diff --git a/internal/util/link/outbound.go b/internal/util/link/outbound.go index cfcf18b82..8ba193396 100644 --- a/internal/util/link/outbound.go +++ b/internal/util/link/outbound.go @@ -781,8 +781,10 @@ func base64DecodeFlexible(s string) (string, error) { return "", fmt.Errorf("base64 decode failed") } -// SlugRemark turns a free-form remark into a conservative DNS-ish tag segment. -var slugRe = regexp.MustCompile(`[^a-z0-9]+`) +// SlugRemark turns a free-form remark into a tag segment, keeping Unicode +// letters and digits (so non-ASCII remarks like Cyrillic stay readable) and +// replacing every other run of characters with a single dash. +var slugRe = regexp.MustCompile(`[^\p{L}\p{N}]+`) func SlugRemark(remark string) string { s := strings.ToLower(strings.TrimSpace(remark)) diff --git a/internal/util/link/outbound_test.go b/internal/util/link/outbound_test.go index 1dbadaf00..43d2a6079 100644 --- a/internal/util/link/outbound_test.go +++ b/internal/util/link/outbound_test.go @@ -59,4 +59,11 @@ func TestSlugAndSuggest(t *testing.T) { if tag != "hk-sg-01" { t.Errorf("suggest tag got %q", tag) } + // Non-ASCII letters/digits are preserved rather than stripped. + if got := SlugRemark("Москва 🇷🇺 01"); got != "москва-01" { + t.Errorf("unicode slug got %q", got) + } + if got := SuggestTag("ru-", "Сервер 2", 0); got != "ru-сервер-2" { + t.Errorf("unicode suggest tag got %q", got) + } }