Przejdź do treści
Intum Dev

Znaki diakrytyczne i niełacińskie w URL-ach — jak generować ładne slugi

Aktualizacja: 3 min czytania

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ęś łąkizolta-ges-laki
  • Київ столицяkyiv-stolytsya
  • Produkty świąteczneprodukty-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 parameterize zwró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):

  1. Łacińskiparameterize (działa od razu)
  2. Cyrylica — gem babosa lub initializer z mapowaniem
  3. CJK — fallback na token
  4. 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ńskichinese_pinyin + fallback
  • Japońskiromaji + fallback

Czy ten wpis był pomocny?

Udostępnij

Komentarze