
Rails obsahuje integrovaný framework pro internacionalizaci. K tomu, abyste mohli začít, toho moc víc nepotřebujete – rozhraní I18n API je součástí balíku a základní funkce zvládá dobře: překlad statických řetězců, formátování dat a čísel a správu množného čísla v různých jazykových mutacích.
„Integrované“ však neznamená „kompletní“. Jakmile se vaše požadavky rozšíří na lokalizované URL adresy, překlady v JavaScriptu nebo vícejazyčné SEO, dostanete se mimo rámec toho, co Rails standardně nabízí. Tyto mezery vyžadují promyšlená architektonická rozhodnutí.
Projdeme si obě vrstvy: co zajišťuje API Rails I18n a kde budete muset něco naprogramovat – nebo tuto úlohu přenechat jinému.
Rozhraní API I18n nabízí dvě základní metody: I18n.t pro překlad řetězců a I18n.l pro lokalizaci dat a čísel. Obě čtou ze souborů YAML nebo Ruby v adresáři config/locales/ a Rails je při spuštění načte automaticky.
Ve výchozím nastavení to zahrnuje statické řetězce uživatelského rozhraní, formátování datumu a čísel a validační hlášení ActiveRecord. Pro většinu projektů, kde se překládá z jednoho jazyka do druhého, to k vydání stačí.
Jakmile se dostanete dál, mezery se rychle projeví.
Rails I18n se nijak nevyjadřuje ke struktuře URL: neposkytuje lokalizované trasy, detekci subdomén ani předpony cest. Neobsahuje žádný mechanismus pro překlad obsahu uloženého v databázi, jako jsou názvy produktů nebo příspěvky na blogu. Soubory JavaScriptu se nacházejí zcela mimo tento proces. A vícejazyčné SEO, tedy například tagy hreflang, přeložené slugy a jazykově specifické soubory sitemap, vyžaduje samostatnou práci, do které se framework nezapojuje.
Než začnete stavět, musíte vědnit, kde vede hranice.
Začít můžete s gemem rails-i18n.
Rails dodává pouze data pro anglické národní prostředí, takže bez nich selže volání I18n.l(Date.today) v jiných národních prostředích než anglickém a řetězce na úrovni frameworku, jako jsou například validační zprávy Active Record, zůstanou v angličtině bez ohledu na aktuální národní prostředí.
# Gemfile
gem "rails-i18n"Poté nastavte výchozí hodnoty aplikace:
# config/application.rb
config.i18n.default_locale = :en
config.i18n.available_locales = [:en, :fr]
config.i18n.enforce_available_locales = true
Nastavení `enforce_available_locales = true` vyvolá chybu, pokud se aplikace pokusí nastavit národní prostředí mimo tento seznam. Bez tohoto nastavení může překlep nebo nesprávně zadaný parametr URL v produkčním prostředí tiše nastavit nepodporované národní prostředí.
Ačkoli moderní Rails prohledává pouze jednu úroveň, často mu uniknou hluboce vnořené složky (například config/locales/views/products/). Přidáním tohoto řádku zajistíte, že se při rozšiřování vaší aplikace zahrnou všechny podadresáře:
config.i18n.load_path += Dir[Rails.root.join("config", "locales", "**", „*.{rb,yml}“)]Díky tomu můžete překladové soubory rozdělit podle domén:
config/locales/
en/
models.yml
views.yml
mailers.yml
fr/
modely.yml
views.yml
mailers.yml⚠️ YAML interpretuje hodnoty jako true a false jako logické hodnoty. Pokud je potřebujete jako doslovný text, uveďte je výslovně v uvozovkách. Moderní verze Ruby/YAML nyní zacházejí s výrazem yes a no jako s řetězci, ale jejich uvozování zůstává bezpečným zvykem z důvodu kompatibility:
cs:
odpovědi:
ano: „ano“
záporné: „ne“Tím se odhalí určitý druh chyby, která se projeví pouze v případě, že překlad vrátí hodnotu „true“ namísto „yes“ a váš zobrazení nevykreslí nic, nebo v horším případě řetězec „true“.
Ve viewech jsou t a l dva pomocné prvky, které budete používat neustále.
Funkce `l` lokalizuje data, časy a čísla podle aktuálního národního prostředí. Je-li nainstalován modul `rails-i18n`, jsou součástí balíčku definice formátů pro více než 100 národních prostředí. Bez něj však volání `l(Date.today)` v jiném než anglickém národním prostředí obvykle vrátí řetězec „translation missing“ nebo neformátované datum, protože Rails postrádá potřebné lokalizované formátovací šablony.
<%= l(Date.today) %>
<%= l(Date.today, format: :long) %>t překládá řetězce podle klíče. Plný zápis je t("products.index.title"), ale ve výpisech můžete použít zkrácený zápis s odloženým vyhledáváním:
<%= t(".title") %>Úvodní tečka sděluje Railsům, aby klíč vyhodnotily relativně k aktuální cestě k zobrazení. V souboru app/views/products/index.html.erb se výraz t(".title") automaticky rozbalí na t("products.index.title"). Díky tomu zůstávají klíče krátké a bez dalšího úsilí se dodržuje jednotná konvence pojmenování.
For interpolation, use %{variable} in your YAML and pass the value as a keyword argument:
en:
welcome: "Hello, %{name}"<%= t(".welcome", name: current_user.name) %>Pokud překlad obsahuje HTML kód, kterému důvěřujete, připojte k názvu klíče příponu _html. Rails jej automaticky označí jako bezpečný, aniž by bylo nutné volat metodu html_safe.
en:
notice_html: "Please <strong>confirm</strong> your email."Odložené vyhledávání funguje pouze v případech, kdy si Rails dokáže odvodit cestu k zobrazení, což znamená, že nefunguje v úlohách na pozadí ani v API řadičích. V těchto případech vždy použijte úplný klíč.
Než začnete psát kód pro detekci jazykového prostředí, zvolte si strategii. Existuje pět hlavních přístupů a ten správný závisí na struktuře vaší aplikace a požadavcích na SEO.
Předpona adresy, například /fr/products, je nejčastější volbou pro veřejně přístupné aplikace v Rails. Díky ní je v každé URL explicitně uvedeno jazykové nastavení, což vyhledávačům umožňuje indexovat stránky samostatně pro každý jazyk.
Strategie využívající subdomény a domény nejvyšší úrovně (TLD) se osvědčují, pokud chcete posílit regionální identitu, ale s sebou přinášejí další práci s konfigurací DNS a správou SSL certifikátů.
Parametry URL, jako například /products?locale=fr, jsou vhodné pro interní nástroje, u nichž na SEO nezáleží.
Předvolby uložené v databázi fungují u ověřených aplikací, kde se národní prostředí řídí podle uživatele, nikoli podle adresy URL.
Ať už se rozhodnete pro jakoukoli strategii, existuje jedna chyba při implementaci, která způsobuje nenápadné chyby v produkčním prostředí: přímé použití I18n.locale =.
# Don't do this
before_action { I18n.locale = params[:locale] }I18n.locale = zapisuje do proměnné Thread.current.
Pokud používáte webový server Puma, ten využívá vlákna napříč jednotlivými požadavky. Pokud požadavek výslovně nenastaví národní prostředí, převezme nastavení z předchozího požadavku.
Při lokálním vývoji v jednovláknovém prostředí se tento problém nikdy neprojeví. V produkčním prostředí však způsobuje občasné odpovědi v nesprávném jazyce, které je obtížné reprodukovat a ještě obtížnější vysledovat.
Místo toho použijte metodu I18n.with_locale uvnitř akce around_action:
around_action :switch_localed
ef switch_locale(&action)
locale = params[:locale] || I18n.default_locale
I18n.with_locale(locale, &action)
endFunkce `with_locale` obnoví původní národní prostředí po ukončení bloku, bez ohledu na to, jak žádost skončí.
Definujte své trasy v adresáři /:locale a předefinujte nastavení `default_url_options`, aby Rails automaticky předřazoval aktuální národní prostředí ke každé URL-pomocné funkci:
# config/routes.rb
scope "/:locale" do
resources :products
root "home#index"
end
# app/controllers/application_controller.rb
around_action :switch_locale
def switch_locale(&action)
locale = params[:locale]
# Fallback to default if the param is missing or unsupported
valid_locale = I18n.available_locales.map(&:to_s).include?(locale) ? locale : I18n.default_locale
I18n.with_locale(valid_locale, &action)
end
def default_url_options
{ locale: I18n.locale }
end
Je-li nastavena proměnná `default_url_options`, adresa `products_path` se automaticky zobrazí jako `/fr/products`, pokud je aktuální národní nastavení `:fr`.
Pokud chcete, aby výchozí lokalizace předponu vynechala, nastavte segment jako volitelný s rozsahem „(:locale)“. Tím se pro angličtinu zobrazí /products a pro francouzštinu /fr/products, ale vznikne tím nejednoznačnost. Cesta typu /about by se mohla vztahovat buď na chybějící lokalizaci, nebo na řadič s názvem about, v závislosti na pořadí tras.
Při detekci subdomén nejprve načtěte hodnotu z `request.subdomains.first` a porovnejte ji s `available_locales`, než provedete jakékoli nastavení:
def extrahovat_jazyk_z_subdomény
subdomain = request.subdomains.first
vrátit nil if subdomain.blank? || subdomain == "www"
subdomain if I18n.available_locales.map(&:to_s).include?(subdomain)
end
Kontrola www zabraňuje tomu, aby byl považován za národní prostředí. Na localhostu vrací request.subdomains prázdné pole, takže detekce subdomén ve vývojovém prostředí selže, pokud nepoužíváte server Pow nebo nepřidáte záznamy do souboru /etc/hosts.
Jednu věc je třeba nastavit zvlášť: proměnná `default_url_options` definovaná v `ApplicationController` se nepřenáší do modulů pro odesílání e-mailů ani do úloh na pozadí. V těchto kontextech ji nastavte výslovně:
Rails.application.routes.default_url_options = { host: "example.com", locale: :en }Lokalizované trasy vám poskytnou strukturu URL, avšak tagy hreflang, přeložené slugy a vícejazyčné soubory Sitemap je i po tomto nastavení třeba zadávat zcela ručně.
Integrace reverzního proxy Weglot tuto úroveň zpracovává automaticky a generuje tagy hreflang a jazykově specifické URL adresy bez nutnosti další konfigurace.
Tvorba množného čísla v angličtině je jednoduchá. Jedna forma pro jednotné číslo, jedna pro všechny ostatní případy.
en:
messages:
one: "%{count} message"
other: "%{count} messages"
Většina jazyků není tak jednoduchá.
Například bulharština má u některých slov v mužském rodě pravidelný plurál a speciální „počítací plurál“. Slovo ден (den) se tedy běžně mění na дни (mnoho dní), ale při počítání se používá dva дена (dva dny).
bg:
cities:
one: "%{count} ден"
few: "%{count} дена"
many: "%{count} дни"
Bez modulu rails-i18n nemá Rails o těchto pravidlech žádné informace. Vaše bulharské překlady by se při každém počítání buď zobrazovaly s chybou, nebo by se přepnuly na druhou formu.
Gem obsahuje logiku pro tvorbu množného čísla pro více než 100 jazykových verzí, takže se vše správně zobrazí v bulharštině, ruštině, arabštině, polštině a v jakémkoli jiném jazyce s odlišnými pravidly pro tvorbu množného čísla než v angličtině.
Náhradní řešení představují samostatný problém a ve výchozím nastavení jsou vypnutá. Bez nich se při chybějícím překladovém klíči v produkčním prostředí zobrazí hlášení o chybějícím překladu. Právě takové chyby se dostávají do finální verze a objevují se na snímcích obrazovky.
Zapněte záložní řešení a definujte výchozí cíl v souboru config/application.rb:
config.i18n.fallbacks = [I18n.default_locale]Je-li nastaveno `fallbacks = true`, chybějící klíč v aktuálním národním prostředí se nahradí hodnotou z `default_locale`. Pro regionální varianty můžete definovat explicitní řetězce:
config.i18n.fallbacks = { "fr-CA": :fr, "en-GB": :en }Nastavte to včas. Dodatečné zavedení záložního chování do aplikace, která již má v produkčním prostředí částečné překlady, je složitější než jeho nastavení hned na začátku.
JavaScript nemá přístup k procesu lokalizace v Rails.
K dispozici není žádný pomocný modul t, načítací program YAML ani vestavěný most mezi překladovými soubory a řadiči Stimulus. Překlady je nutné předávat explicitně ze strany serveru.
Nejjednodušším způsobem v rámci Stimulus je použití API hodnot. Překlad definujte jako hodnotu v řadiči, nastavte jej v HTML a načtěte jej v JavaScriptu:
# app/views/products/index.html.erb
<div data-controller="notification"
data-notification-message-value="<%= t('.success_message') %>">
Hodnota se vykresluje na straně serveru pomocí standardního pomocného modulu `t`, takže automaticky zohledňuje aktuální národní prostředí. Na straně JavaScriptu ji deklarujte jako statickou hodnotu a načtěte ji pomocí rozhraní API `values`:
// app/javascript/controllers/notification_controller.js
export default class extends Controller {
static values = { message: String }
show() {
alert(this.messageValue)
}
}
Každý překlad je explicitní a ohraničený na konkrétní řadič, který jej potřebuje. Do globálního rozsahu se nic neprojeví.
Pokud správce potřebuje více překladů najednou, je přehlednější seskupit je do jednoho atributu datového formátu JSON, než přidávat jednotlivé definice hodnot pro každý řetězec:
<div data-controller="cart"
data-cart-i18n-value="<%= { add: t('.add'), remove: t('.remove') }.to_json %>">
V JavaScriptu deklarujte i18n jako hodnotu typu Object a přistupujte přímo k jednotlivým klíčům:
static values = { i18n: Object }
add() {
console.log(this.i18nValue.add)
}
V případě aplikací, kde JavaScript potřebuje široký přístup k překladům napříč mnoha řadiči, gem i18n-js exportuje vaše soubory YAML do objektu JavaScriptu, který můžete dotazovat pomocí I18n.t("key").
Funguje to, ale přidává to další krok při sestavování a klientovi se tak odešle kompletní sada překladů. Používejte to v případě, že se první dva postupy začnou opakovat, nikoli jako výchozí nastavení.
Při používání Turbo Frames platí, že pokud URL zdroje Turbo Frames neobsahuje předponu locale, dojde obvykle k selhání požadavku s chybou směrování (404), protože nebude odpovídat vzoru rozsahu „/:locale“. Pro zdroje rámců vždy používejte pomocné funkce pro cesty zohledňující locale.
Nejde o chybu systému Turbo. Jedná se spíše o opomenutí při směrování, kterému zabraňuje akce `around_action` z části pro detekci locale, a to za předpokladu, že každá URL v rámci používá pomocný prvek pro cesty s podporou locale.
Reverzní proxy Weglot využívá zcela odlišný přístup. Překládá vykreslený DOM až po načtení stránky, takže obsah vykreslený pomocí Stimulus a dynamicky vkládané řetězce jsou pokryty bez jakéhokoli tohoto propojování.
Existují tři kategorie, které zcela nespadají do působnosti funkce Rails I18n:
Weglot řeší všechny tyto problémy na úrovni výstupu, nikoli na úrovni kódu:
Je však třeba si uvědomit několik omezení, o kterých byste měli vědět, než se k tomuto řešení vyjádříte:
Každá implementace i18n v Railsu spočívá ve stejných rozhodnutích, která se provádějí zhruba ve stejném pořadí.
Nejprve si zvolte strategii pro URL, než začnete psát kód pro detekci národního prostředí. U většiny aplikací určených pro veřejnost stačí segmenty adresy. Subdomény mají smysl tam, kde záleží na regionální identitě. Předvolby uložené v databázi se hodí pro aplikace vyžadující přihlášení, kde se národní prostředí přizpůsobuje uživateli, nikoli URL.
Za druhé, rozhodněte se, jakým způsobem bude JavaScript získávat překlady. API Stimulus values pokrývá většinu případů. Atributy JSON se hodí v situacích, kdy řadič potřebuje více řetězců najednou.
Za třetí, rozhodněte se, co budete vytvářet ručně. Rails si se statickými řetězci poradí dobře. SEO vrstva, pracovní postup překladatelů i obsah databáze vyžadují samostatná rozhodnutí. Můžete si vše vytvořit sami, nebo výstupní vrstvu svěřit nástroji, jako je Weglot čas vývojářů soustředit na samotnou aplikaci.
Vynechejte výstupní vrstvu úplně. Vyzkoušejte Weglot na 14 dní Weglot a získejte vícejazyčné SEO/GEO, přeložené URL adresy a automatickou detekci obsahu, aniž byste museli zasahovat do svého kódu pro internacionalizaci.
Nejlepší způsob, jak pochopit sílu Weglot vyzkoušet si ho na vlastní kůži. Vyzkoušejte ho zdarma a bez jakýchkoli závazků.
Pokud ještě nejste připraveni propojit svůj web, je k dispozici demo webová stránka ve vašem ovládacím panelu.