Angielska wersja nowo wydanego analizatora Cache-Control wyświetlała tekst w języku japońskim – jego status brzmiał „新鮮” zamiast „Fresh”. Błąd wynikał ze współdzielonej logiki, która zwracała zakodowane na sztywno japońskie ciągi znaków, podczas gdy strona dostarczała jedynie angielskie etykiety.
Deweloper tworzy serię lekkich narzędzi przeglądarkowych, z których każde posiada wersję angielską i japońską, korzystające z tych samych funkcji parsujących i logiki rdzennej. Różnić powinno się jedynie widoczne brzmienie tekstów. Kiedy analizator Cache-Control został wydany, angielski interfejs wyświetlał poprawne etykiety, ale renderowane wartości pochodziły z warstwy logiki, która wciąż zawierała japońskie literały. W konsoli nie pojawiły się żadne błędy; strona wyglądała normalnie, jednak informacje prezentowane użytkownikom anglojęzycznym były błędne.
Dlaczego współdzielona logika może zawieść tłumaczenie
Błąd wynikał z decyzji projektowej: główna funkcja decydująca o tym, co ma zostać wyświetlone, zwracała japońskie ciągi znaków. Warstwa strony, odpowiedzialna za otaczający tekst w języku angielskim, nie miała szansy podmienić tych wartości. Ponieważ logika i interfejs użytkownika (UI) były wyraźnie rozdzielone, problem pozostał niewidoczny podczas testów – technicznie wszystko „działało”, mimo że język prezentowany użytkownikowi był nieprawidłowy.
Wadą jest to, że język użyty wewnątrz współdzielonego modułu staje się domyślnym dla każdego front-endu, który go wykorzystuje. Jeśli wymagany jest inny język, ten domyślny staje się ukrytym błędem.
Rozwiązanie: klucze, pakiety i siatka bezpieczeństwa
Autor przepisał architekturę, aby oddzielić poszczególne odpowiedzialności:
- Pakiety komunikatów (message packs) przechowują teraz wszystkie czytelne dla człowieka ciągi znaków dla każdego języka.
- Współdzielona logika zwraca jedynie symboliczne klucze, a nigdy surowy tekst.
- Strony wyszukują odpowiednie słowo w właściwym pakiecie na podstawie klucza.
Gdy komunikat musi zawierać liczbę, nowy kod wykorzystuje małą funkcję zamiast ciągu szablonowego (template string). Pozwala to każdemu językowi zdecydować, gdzie powinna znaleźć się liczba, uwzględniając różnice w szyku zdania.
Dodano również prosty krok analizy statycznej: proces budowania (build process) skanuje współdzielone pliki w poszukiwaniu japońskich znaków. Jeśli jakiekolwiek zostaną znalezione, deweloper jest natychmiast ostrzegany, co zapobiega ponownemu pojawieniu się zakodowanego na sztywno obcego tekstu.
Czego to doświadczenie nauczyło autora
- Tłumaczenie działa jak etap przeglądu. Podczas pisania angielskich komunikatów autor zauważył, że niektóre japońskie odpowiedniki były niejasne. Tłumaczenie wymusiło bardziej klarowne sformułowania w obu językach.
- Współdzielone funkcje zwracające ciągi znaków narzucają język wszystkim użytkownikom. Jeśli funkcja decyduje o języku, każdy odbiorca oczekujący innego języka dziedziczy ten błąd. Błąd ten nie jest usterką interfejsu (UI glitch), lecz wadą logiki.
Rekomendacje dla osób utrzymujących wielojęzyczne narzędzia
- Zwracaj klucze, a nie ciągi znaków, z funkcji rdzennych. Pozwól warstwie UI zająć się lokalizacją.
- Lub przekazuj pożądane ciągi znaków do funkcji jako parametry. Dzięki temu logika pozostaje niezależna od języka.
- Audytuj współdzielone moduły pod kątem zakodowanego na sztywno tekstu w języku ojczystym. Szybkie wyszukiwanie znaków spoza standardu ASCII może ujawnić ukryte problemy.
- Dodaj sprawdzanie obcych znaków w kodzie współdzielonym podczas budowania projektu. Wczesne wykrycie jest lepsze niż zamieszanie po wydaniu wersji.
Na co zwrócić uwagę w przyszłości
Wniosek: Jeśli Twój projekt współdzieli kod między wersjami językowymi, upewnij się, że część współdzielona nigdy nie decyduje o brzmieniu tekstów. Pozwól każdej stronie dostarczać własne słowa, a unikniesz wstydu związanego z angielską stroną, która przypadkowo mówi po japońsku.
