Słowniki tłumaczeń
Kodowanie,  Poradnik

Słowniki tłumaczeń

W systemach wielojęzycznych bardzo szybko pojawia się ten sam problem: ta sama informacja musi zostać pokazana użytkownikowi w różnych językach, bez przepisywania całej logiki programu. Nie chodzi tylko o interfejs aplikacji, ale też komunikaty błędów, opisy produktów, statusy zamówień, raporty czy dokumenty generowane automatycznie. Jeśli ten mechanizm nie jest uporządkowany, projekt zaczyna się rozpadać przy każdej zmianie tekstu. Najprościej porządkuje się to przez Słowniki tłumaczeń.

Słowniki tłumaczeń jako warstwa pośrednia między kodem programu a treścią widoczną dla użytkownika

Najważniejsza zasada jest prosta: w kodzie nie zapisuje się tekstów końcowych typu „Błąd logowania” albo „Zapisano poprawnie”, tylko używa się kluczy logicznych, na przykład:

  • login.error
  • user.saved
  • cart.empty

Program operuje na kluczach, a dopiero osobna struktura danych zamienia klucz na tekst w odpowiednim języku.

Dzięki temu:

  • programista nie edytuje treści językowych w logice aplikacji,
  • tłumacz nie musi znać kodu,
  • zmiana jednego komunikatu nie wymaga przebudowy programu,
  • można łatwo dodać kolejny język.

To jest podstawowy wzorzec stosowany w systemach i18n (internationalization) i l10n (localization).

Przykład działania:

  1. Program wywołuje klucz payment.success
  2. System sprawdza aktywny język użytkownika, np. pl
  3. Odczytywana jest wartość z mapy:
    payment.success -> Płatność zakończona poprawnie
  4. Użytkownik widzi gotowy komunikat

Bez tego przy większym projekcie zaczyna się chaos: ten sam komunikat występuje w 12 miejscach, część po polsku, część po angielsku, część w starej wersji.

Struktura danych i sposób przechowywania map klucz–wartość w pamięci oraz na dysku

Najczęściej używa się struktury typu:

  • hash map
  • associative array
  • dictionary
  • map

czyli relacji:

klucz -> wartość

Przykład logiczny:

KluczPolskiAngielski
login.errorBłąd logowaniaLogin error
cart.emptyKoszyk jest pustyCart is empty
user.savedZapisano użytkownikaUser saved

Klucz powinien być:

  • stabilny
  • czytelny
  • niezmienny w czasie
  • niezależny od języka

Zły przykład:

Błąd_logowania

Dobry przykład:

auth.login.error

Drugi wariant jest lepszy, bo porządkuje system modułowo.

Popularne formaty zapisu:

  • JSON
  • YAML
  • XML
  • CSV
  • pliki .po i .mo
  • bazy SQL

Najczęściej w praktyce webowej używa się JSON lub YAML, bo są szybkie do edycji i łatwe do ładowania.

Przykład JSON:

FormatPrzykład
JSON{ "login.error": "Błąd logowania", "user.saved": "Zapisano użytkownika" }

Przykład YAML:

FormatPrzykład
YAMLlogin.error: "Błąd logowania"

JSON jest wygodniejszy dla parserów, YAML dla ludzi.

Słowniki tłumaczeń w Pythonie, C oraz C++ na prostych przykładach akademickich

Najprostszy przykład to ręczna mapa klucz–wartość.

Python

