Globalization (глобалізація, також інтернаціоналізація, i18n) — процес підготовки мобільного додатку до роботи з кількома мовами та регіональними форматами без зміни вихідного коду. Включає винесення рядкових ресурсів з коду, підтримку різних форматів дат, чисел та валют, врахування напрямку тексту (LTR/RTL) та адаптацію макету під різні мови. У iOS використовується NSLocalizedString та Localizable.strings, у Android — strings.xml у директоріях values-{lang}. Докладніше — у документації Apple з інтернаціоналізації.
Головне
Globalization (скорочено i18n — 18 літер між «i» та «n») — архітектурна підготовка додатку до роботи з будь-якою мовою та регіоном. Ключове правило i18n: жоден рядок тексту не повинен бути жорстко закодований (hardcoded) у вихідному коді. Натомість рядки виносяться у ресурсні файли, а код звертається до них за ключами. При додаванні нової мови достатньо додати файл перекладу — код залишається незмінним. Це відрізняє i18n від локалізації (l10n), де перекладаються самі рядки.
Бізнес-аргумент — глобалізація збільшує ринок. За даними Common Sense Advisory (2023), понад 70% користувачів віддають перевагу покупкам у додатках рідною мовою. Локалізація на 10 мов збільшує потенційну аудиторію на 80%. Без i18n кожне розширення на нову мову вимагає доопрацювання коду, що уповільнює вихід на ринок і збільшує вартість у 5–10 разів. Правильна i18n-архітектура дозволяє підтримувати 40+ мов з мінімальними витратами.
Компоненти i18n включають: винесення рядків (String externalization), плюрали (pluralization для 1/2/5+), форматування дат і чисел (DateFormatter/SimpleDateFormat), підтримку RTL-мов (Right-to-Left), сортування за правилами локалі (Collator), регіональні символи (роздільники тисяч, десяткові знаки). В IT Sectr ми закладаємо i18n на етапі архітектури, а не додаємо постфактум — це економить до 60% часу при подальшій локалізації.
NSLocalizedString — основний макрос Swift для роботи з перекладами. Формат: NSLocalizedString("key", comment: "опис для перекладача"). Макрос автоматично підставляє рядок з Localizable.strings для поточної локалі пристрою (NSLocale.preferredLanguages). Якщо переклад для ключа не знайдено, повертається сам ключ або значення в мові розробки (зазвичай en). Apple рекомендує використовувати осмислені ключі, а не англійські рядки як ключі.
// Localizable.strings (en)
// "welcome_title" = "Welcome!";
// Localizable.strings (ru)
// "welcome_title" = "Добро пожаловать!";
// Код Swift — єдиний для всіх мов
titleLabel.text = NSLocalizedString(
"welcome_title",
comment: "Заголовок екрану привітання"
)
// Плюрали через Localizable.stringsdict
//
// <dict>
// <key>items_count</key>
// <dict>
// <key>NSStringLocalizedFormatKey</key>
// <string>%#@items@</string>
// <key>items</key>
// <dict>
// <key>one</key>
// <string>%d товар</string>
// <key>few</key>
// <string>%d товара</string>
// <key>many</key>
// <string>%d товаров</string>
// </dict>
// </dict>
// </dict>
// Використання плюралів
let items = 5
let label = String.localizedStringWithFormat(
NSLocalizedString("items_count", comment: ""), items
)
XLIFF — формат обміну перекладами між розробниками та перекладачами. Xcode експортує XLIFF-файл (Editor → Export for Localization), який містить усі рядки для перекладу. Перекладач працює з XLIFF у CAT-інструментах (Trados, memoQ, Smartcat). Після перекладу XLIFF імпортується назад у Xcode (Editor → Import Localizations). XLIFF автоматично оновлює всі .lproj-директорії. Це стандартний робочий процес локалізації iOS-додатків у продакшені.
SwiftUI працює з NSLocalizedString через ініціалізатор Text. Текст у SwiftUI автоматично інтернаціоналізований: Text("welcome_title") шукає переклад у Localizable.strings так само, як NSLocalizedString. Для плюралів використовуйте Text("%d items", count: items). SwiftUI підтримує форматування дат через Text(date, style: .date) — воно автоматично використовує Locale.current. Apple рекомендує SwiftUI для нових проектів, оскільки інтернаціоналізація в ньому більш прозора.
Android i18n будується на ресурсній системі. Рядки виносяться в res/values/strings.xml для мови за замовчуванням (зазвичай англійська). Для кожної мови створюється окрема директорія: res/values-ru/strings.xml (російська), res/values-de/strings.xml (німецька), res/values-fr/strings.xml (французька). Android автоматично вибирає рядки на основі системної мови пристрою (Locale.getDefault()). Якщо точної локалі немає, підставляється базова (values/strings.xml).
// res/values/strings.xml (англійська, за замовчуванням)
<resources>
<string name="welcome_title">Welcome!</string>
<string name="items_count">%d item(s)</string>
</resources>
// res/values-ru/strings.xml (російська)
<resources>
<string name="welcome_title">Ласкаво просимо!</string>
<plurals name="items_count">
<item quantity="one">%d товар</item>
<item quantity="few">%d товари</item>
<item quantity="many">%d товарів</item>
</plurals>
</resources>
// Код Kotlin
textView.text = getString(R.string.welcome_title)
// Плюрали
val items = 5
textView.text = resources.getQuantityString(
R.plurals.items_count, items, items
)
// Підтримка RTL у коді
textView.textDirection = View.TEXT_DIRECTION_LOCALE
// Manifest: supportsRtl="true"
RTL (Right-to-Left) — підтримка мов, де текст читається справа наліво (арабська, іврит, урду, фарсі). Android підтримує RTL через атрибут android:layoutDirection та android:textDirection. У маніфесті вкажіть android:supportsRtl="true" — і Android автоматично дзеркалить layout. NavDrawer, іконки back/forward, вирівнювання тексту повинні працювати в обидві сторони. У коді використовуйте View.LAYOUT_DIRECTION_LOCALE та Gravity.START/END замість LEFT/RIGHT.
Android Resource Qualifiers дозволяють локалізувати не тільки рядки, а й зображення (res/drawable-ru/), макети (res/layout-ru/), анімації, кольори. Для арабської та івриту потрібні окремі макети з дзеркальним розташуванням елементів — використовуйте res/layout-ar/ (арабська). Android також підтримує регіональні варіанти: values-rUS, values-rGB, values-de-DE. Qualifiers комбінуються: values-ldrtl-ru — російська для RTL-дисплеїв.
Дати та час — один із ключових аспектів i18n. Різні регіони використовують різні формати: Росія — ДД.ММ.РРРР, США — ММ/ДД/РРРР, Японія — РРРР.ММ.ДД. Використовувати фіксований формат (yyyy-MM-dd) для відображення користувачеві — помилка. В iOS використовуйте DateFormatter з Locale(identifier: locale), в Android — DateFormat.getDateInstance(DateFormat.SHORT, locale). Для голосових помічників та AI-пошуку дати повинні бути в ISO 8601 у внутрішньому представленні.
Числа та валюта — у різних регіонах різні роздільники: 1,234.56 (США) vs 1.234,56 (Росія), 1 234,56 (Франція). iOS: NumberFormatter з .locale = locale. Android: DecimalFormat з DecimalFormatSymbols(locale). Для валют: формат ¥1,234 (Японія) vs $1,234.56 (США) vs 1 234,56 ₽ (Росія). Ніколи не конкатенуйте валюту та число вручну — використовуйте NumberFormatter.currencyCode та .currencySymbol.
| Регіон | Дата | Число | Валюта |
|---|---|---|---|
| Росія | 31.12.2024 | 1 234,56 | 1 234,56 ₽ |
| США | 12/31/2024 | 1,234.56 | $1,234.56 |
| Німеччина | 31.12.2024 | 1.234,56 | 1.234,56 € |
| Японія | 2024/12/31 | 1,234 | ¥1,234 |
| Саудівська Аравія | 31/12/2024 | 1,234.56 | 1,234.56 SAR |
Сортування (Collation) — алфавітне сортування відрізняється в різних мовах. В іспанській «ch» йде після «c». У шведській «ä» — в кінці алфавіту. У німецькій «ß» сортується як «ss». iOS: LocalizedComparison (String.localizedCompare). Android: Collator.getInstance(locale). Never використовуйте compareTo() для рядків, що відображаються користувачеві — він використовує Unicode Code Point order, що не враховує регіональні правила.
Архітектурні принципи — починайте i18n з першого коміту. Кожен рядок у коді повинен пройти через функцію-обгортку (tr("key")), яка не існує до налаштування i18n — це змусить розробника виносити рядки одразу. Не використовуйте англійські рядки як ключі — при зміні формулювання англійською доведеться оновлювати всі переклади. Використовуйте осмислені ключі: «profile.title», «settings.language.label».
Псевдолокалізація — техніка тестування i18n до реального перекладу. Замініть кожну латинську літеру на символи з діакритикою (á, é, ñ, ü) для перевірки кодування, додайте префікс [XXX] для перевірки обрізання рядків. Xcode: схеми запуску — псевдомова «Double-Length Pseudolanguage». Android: Developer Options — Force RTL layout direction, System font scale до 200%. Псевдолокалізація знаходить 80% проблем i18n без участі перекладача.
IT Sectr чекліст i18n — перед релізом ми перевіряємо: (1) немає hardcoded рядків у коді (виняток: логи), (2) плюрали коректно працюють для всіх мов, (3) дати/числа форматуються через Locale API, (4) layout коректно відображається на RTL-мовах, (5) рядки не обрізаються при максимальному масштабуванні, (6) псевдолокалізація не виявила помилок, (7) всі мови, заявлені в сторах, мають повний набір перекладів.
Часті запитання
i18n (інтернаціоналізація) — підготовка коду: винос рядків, підтримка RTL, форматування. Робиться розробником один раз. l10n (локалізація) — переклад рядків на конкретну мову. Робиться перекладачем багато разів для кожної локалі. i18n — архітектура, l10n — контент. Без i18n локалізація неможлива в принципі.
NSLocalizedString — макрос, який шукає значення за ключем у Localizable.strings для поточної локалі пристрою. Якщо переклад знайдено — повертає його. Якщо ні — повертає ключ. Формат: NSLocalizedString("key", comment: "опис"). Для форматування з параметрами використовуйте String.localizedStringWithFormat().
strings.xml — файл з перекладами в директорії res/values/{lang}/. Базова версія в values/strings.xml, переклади — в values-ru/strings.xml. Код звертається через getString(R.string.key). Android сам вибирає потрібний файл на основі системної мови. Для плюралів використовується ресурс <plurals> з уточненнями zero/one/few/many/other.
RTL (Right-to-Left) — напрям письма для арабської, івриту, урду, фарсі. Android: supportsRtl="true" в маніфесті, android:layoutDirection, Gravity.START/END. iOS: UISemanticContentAttribute.forceLeftToRight для примусового RTL. Layout повинен дзеркально відображатися: меню справа, текст — справа наліво, іконки навігації — перевернуті.
Для глобальної публікації мінімальний набір: англійська, іспанська, французька, німецька, японська, китайська, корейська, португальська, російська, італійська. App Store вимагає мінімум англійську локалізацію. Кожна додаткова локаль збільшує потенційну аудиторію. Для локального ринку достатньо 1–2 мов.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також