Further wiki slug normalization

This commit is contained in:
2026-05-21 22:17:56 +02:00
parent 43fee721db
commit a0af6315b9
3 changed files with 51 additions and 14 deletions
+7 -5
View File
@@ -170,11 +170,13 @@ func TestMatchExistingNodeBBPagePrefersGeneratedPublicSlug(t *testing.T) {
func TestDeploySlugifyWikiTitleMatchesGeneratedSlugPolicy(t *testing.T) {
tests := map[string]string{
`Grandmaster's Battle Momentum`: "grandmasters-battle-momentum",
`Bigbys Clenched Fist`: "bigbys-clenched-fist",
`Hardiness vs. Enchantments`: "hardiness-vs-enchantments",
`Clairaudience/Clairvoyance`: "clairaudience-clairvoyance",
`Élite & Noble Houses`: "elite-noble-houses",
`Grandmaster's Battle Momentum`: "grandmasters-battle-momentum",
`Bigbys Clenched Fist`: "bigbys-clenched-fist",
`Hardiness vs. Enchantments`: "hardiness-vs-enchantments",
`Clairaudience/Clairvoyance`: "clairaudience-clairvoyance",
`Élite & Noble Houses`: "elite-noble-houses",
`Alpha!@#$%^&*()[]-=_+/?.,<>` + "`" + `~|\Omega`: "alpha-omega",
`Æther Œuvre Øresund Straße Þorn Łódź Đelta`: "aether-oeuvre-oresund-strasse-thorn-lodz-delta",
}
for input, want := range tests {
if got := slugifyWikiTitle(input); got != want {
+11 -9
View File
@@ -1241,15 +1241,17 @@ func TestWikiPageSlugOverridesChangeTargets(t *testing.T) {
func TestWikiSlugifyTitleNormalizesPunctuationAndSeparators(t *testing.T) {
tests := map[string]string{
`Grandmaster's Battle Momentum`: "grandmasters-battle-momentum",
`Bigbys Clenched Fist`: "bigbys-clenched-fist",
`"Quoted" Curly “Title”`: "quoted-curly-title",
`Hardiness vs. Enchantments`: "hardiness-vs-enchantments",
`Clairaudience/Clairvoyance`: "clairaudience-clairvoyance",
`Moon-on-a-Stick`: "moon-on-a-stick",
`Élite &amp; Noble Houses`: "elite-noble-houses",
`Rock 'n' Roll`: "rock-n-roll",
`Melf&#39;s Acid Arrow`: "melfs-acid-arrow",
`Grandmaster's Battle Momentum`: "grandmasters-battle-momentum",
`Bigbys Clenched Fist`: "bigbys-clenched-fist",
`"Quoted" Curly “Title”`: "quoted-curly-title",
`Hardiness vs. Enchantments`: "hardiness-vs-enchantments",
`Clairaudience/Clairvoyance`: "clairaudience-clairvoyance",
`Moon-on-a-Stick`: "moon-on-a-stick",
`Élite &amp; Noble Houses`: "elite-noble-houses",
`Rock 'n' Roll`: "rock-n-roll",
`Melf&#39;s Acid Arrow`: "melfs-acid-arrow",
`Alpha!@#$%^&*()[]-=_+/?.,<>` + "`" + `~|\Omega`: "alpha-omega",
`Æther Œuvre Øresund Straße Þorn Łódź Đelta`: "aether-oeuvre-oresund-strasse-thorn-lodz-delta",
}
for input, want := range tests {
if got := wikiSlugifyTitle(input); got != want {
+33
View File
@@ -13,6 +13,7 @@ func slugifyWikiText(value string, fallback string) string {
var b strings.Builder
lastDash := false
for _, r := range norm.NFKD.String(strings.ToLower(value)) {
transliterated := transliterateWikiSlugRune(r)
switch {
case r >= 'a' && r <= 'z':
b.WriteRune(r)
@@ -24,6 +25,9 @@ func slugifyWikiText(value string, fallback string) string {
continue
case isWikiSlugJoinerPunctuation(r):
continue
case transliterated != "":
b.WriteString(transliterated)
lastDash = false
default:
if b.Len() > 0 && !lastDash {
b.WriteByte('-')
@@ -46,3 +50,32 @@ func isWikiSlugJoinerPunctuation(r rune) bool {
return false
}
}
func transliterateWikiSlugRune(r rune) string {
switch r {
case 'æ':
return "ae"
case 'œ':
return "oe"
case 'ø':
return "o"
case 'ß':
return "ss"
case 'þ':
return "th"
case 'ð', 'đ':
return "d"
case 'ł':
return "l"
case 'ħ':
return "h"
case 'ı':
return "i"
case 'ŋ':
return "n"
case 'ŧ':
return "t"
default:
return ""
}
}