Globalizacja (globalizacja, także internacjonalizacja, i18n) — proces przygotowania aplikacji mobilnej do pracy z wieloma językami i formatami regionalnymi bez zmiany kodu źródłowego. Obejmuje wyodrębnienie zasobów tekstowych z kodu, obsługę różnych formatów dat, liczb i walut, uwzględnienie kierunku tekstu (LTR/RTL) i adaptację układu do różnych języków. W iOS używane są NSLocalizedString i Localizable.strings, w Android — strings.xml w katalogach values-{lang}. Więcej w dokumentacji Apple dotyczącej internacjonalizacji.
Najważniejsze
Globalizacja (w skrócie i18n — 18 liter między «i» a «n») — architektoniczne przygotowanie aplikacji do pracy z dowolnym językiem i regionem. Kluczowa zasada i18n: żaden ciąg tekstowy nie powinien być zakodowany na sztywno (hardcoded) w kodzie źródłowym. Zamiast tego stringi są wyodrębniane do plików zasobów, a kod odwołuje się do nich za pomocą kluczy. Przy dodawaniu nowego języka wystarczy dodać plik tłumaczenia — kod pozostaje niezmieniony. To odróżnia i18n od lokalizacji (l10n), gdzie tłumaczone są same stringi.
Argument biznesowy — globalizacja zwiększa rynek. Według Common Sense Advisory (2023), ponad 70% użytkowników woli kupować w aplikacjach w swoim ojczystym języku. Lokalizacja na 10 języków zwiększa potencjalną publiczność o 80%. Bez i18n każde rozszerzenie o nowy język wymaga modyfikacji kodu, co spowalnia wejście na rynek i zwiększa koszt 5–10 razy. Poprawna architektura i18n pozwala obsługiwać 40+ języków przy minimalnych kosztach.
Komponenty i18n obejmują: wyodrębnianie stringów (String externalization), formy liczby mnogiej (pluralization dla 1/2/5+), formatowanie dat i liczb (DateFormatter/SimpleDateFormat), obsługę języków RTL (Right-to-Left), sortowanie według reguł locale (Collator), symbole regionalne (separatory tysięcy, znaki dziesiętne). W IT Sectr uwzględniamy i18n na etapie architektury, a nie dodajemy po fakcie — to oszczędza do 60% czasu przy późniejszej lokalizacji.
NSLocalizedString — główne makro Swift do pracy z tłumaczeniami. Format: NSLocalizedString(«key», comment: «opis dla tłumacza»). Makro automatycznie podstawia string z Localizable.strings dla bieżącego locale urządzenia (NSLocale.preferredLanguages). Jeśli tłumaczenie dla klucza nie zostanie znalezione, zwracany jest sam klucz lub wartość w development language (zwykle en). Apple zaleca używanie znaczących kluczy, a nie angielskich stringów jako kluczy.
// Localizable.strings (en)
// "welcome_title" = "Witamy!";
// Localizable.strings (ru)
// "welcome_title" = "Witamy!";
// Kod Swift — jeden dla wszystkich języków
titleLabel.text = NSLocalizedString(
"welcome_title",
comment: "Nagłówek ekranu powitalnego"
)
// Formy liczby mnogiej przez Localizable.stringsdict
//
// <dict>
// <key>items_count</key>
// <dict>
// <key>NSStringLocalizedFormatKey</key>
// <string>%#@items@</string>
// <key>items</key>
// <dict>
// <key>one</key>
// <string>%d produkt</string>
// <key>few</key>
// <string>%d produkty</string>
// <key>many</key>
// <string>%d produktów</string>
// </dict>
// </dict>
// </dict>
// Użycie form liczby mnogiej
let items = 5
let label = String.localizedStringWithFormat(
NSLocalizedString("items_count", comment: ""), items
)
XLIFF — format wymiany tłumaczeń między programistami a tłumaczami. Xcode eksportuje plik XLIFF (Editor → Export for Localization), który zawiera wszystkie stringi do tłumaczenia. Tłumacz pracuje z XLIFF w narzędziach CAT (Trados, memoQ, Smartcat). Po tłumaczeniu XLIFF jest importowany z powrotem do Xcode (Editor → Import Localizations). XLIFF automatycznie aktualizuje wszystkie katalogi .lproj. To standardowy proces pracy nad lokalizacją aplikacji iOS w produkcji.
SwiftUI współpracuje z NSLocalizedString przez inicjalizator Text. Tekst w SwiftUI jest automatycznie umiędzynarodowiony: Text(«welcome_title») szuka tłumaczenia w Localizable.strings tak samo jak NSLocalizedString. Dla form liczby mnogiej użyj Text(«%d items», count: items). SwiftUI obsługuje formatowanie dat przez Text(date, style: .date) — automatycznie używa Locale.current. Apple zaleca SwiftUI dla nowych projektów, ponieważ internacjonalizacja w nim jest bardziej przejrzysta.
Android i18n opiera się na systemie zasobów. Stringi są wyodrębniane do res/values/strings.xml dla domyślnego języka (zwykle angielskiego). Dla każdego języka tworzony jest osobny katalog: res/values-ru/strings.xml (rosyjski), res/values-de/strings.xml (niemiecki), res/values-fr/strings.xml (francuski). Android automatycznie wybiera stringi na podstawie języka systemowego urządzenia (Locale.getDefault()). Jeśli nie ma dokładnego locale, podstawiana jest bazowa wersja (values/strings.xml).
// res/values/strings.xml (angielski, domyślnie)
<resources>
<string name="welcome_title">Welcome!</string>
<string name="items_count">%d item(s)</string>
</resources>
// res/values-ru/strings.xml (rosyjski)
<resources>
<string name="welcome_title">Witamy!</string>
<plurals name="items_count">
<item quantity="one">%d produkt</item>
<item quantity="few">%d produkty</item>
<item quantity="many">%d produktów</item>
</plurals>
</resources>
// Kod Kotlin
textView.text = getString(R.string.welcome_title)
// Formy liczby mnogiej
val items = 5
textView.text = resources.getQuantityString(
R.plurals.items_count, items, items
)
// Obsługa RTL w kodzie
textView.textDirection = View.TEXT_DIRECTION_LOCALE
// Manifest: supportsRtl="true"
RTL (Right-to-Left) — obsługa języków, w których tekst czyta się od prawej do lewej (arabski, hebrajski, urdu, perski). Android obsługuje RTL przez atrybuty android:layoutDirection i android:textDirection. W manifeście ustaw android:supportsRtl="true" — a Android automatycznie odbija layout. NavDrawer, ikony wstecz/do przodu, wyrównanie tekstu powinny działać w obie strony. W kodzie używaj View.LAYOUT_DIRECTION_LOCALE i Gravity.START/END zamiast LEFT/RIGHT.
Android Resource Qualifiers pozwalają lokalizować nie tylko stringi, ale także obrazy (res/drawable-ru/), layouty (res/layout-ru/), animacje, kolory. Dla arabskiego i hebrajskiego potrzebne są osobne layouty z lustrzanym rozmieszczeniem elementów — użyj res/layout-ar/ (arabski). Android obsługuje również warianty regionalne: values-rUS, values-rGB, values-de-DE. Qualifiers łączą się: values-ldrtl-ru — rosyjski dla wyświetlaczy RTL.
Daty i czas — jeden z kluczowych aspektów i18n. Różne regiony używają różnych formatów: Rosja — DD.MM.RRRR, USA — MM/DD/RRRR, Japonia — RRRR.MM.DD. Używanie stałego formatu (yyyy-MM-dd) do wyświetlania użytkownikowi — błąd. W iOS używaj DateFormatter z Locale(identifier: locale), w Android — DateFormat.getDateInstance(DateFormat.SHORT, locale). Dla asystentów głosowych i wyszukiwania AI daty powinny być w ISO 8601 w wewnętrznej reprezentacji.
Liczby i waluta — w różnych regionach różne separatory: 1,234.56 (USA) vs 1.234,56 (Rosja), 1 234,56 (Francja). iOS: NumberFormatter z .locale = locale. Android: DecimalFormat z DecimalFormatSymbols(locale). Dla walut: format ¥1,234 (Japonia) vs $1,234.56 (USA) vs 1 234,56 ₽ (Rosja). Nigdy nie konkatenuj waluty i liczby ręcznie — używaj NumberFormatter.currencyCode i .currencySymbol.
| Region | Data | Liczba | Waluta |
|---|---|---|---|
| Rosja | 31.12.2024 | 1 234,56 | 1 234,56 ₽ |
| USA | 12/31/2024 | 1,234.56 | $1,234.56 |
| Niemcy | 31.12.2024 | 1.234,56 | 1.234,56 € |
| Japonia | 2024/12/31 | 1,234 | ¥1,234 |
| Arabia Saudyjska | 31/12/2024 | 1,234.56 | 1,234.56 SAR |
Sortowanie (Collation) — sortowanie alfabetyczne różni się w różnych językach. W hiszpańskim «ch» występuje po «c». W szwedzkim «ä» — na końcu alfabetu. W niemieckim «ß» sortuje się jak «ss». iOS: LocalizedComparison (String.localizedCompare). Android: Collator.getInstance(locale). Nigdy nie używaj compareTo() dla stringów wyświetlanych użytkownikowi — używa on Unicode Code Point order, nie uwzględniającego reguł regionalnych.
Zasady architektoniczne — zaczynaj i18n od pierwszego commita. Każdy string w kodzie powinien przejść przez funkcję opakowującą (tr("key")), która nie istnieje przed skonfigurowaniem i18n — to zmusi programistę do wyodrębniania stringów od razu. Nie używaj angielskich stringów jako kluczy — przy zmianie sformułowania po angielsku trzeba będzie zaktualizować wszystkie tłumaczenia. Używaj znaczących kluczy: «profile.title», «settings.language.label».
Pseudolokalizacja — technika testowania i18n przed rzeczywistym tłumaczeniem. Zastąp każdą literę łacińską symbolem z diakrytyką (á, é, ñ, ü) do sprawdzenia kodowania, dodaj prefiks [XXX] do sprawdzenia obcinania stringów. Xcode: schematy uruchamiania — pseudojęzyk «Double-Length Pseudolanguage». Android: Developer Options — Force RTL layout direction, System font scale do 200%. Pseudolokalizacja znajduje 80% problemów i18n bez udziału tłumacza.
Lista kontrolna IT Sectr i18n — przed wydaniem sprawdzamy: (1) brak hardcoded stringów w kodzie (wyjątek: logi), (2) formy liczby mnogiej działają poprawnie dla wszystkich języków, (3) daty/liczby są formatowane przez Locale API, (4) layout poprawnie wyświetla się w językach RTL, (5) stringi nie są obcinane przy maksymalnym skalowaniu, (6) pseudolokalizacja nie wykazała błędów, (7) wszystkie języki zadeklarowane w sklepach mają kompletny zestaw tłumaczeń.
Często zadawane pytania
i18n (internacjonalizacja) — przygotowanie kodu: wyodrębnianie stringów, obsługa RTL, formatowanie. Wykonywane przez programistę raz. l10n (lokalizacja) — tłumaczenie stringów na konkretny język. Wykonywane przez tłumacza wielokrotnie dla każdej lokalizacji. i18n — architektura, l10n — treść. Bez i18n lokalizacja jest w ogóle niemożliwa.
NSLocalizedString — makro, które szuka wartości po kluczu w Localizable.strings dla bieżącego locale urządzenia. Jeśli tłumaczenie zostanie znalezione — zwraca je. Jeśli nie — zwraca klucz. Format: NSLocalizedString(«key», comment: «opis»). Do formatowania z parametrami użyj String.localizedStringWithFormat().
strings.xml — plik z tłumaczeniami w katalogu res/values/{lang}/. Bazowa wersja w values/strings.xml, tłumaczenia — w values-ru/strings.xml. Kod odwołuje się przez getString(R.string.key). Android sam wybiera odpowiedni plik na podstawie języka systemowego. Dla form liczby mnogiej używany jest zasób <plurals> z kwalifikatorami zero/one/few/many/other.
RTL (Right-to-Left) — kierunek pisma dla arabskiego, hebrajskiego, urdu, perskiego. Android: supportsRtl="true" w manifeście, android:layoutDirection, Gravity.START/END. iOS: UISemanticContentAttribute.forceLeftToRight dla wymuszonego RTL. Layout powinien odbijać się lustrzanie: menu po prawej, tekst — od prawej do lewej, ikony nawigacji — odwrócone.
Do globalnej publikacji minimalny zestaw: angielski, hiszpański, francuski, niemiecki, japoński, chiński, koreański, portugalski, rosyjski, włoski. App Store wymaga co najmniej lokalizacji angielskiej. Każda dodatkowa lokalizacja zwiększa potencjalną publiczność. Dla lokalnego rynku wystarczy 1–2 języki.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również