JęzykKod
Pythonpython\ntranslations = {\n \"login.error\": \"Błąd logowania\",\n \"user.saved\": \"Zapisano użytkownika\"\n}\n\nkey = \"login.error\"\nprint(translations.get(key, \"Brak tłumaczenia\"))\n

Metoda get() jest ważna, bo zabezpiecza przed błędem braku klucza.

C++

JęzykKod
C++cpp\n#include <iostream>\n#include <map>\nusing namespace std;\n\nint main() {\n map<string, string> translations;\n\n translations[\"login.error\"] = \"Błąd logowania\";\n translations[\"user.saved\"] = \"Zapisano użytkownika\";\n\n string key = \"login.error\";\n cout << translations[key] << endl;\n\n return 0;\n}\n

W nowoczesnym C++ często używa się unordered_map, bo jest szybsze dla wyszukiwania.

C

C nie ma wbudowanego słownika, więc najczęściej robi się tablicę struktur.

JęzykKod
Cc\n#include <stdio.h>\n#include <string.h>\n\nstruct Translation {\n char key[50];\n char value[100];\n};\n\nint main() {\n struct Translation dict[] = {\n {\"login.error\", \"Błąd logowania\"},\n {\"user.saved\", \"Zapisano użytkownika\"}\n };\n\n int size = 2;\n char search[] = \"login.error\";\n\n for(int i = 0; i < size; i++) {\n if(strcmp(dict[i].key, search) == 0) {\n printf(\"%s\\n\", dict[i].value);\n }\n }\n\n return 0;\n}\n

To rozwiązanie jest wolniejsze, ale dobrze pokazuje ideę.

Słowniki tłumaczeń a problem odmiany językowej liczby mnogiej i parametrów dynamicznych

Prosty tekst to dopiero początek. Problem zaczyna się przy takich komunikatach:

  • „Masz 1 wiadomość”
  • „Masz 2 wiadomości”
  • „Masz 5 wiadomości”

Polski jest tu znacznie trudniejszy niż angielski.

Nie wystarczy jeden wpis.

Potrzebne są reguły pluralizacji.

Przykład logiczny

LiczbaWersja
1wiadomość
2–4wiadomości
5+wiadomości / wiadomości zależnie od reguły

Jeszcze trudniejsze są parametry dynamiczne:

Witaj, {name}

albo:

Zamówienie nr {id} zostało wysłane

Wtedy słownik przechowuje szablon, a program podstawia dane.

Przykład Python:

JęzykKod
Pythonpython\nmessage = \"Witaj, {name}\"\nprint(message.format(name=\"Anna\"))\n

To trzeba robić ostrożnie. Zły placeholder potrafi zepsuć cały ekran albo wygenerować błędny dokument.

Wydajność wyszukiwania oraz koszt operacyjny przy dużych systemach wielojęzycznych

Przy 20 komunikatach problemu nie widać.

Przy:

  • 50 000 kluczy
  • 12 językach
  • wielu mikroserwisach

zaczyna mieć znaczenie:

  • czas ładowania
  • zużycie pamięci
  • cache
  • synchronizacja wersji

Hash map ma średnio złożoność:

OperacjaZłożoność
wyszukiwanieO(1)
wstawianieO(1)
usuwanieO(1)

Tablica liniowa:

OperacjaZłożoność
wyszukiwanieO(n)

Dlatego ręczne przeszukiwanie tablic w dużych systemach jest złym pomysłem.

Często stosuje się:

  • preload przy starcie aplikacji
  • cache Redis
  • pamięć lokalną procesu
  • wersjonowanie plików tłumaczeń

Błąd spotykany bardzo często: każde tłumaczenie pobierane osobnym zapytaniem SQL. Przy większym ruchu to zabija wydajność.

Słowniki tłumaczeń w systemach produkcyjnych i problemy, które naprawdę psują projekty

Najczęstsze problemy nie są algorytmiczne, tylko organizacyjne.

1. Duplikacja kluczy

save.button

i równolegle

button.save

Po roku nikt nie wie, którego używać.

2. Brak fallback language

Jeśli brakuje tłumaczenia dla de, system powinien umieć wrócić np. do en.

Bez tego użytkownik widzi pusty ekran albo sam klucz.

3. Tłumaczenie klucza zamiast wartości

Klucz ma być techniczny, nie językowy.

Źle:

blad_logowania

Dobrze:

auth.login.error

4. Brak wersjonowania

Zmiana tekstu prawnego bez historii może oznaczać realny problem biznesowy albo prawny.

5. Ręczna edycja bez walidacji

Jeden brakujący przecinek w JSON i produkcja przestaje działać.

To kosztuje realne pieniądze, nie tylko czas.

Krótkie wzory i zależności używane przy analizie wydajności wyszukiwania

Przy analizie struktur danych warto pamiętać o podstawowych zależnościach.

ZagadnienieWzór
wyszukiwanie linioweT(n)=nT(n) = nT(n)=n
wyszukiwanie w hash mapT(n)1T(n) \approx 1T(n)≈1
pamięć dla n wpisówM(n)=n(k+v+o)M(n) = n \cdot (k + v + o)M(n)=n⋅(k+v+o)

gdzie:

  • k – rozmiar klucza
  • v – rozmiar wartości
  • o – narzut struktury

Przy 100 000 wpisów różnica pamięciowa między naiwną implementacją a dobrze zaprojektowaną mapą jest już zauważalna.

FAQ

Czy klucze powinny być po angielsku?

Najczęściej tak, bo projekty techniczne zwykle są rozwijane międzynarodowo. Ważniejsze od języka jest jednak zachowanie spójności.

Czy baza danych jest lepsza niż pliki JSON?

Nie zawsze. Dla statycznych tłumaczeń pliki są prostsze i szybsze. Baza ma sens przy dynamicznej edycji przez panel administracyjny.

Czy warto trzymać tłumaczenia w frontendzie i backendzie osobno?

Tak, jeśli zakres odpowiedzialności jest różny. Wspólny system bywa wygodny, ale często komplikuje deployment.

Co zrobić, gdy brakuje tłumaczenia?

Najlepiej zastosować fallback do języka domyślnego i logować brakujący klucz do monitoringu.

Czy nazwa klucza może się zmieniać?

Technicznie tak, ale praktycznie lepiej tego unikać. Zmiana klucza często wymaga zmian w wielu usługach naraz.

Czy tłumaczenia powinny być cache’owane?

Tak. Wielokrotne odczytywanie tych samych danych z pliku lub bazy bez cache jest niepotrzebnym obciążeniem.

Zakończenie

Dobrze zaprojektowany system tłumaczeń nie wygląda efektownie, ale ratuje projekt wtedy, gdy aplikacja zaczyna rosnąć. To jedna z tych rzeczy, które wydają się drobiazgiem na początku, a później decydują o kosztach utrzymania, czasie wdrożeń i liczbie błędów na produkcji. Porządek w kluczach, przewidywalna struktura i rozsądne reguły fallback są znacznie ważniejsze niż wybór konkretnego formatu pliku.

Źródło Foto: Freepik

Dodaj komentarz