Problem
Przy generowaniu URL-i (slugów) z tytułów zawierających znaki spoza ASCII — polskie diakrytyki (ą, ę, ł), cyrylicę (Київ), znaki CJK (東京) — powstaje pytanie: jak zapewnić czytelny, bezpieczny URL?
Dwa podejścia
1. Transliteracja do ASCII (rekomendowane)
Zamiana znaków na ich najbliższe odpowiedniki ASCII:
-
Żółta gęś łąki→zolta-ges-laki -
Київ столиця→kyiv-stolytsya -
Produkty świąteczne→produkty-swiateczne
Zalety:
- Bezproblemowe kopiowanie/wklejanie linków
- Czytelne w e-mailach, czatach, logach
- Kompatybilne ze wszystkimi systemami i API
- Dobre dla SEO
2. UTF-8 w URL-ach
Trzymanie oryginalnych znaków w URL-u (jak Wikipedia):
- W pasku przeglądarki wygląda ładnie:
example.com/artykuły/żółta-gęś - W kodzie źródłowym wygląda brzydko (percent-encoding):
example.com/%C5%BC%C3%B3%C5%82ta-%67%C4%99%C5%9B
Problemy z UTF-8 w URL-ach:
- Przy kopiowaniu z paska przeglądarki czasem wkleja się percent-encoded wersja
- W e-mailach i czatach linki mogą się źle łamać
- Starsze systemy i API mogą nie obsłużyć poprawnie
- Trudniejsze debugowanie
Rozwiązanie per alfabet
Łaciński z diakrytykami (polski, czeski, niemiecki, francuski)
Działa od razu w Rails — String#parameterize automatycznie transliteruje:
"Żółta gęś łąki".parameterize
# => "zolta-ges-laki"
"Příliš žluťoučký kůň".parameterize
# => "prilis-zlutoucky-kun"
Cyrylica (ukraiński, rosyjski)
Wymaga dodatkowej konfiguracji. Dwa sposoby:
Sposób 1 — Initializer z mapowaniem:
# config/initializers/transliterate.rb
ActiveSupport::Inflector.transliterate_mapping = {
"А" => "A", "Б" => "B", "В" => "V", "Г" => "H",
"Д" => "D", "Е" => "E", "Є" => "Ye", "Ж" => "Zh",
"З" => "Z", "И" => "Y", "І" => "I", "Ї" => "Yi",
"К" => "K", "Л" => "L", "М" => "M", "Н" => "N",
"О" => "O", "П" => "P", "Р" => "R", "С" => "S",
"Т" => "T", "У" => "U", "Ф" => "F", "Х" => "Kh",
"Ц" => "Ts", "Ч" => "Ch", "Ш" => "Sh", "Щ" => "Shch",
"Ь" => "", "Ю" => "Yu", "Я" => "Ya",
# + małe litery analogicznie
}
Sposób 2 — Gem babosa (rekomendowane):
"Київ столиця".to_slug.transliterate(:ukrainian).to_s.parameterize
# => "kyiv-stolytsya"
Chiński / Japoński (CJK)
Nie da się zamapować 1:1 — znaki kanji mają wymowę zależną od kontekstu. Opcje:
-
Gem
chinese_pinyin— chiński hanzi → pinyin:北京→bei-jing -
Gem
romaji— japońskie kana → romaji:東京→toukyou -
Gem
babosa— uniwersalny, obsługuje wiele alfabetów -
Fallback na token — jeśli
parameterizezwróci pusty string, generuj losowy identyfikator
def generate_slug(text)
slug = text.to_s.parameterize
slug.present? ? slug : Utils.generate_token
end
Rekomendacja
Dla aplikacji SaaS z wieloma locale (pl, en, fr, cs, sk, de, es, uk):
-
Łaciński —
parameterize(działa od razu) -
Cyrylica — gem
babosalub initializer z mapowaniem - CJK — fallback na token
- Transliteracja do ASCII jest lepsza niż UTF-8 w URL-ach — linki są bezpieczne w każdym kontekście
Porównanie gemów Ruby
| Gem | GitHub Stars | Powstał | Ostatni push | Pobrania | Opis |
|---|---|---|---|---|---|
| friendly_id | ~6 200 | 2008 | 2026 | 54M | Pełna integracja z ActiveRecord — auto-slug, historia, scoped slugs |
| stringex | ~980 | 2008 | 2023 | 40M | Rozszerzenia String + wbudowany Unidecoder |
| babosa | ~530 | 2010 | 2023 | 157M | Najlepsza transliteracja per-locale, lekki, bez AR |
| chinese_pinyin | ~430 | 2010 | 2021 | 1M | Hanzi → pinyin (nieaktywny) |
| romaji | ~100 | 2012 | 2025 | 7M | Kana ↔ romaji |
babosa ma najwięcej pobrań (157M) bo jest zależnością friendly_id. Oba gemy stworzył ten sam autor.
Który gem wybrać?
- Tylko transliteracja (bez integracji z AR) → babosa
- Auto-slug w modelach (historia, unikalne URL-e) → friendly_id (używa babosa pod spodem)
- Chiński → chinese_pinyin + fallback
- Japoński → romaji + fallback