Internacjonalizacja sklepu Rails dla wielu rynków
Sprzedaż w wielu krajach oznacza tłumaczenie nie tylko interfejsu, ale danych, URL-i, formatów i SEO. Deep-dive o i18n w Rails przy skali — pliki lokalizacji, tłumaczona treść, routing lokalny i pułapki.
Internacjonalizacja aplikacji to jedno z tych zadań, które wszyscy niedoceniają. „Przetłumacz etykiety” to może 20% pracy; reszta to dane, URL-e, formaty liczb i dat, reguły liczby mnogiej i SEO — każde z własnymi pułapkami. Dla sklepu e-commerce sprzedającego na wielu rynkach zrobienie tego dobrze to różnica między poczuciem lokalności w każdym kraju a poczuciem niezdarnego tłumaczenia maszynowego. Oto co naprawdę obejmuje pełna robota w Rails.
Fundament: I18n i pliki lokalizacji
Rails dostarcza gem I18n, a podstawowy mechanizm jest solidny: tekst żyje w plikach
lokalizacji kluczowanych lokalizacją, a wyszukujesz go po kluczu:
# config/locales/en.yml
en:
cart:
title: "Your basket"
item_count:
one: "%{count} item"
other: "%{count} items"
# config/locales/pl.yml
pl:
cart:
title: "Twój koszyk"
item_count:
one: "%{count} produkt"
few: "%{count} produkty"
many: "%{count} produktów"
<h1><%= t("cart.title") %></h1>
<p><%= t("cart.item_count", count: @cart.size) %></p>
Dwie rzeczy do natychmiastowego przyswojenia. Po pierwsze, liczba mnoga to nie tylko
one/other. Angielski ma dwie formy; polski ma cztery (one/few/many/other) z
nieoczywistymi regułami; arabski ma sześć. Interpolacja count: i klucze liczby mnogiej
per lokalizacja obsługują to, jeśli dostarczysz właściwe formy — wpisanie na sztywno
logiki „1 item / N items” w widokach psuje się w chwili, gdy dodasz język słowiański.
Pozwól maszynerii liczby mnogiej I18n to zrobić. Po drugie, trzymaj klucze semantyczne
(cart.title), nie wyprowadzone z tekstu, by tłumacze i kod pozostali rozdzieleni.
Tłumaczenie danych, nie tylko chromu
Oto część, która oddziela prawdziwą internacjonalizację od przetłumaczonego paska menu: w
sklepie treść też potrzebuje tłumaczenia. Nazwy produktów, opisy, nazwy kategorii,
strony CMS — to dane w twojej bazie, nie łańcuchy w pliku YAML, i potrzebują wartości per
lokalizacja. Częstą odpowiedzią Rails jest gem jak globalize albo mobility
przechowujący tłumaczenia w tabelach pobocznych:
class Product < ApplicationRecord
translates :name, :description # name/description różnią się lokalizacją
end
I18n.locale = :pl
product.name # => polska nazwa
I18n.locale = :en
product.name # => angielska nazwa
To prawdziwa decyzja modelowania danych z konsekwencjami: tłumaczenia żyją w osobnych tabelach kluczowanych rekordem i lokalizacją, co wpływa na twoje zapytania, indeksowanie wyszukiwania (indeksujesz teraz per lokalizacja) i UI admina (edytorzy muszą wpisywać każdy język). Zaplanuj to — tłumaczenie treści jest zwykle największą i najbardziej ciągłą częścią i18n, bo każdy nowy produkt potrzebuje tłumaczenia, na zawsze, podczas gdy łańcuchy interfejsu pisze się raz.
Lokalizacja w URL: routing i SEO
To, jak wybierana jest lokalizacja odwiedzającego i odzwierciedlana w URL, to zarówno decyzja UX, jak i SEO, a zrobienie tego źle po cichu rujnuje twoją widoczność w wyszukiwarce. Solidne wzorce umieszczają lokalizację w URL, by każdy język miał własne adresowalne, indeksowalne strony:
# oparte na ścieżce: /en/products, /pl/products
scope "/:locale", locale: /en|pl|de/ do
resources :products
end
# ustaw z URL na każdym żądaniu
before_action :set_locale
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
Alternatywami są subdomena lokalizacji (pl.shop.com) albo domena krajowa (shop.pl) —
właściwy wybór zależy od tego, jak wyraźnie chcesz brandować rynki i jak ustrukturyzowane
jest twoje SEO. Czego nie wolno robić, to serwować różnych języków pod tym samym URL
na podstawie samego ciasteczka czy nagłówka Accept-Language: wyszukiwarki nie mogą wtedy
indeksować każdego języka osobno, a użytkownik nie może udostępnić linku w swoim języku.
Nienegocjowalnym wymogiem SEO są tagi hreflang mówiące wyszukiwarkom, który URL
serwuje który język, by Google pokazał właściwy i nie traktował twoich tłumaczeń jako
zduplikowanej treści:
<link rel="alternate" hreflang="en" href="https://shop.com/en/product/42" />
<link rel="alternate" hreflang="pl" href="https://shop.com/pl/product/42" />
Formaty: liczby, daty i pieniądze też są lokalizowane
Rynek nie czuje się lokalny, dopóki formaty nie są właściwe. 1,234.56 w UK to
1 234,56 w Polsce i 1.234,56 w Niemczech; kolejność daty, umieszczenie symbolu waluty
i pierwszy dzień tygodnia wszystkie się różnią. Rails lokalizuje to też przez I18n:
l(Date.today, format: :long) # zlokalizowana data
number_to_currency(price) # szanuje format lokalizacji
To zazębia się z pracą wielowalutową: waluta (co pobierasz) i format (jak wyświetlasz
liczbę) to osobne sprawy, obie świadome lokalizacji. Niemiecki klient może płacić w EUR
pokazanym jako 19,99 €, podczas gdy francuski widzi 19,99 € z innymi odstępami — ta
sama waluta, inne formatowanie, oba napędzane lokalizacją.
Pułapki warte nazwania
Kilka trybów awarii, które gryzą zespoły robiące to po raz pierwszy:
- Brakujące tłumaczenia zawodzące po cichu lub głośno. Zdecyduj swoją politykę: na
produkcji zwykle chcesz rozsądnego fallbacku (do domyślnej lokalizacji), a nie surowego
klucza pokazanego użytkownikowi; w developmencie i CI chcesz, by brakujące klucze
zawodziły, byś łapał je przed wysyłką. Gem
i18n-tasksznajduje brakujące i nieużywane klucze. - Sklejanie przetłumaczonych fragmentów. Budowanie zdania przez łączenie
przetłumaczonych słów (
t(:you_have) + count + t(:items)) produkuje bełkot w językach o innej kolejności słów. Tłumacz całe frazy z interpolacją, nigdy nie składaj ich z części. - Wpisany na sztywno angielski we flashach, mailerach, walidacjach i PDF-ach. Łańcuchy ukrywają się w kątach — komunikaty błędów, maile, generowane dokumenty. Prawdziwy przegląd i18n musi dosięgnąć ich wszystkich, nie tylko widoków.
- Rozszerzanie tekstu w UI. Niemiecki jest ~30% dłuższy niż angielski; przycisk, który mieści się po angielsku, przepełnia się po niemiecku. Projektuj i testuj układy z najdłuższym językiem.
Werdykt
Internacjonalizacja sklepu to znacznie więcej niż tłumaczenie etykiet — to tłumaczenie
twoich danych, strukturyzowanie twoich URL-i zarówno dla użytkowników, jak i
wyszukiwarek, lokalizowanie każdego formatu, szanowanie liczby mnogiej każdego języka
i wyganianie wpisanego na sztywno angielskiego z każdego kąta. Oprzyj się na maszynerii
I18n Rails dla interfejsu i formatów, użyj gemu do tłumaczeń treści bazy, umieść
lokalizację w URL z hreflang dla SEO i przyjmij narzędzia (i18n-tasks), by trzymać
swoje klucze uczciwymi. Potraktuj tłumaczenie treści jako ciągły koszt, którym jest,
zaplanuj je w modelu danych, a twój sklep może czuć się naprawdę lokalny na każdym rynku,
zamiast jak angielski z podmienionymi słowami. Praca jest znacząca, ale dla biznesu
sprzedającego za granicę to różnica między wyglądaniem na rodzimego a wyglądaniem na
obcego.