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). Если перевод для ключа не найден, возвращается сам ключ или значение в development language (обычно 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/ (арабский). Андроид также поддерживает региональные варианты: 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 сам выбирает нужный файл на основе системного языка. Для плюралов используется ресурс
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 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также