Какие проблемы решает локализация мобильных игр?
Текст не влезает в кнопку на немецком? Диалог ломается на арабском? Это типичные последствия отсутствия локализации. За 5 лет мы локализовали более 50 проектов — от казуалок с 500 строками до RPG с 200 000 строк. И знаем, какие грабли встречаются чаще всего.
Локализация — не просто перевод, а техническая интеграция: адаптация UI под RTL, работа с падежами, шрифтами и аудио. Свяжитесь с нами для аудита вашего проекта — мы оценим объём и подготовим план.
Расширение текста и layout
Немецкий текст в среднем на 30% длиннее английского. «Inventory» — «Inventar» ещё ок, но «Achievement Unlocked» -> «Erfolg freigeschaltet» уже не влезает в кнопку. В Unity это решается через TextMeshPro с Auto Size — шрифт уменьшается до Min Size, а дальше текст обрезается. Нужно задавать разумный Min Size (не меньше 60% от базового) и тестировать все UI-панели на немецком и финском — у финского тоже длинные слова.
В Unreal — STextBlock с WrapTextAt и AutoWrapText. В Godot — Label с autowrap и динамическим размером контейнера.
Арабский и иврит — весь UI переворачивается (RTL). Unity не поддерживает RTL из коробки — нужен пакет RTL-TMPro (бесплатный, GitHub) или I2 Localization с RTL-поддержкой. Unreal с версии 4.23 поддерживает RTL через Internationalization модуль нативно. Подробнее о RTL-вёрстке можно почитать на Wikipedia.
Падежи, склонения и ветвящиеся строки
«Вы получили [item]» — если item это «меч», то «Вы получили меч». Если «броня» — «Вы получили броню». Жёсткая подстановка через string.Format("Вы получили {0}", itemName) даёт «Вы получили броня».
Решения:
- PluralKit-подход в Unity через I2 Localization с поддержкой CLDR plural rules и gender.
- Хранить несколько форм существительного в данных предмета (nominative, accusative, genitive) и выбирать нужную по контексту строки.
- Для сложных случаев — MessageFormat (ICU) с select и plural блоками.
Японский и корейский не имеют падежей, но порядок слов обратный — глагол в конце. «Attack the enemy» -> \「敵を攻撃する\」. Строки с вставленными именами работают только если переводчик знает, куда вставляется подстановка: {player_name} defeated {enemy_name} -> в японском порядок может быть {enemy_name}を{player_name}が倒した. Рекомендации ICU (см. ICU User Guide) советуют использовать именованные плейсхолдеры.
Проблемы RTL в Unity: решение
Для Unity используйте пакет RTL-TMPro или I2 Localization. После установки настройте шрифт, поддерживающий арабские лигатуры (например, Noto Naskh Arabic). Проверьте все UI-элементы: текст должен быть выровнен вправо, а элементы интерфейса — зеркально отражены. 90% проблем решаются автоматически, если настроить RTL до начала перевода.
Значение именованных плейсхолдеров
Без именованных плейсхолдеров переводчик не может изменить порядок слов. Это приводит к грамматическим ошибкам в японском, корейском, арабском и других языках. Именованные плейсхолдеры (например, {player_name}) позволяют переводчику видеть, что подставляется, и расставлять слова в правильном порядке. Мы всегда используем их во всех проектах — это гарантия качества перевода.
Пример из практики: RPG на Unity с 20 000 строк
При локализации на арабский все UI-элементы съезжали. Мы за 2 дня подключили I2 Localization с RTL-модулем, настроили шрифт Noto Naskh Arabic и проверили все 50 экранов. В результате игра вышла на Ближнем Востоке с ростом установок на 60%. Использование Translation Memory позволило сэкономить 30% бюджета на перевод повторяющихся строк.
Как правильно настроить RTL в Unity?
Для Unity используйте I2 Localization с RTL-модулем. Установите пакет RTL-TMPro либо встроенную поддержку I2L. Настройте шрифт, поддерживающий арабские лигатуры (Noto Naskh Arabic). Все UI-элементы с текстом должны иметь выравнивание вправо, а контейнеры — зеркальное отражение. Проверьте каждый экран на длинном арабском тексте.
| Движок |
Рекомендуемый инструмент |
RTL |
ICU |
Plural forms |
| Unity |
I2 Localization |
+ (плагин) |
+ |
+ (CLDR) |
| Godot |
TranslationServer + PO |
+ (4.0+) |
- |
+ (limited) |
| React Native |
i18next + react-i18next |
+ |
+ |
+ |
Сравнение инструментов локализации
| Инструмент |
Движки |
RTL |
ICU |
Стоимость |
| I2 Localization |
Unity |
+ (плагин) |
+ |
Платный |
| Lean Localization |
Unity |
- |
- |
Платный |
| i18next + react-i18next |
React Native |
+ |
+ |
Бесплатно |
| TranslationServer |
Godot |
+ (4.0+) |
- |
Встроено |
Unity. I2 Localization — де-факто стандарт. Google Sheets интеграция: переводчики работают прямо в таблице, изменения подтягиваются через Build или runtime. Альтернатива — Lean Localization (проще, меньше возможностей). Для голосового актёрства — отдельная таблица с ключами аудио-файлов.
Godot. Встроенная система через TranslationServer + CSV или PO-файлы. PO-файлы удобнее для работы с профессиональными переводчиками (поддерживает Poedit, Crowdin).
React Native (Expo games, казуалки). i18next + react-i18next. Для более серьёзных игр на RN — тот же i18next с ICU-плагином.
Нейтральный pipeline. Экспорт строк в XLIFF 2.0 или CSV -> Translation Memory в CAT-инструменте (MemoQ, Phrase, Crowdin) -> импорт обратно. Это важно для согласованности терминологии: «урон» должен везде переводиться одинаково, переводчик видит контекст предыдущих переводов.
Пример конфигурации I2 Localization для RTL
- Установите I2 Localization из Asset Store.
- Включите RTL-модуль в настройках: I2L => Tools => Enable RTL.
- Для TextMeshPro добавьте компонент I2BaseLocalization и выберите язык.
- Шрифт должен содержать арабские глифы. Импортируйте Noto Naskh Arabic как TMP_FontAsset.
- Для UI-элементов с текстом установите выравнивание вправо.
Шрифты и символы
Китайский (упрощённый + традиционный), японский, корейский требуют шрифтов с соответствующими глифами. В TextMeshPro нельзя использовать один Atlas для всех языков — CJK требует отдельного Font Asset с нужным Character Set. Dynamic Font Asset (TMP) загружает глифы on-demand из системного шрифта — удобно, но добавляет runtime-зависимость.
Арабский — шрифт должен поддерживать лигатуры (буквы меняют форму в зависимости от позиции в слове). Noto Naskh Arabic, Cairo — хорошие бесплатные варианты.
Аудио-локализация
Голосовое актёрство (VO) — самая дорогая часть. Синхронизация субтитров с аудио: в Unity через Timeline или AudioSource.clip.length — субтитры появляются по событиям или по таймкодам. Lip-sync в 3D-персонажах — Oculus LipSync, SALSA LipSync (платный), или процедурный через Phoneme-систему.
Для казуальных игр без VO — только текст + SFX. Здесь локализация занимает 1-3 недели.
Процесс работы: что входит в услугу
-
Аудит строк — экстракция всех hardcoded строк из кода и префабов, создание ключей. Вы получаете полный отчёт о количестве строк, их типах и сложности.
-
Инструментирование — подключение локализационной системы (I2L, Godot TranslationServer) с учётом вашего стека.
-
Передача переводчикам — XLIFF/CSV с контекстом (скриншоты экранов, описание сцены). Мы работаем с проверенными бюро переводов — это гарантирует качество.
-
Интеграция переводов — импорт, проверка layout на каждом языке, исправление ошибок вёрстки.
-
Тестирование — прохождение ключевых флоу на каждом языке, проверка RTL, проверка edge-cases (длинные имена, числа в строках).
- Документация и поддержка — передаём исходники, конфиги, инструкцию по добавлению новых языков.
Сроки: от 1 недели (казуальная игра, 2-3 языка) до 3 месяцев (RPG с разветвлёнными диалогами, 10+ языков, VO). Стоимость рассчитывается индивидуально после анализа объёма контента. Закажите локализацию и получите готовое решение под ключ. Свяжитесь с нами для аудита вашего проекта — мы определим объём работ и сроки.
Локализация мобильных приложений: i18n, RTL, динамическое переключение языка
При локализации приложений мы часто сталкиваемся с неочевидными ошибками: дата 04/05 для американца — это 5 апреля, для европейца — 4 мая. Сумма «1,000.50» в большинстве стран — тысяча с половиной, в Германии — один и пятьдесят сантов. Число слов для «1 файл», «3 файла», «5 файлов» в русском — три разные формы; арабский имеет шесть форм множественного числа. Если архитектура приложения не учитывает это с самого начала, локализация превращается в серию патчей. Наш 7-летний опыт в мобильной разработке и 50+ релизов в App Store и Google Play подтверждают: правильный i18n/l10n с первого коммита окупается многократно.
Как настроить базовую инфраструктуру локализации?
iOS: от Localizable.strings к String Catalogs
Исторически строки в iOS хранились в Localizable.strings — простой key=value формат. С Xcode 15 появились String Catalogs (.xcstrings) — JSON-based формат, который хранит все локали в одном файле, отображает статус перевода (переведено/устарело/отсутствует) и интегрирован с Xcode UI.
String(localized: "welcome_title") в Swift 5.7+ заменяет NSLocalizedString(...). Короче, типобезопаснее. String Interpolation в локализованных строках: String(localized: "items_count \(count)") с правилом плюрализации в .xcstrings — система автоматически выберет нужную форму для языка. Плюрализация через .stringsdict (старый подход) или прямо в String Catalog с NSStringPluralRuleType. Для русского нужно определить формы one (1 файл), few (3 файла), many (5 файлов), other (fallback). Пропустить few для русского — значит получить «5 файлов» там где должно быть «3 файлы». String Catalogs сокращают время настройки в два раза по сравнению со .stringsdict.
Android: XML resources и строковые форматы
res/values/strings.xml для базовой локали (en), res/values-ru/strings.xml для русского. Plural strings через <plurals> с <item quantity="one">, <item quantity="few">, <item quantity="many">. resources.getQuantityString(R.plurals.file_count, count, count) — первый count выбирает форму, второй подставляется в строку.
В Compose: stringResource(R.string.key) и pluralStringResource(R.plurals.file_count, count, count). Типобезопасная альтернатива — библиотека Lyricist, которая генерирует типизированные строки из аннотаций.
Android App Bundle с android:splitByLocale="true" в bundle.gradle — ресурсы доставляются только для языков устройства. APK уменьшается на 15-20%, ресурсы нужных локалей догружаются через Play Asset Delivery. Важно: на Android 8+ Configuration.locales — список, не один язык.
Flutter: intl и слои абстракции
Flutter intl пакет — стандарт. AppLocalizations.of(context).welcomeTitle генерируется из ARB-файлов (app_en.arb, app_ru.arb). flutter gen-l10n генерирует типизированный код. Pluralization через {count, plural, one{# файл} few{# файла} many{# файлов} other{# файла}} в ARB.
Для больших приложений с 50+ языками — easy_localization с поддержкой YAML/JSON/CSV форматов и lazy loading переводов: не все 50 языков грузятся сразу, только нужный. Это снижает размер начальной загрузки на 30%.
Сравнительная таблица подходов
| Параметр |
iOS (String Catalogs) |
Android (XML) |
Flutter (ARB) |
| Формат хранения |
JSON (.xcstrings) |
XML |
JSON (ARB) |
| Плюрализация |
Встроенная в Xcode |
<plurals> |
ICU message syntax |
| Типобезопасность |
String Catalog – кодогенерация (Swift 5.9) |
R.java / ViewBinding |
gen-l10n |
| Статус переводов |
Визуальный в Xcode |
Только сторонние инструменты |
Только сторонние инструменты |
| RTL из коробки |
Auto Layout (leading/trailing) |
supportsRtl + start/end |
Directionality Widget |
Как реализовать RTL-поддержку без переписывания UI?
Арабский, иврит, персидский, урду — языки RTL (Right-to-Left). Это меняет не только направление текста, но и всю раскладку UI: back button справа, иконки зеркально, паддинги и марджины инвертируются.
На iOS всё делается через semanticContentAttribute и Auto Layout. Layout constraint-ы с leading/trailing (не left/right) автоматически инвертируются при RTL. UIView.semanticContentAttribute = .forceRightToLeft для конкретного компонента. Системные компоненты (UINavigationController, UITableView, UIStackView) переключаются автоматически при RTL-локали. Проблемы возникают с кастомными UI, где разработчик жёстко использовал left/right констрейнты или frame-based layout. Мы в таких случаях переписываем кастомные вью на Auto Layout — это занимает 1-2 дня на экран.
На Android android:supportsRtl="true" в AndroidManifest включает RTL-поддержку. start/end вместо left/right в XML-атрибутах: paddingStart, layout_marginEnd, textAlignment="viewStart". LayoutInflater с android:layoutDirection="rtl" для превью. Иконки с направленностью (стрелки, шеврон) нужно зеркалировать — android:autoMirrored="true" в drawable для автоматического инвертирования при RTL.
На Flutter Directionality виджет с TextDirection.rtl управляет направлением для поддерева. Padding(EdgeInsetsDirectional.fromSTEB(...)) вместо EdgeInsets.only(left:...). Row автоматически учитывает TextDirection из Directionality. Большинство Material виджетов RTL-ready, но кастомные CustomPainter — нет: нужно получать TextDirection из context и учитывать вручную.
Тестирование RTL: на iOS Settings → General → Language & Region → Region: Saudi Arabia переключает в RTL режим без смены языка системы. На Android adb shell setprop debug.force.rtl 1 форсирует RTL для отладки. Это позволяет обнаружить до 80% проблем RTL до релиза.
Почему динамическое переключение языка — узкое место?
Переключение языка без перезапуска приложения — нетривиальная задача, особенно если система построена на системной локали. Мы выделили три основных подхода.
iOS не поддерживает смену языка приложения без перезапуска нативно. Самый чистый подход — хранить выбранный язык в UserDefaults, при запуске создавать Bundle с нужной локализацией, использовать кастомный NSLocalizedString через этот Bundle. Bundle.setLanguage("ru") через swizzling Bundle.localizedString(forKey:value:table:) — работает, но это runtime swizzling, что не идеально. Альтернатива: собственная система строк поверх NSBundle, которая перечитывает файлы при смене языка. При переключении — пересоздать корневой ViewController.
Android с API 33: LocaleManager.setApplicationLocales() — официальный API для смены языка приложения без перезапуска системы, без рекреации Activity если использовать AppCompatDelegate.setApplicationLocales(). До API 33 — Configuration.setLocale() + recreate() для Activity. При смене языка нужно уведомить все открытые Activity через broadcast или ViewModel. Для Android 12+ мы также используем android:localeConfig в манифесте — это позволяет системе узнать поддерживаемые языки без дополнительной конфигурации.
Flutter — самый простой из трёх. LocalizationsDelegate перезагружается при изменении locale в MaterialApp. Храним выбранный язык в провайдере (Riverpod/Provider/Bloc), изменение locale в MaterialApp перестраивает дерево с новыми строками. Практически без бойлерплейта при использовании easy_localization. Однако есть нюанс: все StatefulWidget-ы, которые не подписаны на смену локали, не обновятся — нужно явно передавать локаль через InheritedWidget или пересоздавать дерево.
Форматирование дат, чисел, валют
DateFormatter (iOS) и DateFormat (Android, intl) — всегда с явным locale, никогда без него. DateFormatter().dateStyle = .medium с locale = Locale(identifier: "ru_RU") даст «4 мая», с Locale(identifier: "en_US") — «May 4». Мы используем RelativeDateTimeFormatter (iOS 13+) и RelativeTimeFormatter через intl пакет — не изобретайте велосипед с ручным форматированием.
NumberFormatter / NumberFormat.currency() для валют. Символ валюты, разделители тысяч и дробной части — всё locale-специфично. Хардкодить «₽» или «.» как разделитель — ошибка. Locale(identifier: "ru_RU") + NumberFormatter.numberStyle = .currency с currencyCode = "RUB" даст правильное форматирование автоматически.
Типичные ошибки при локализации
Конкатенация строк вместо форматирования: "Hello, " + name + "!" работает для SVO-языков, но в японском имя идёт перед обращением. String(format: "greeting %@", name) с greeting = "%@ さん、こんにちは" в японском файле — правильно. Фиксированный размер UI под текст: немецкий в среднем на 30% длиннее английского. AutoLayout с правильными констрейнтами, adjustsFontSizeToFitWidth там где допустимо, динамическое изменение высоты ячеек через UITableView.automaticDimension. Изображения с embedded текстом требуют локализованных версий или замены на text overlay.
Процесс работы: как мы локализуем приложение под ключ
-
Аналитика и аудит (2-5 дней) — ревью кода на i18n-готовность, выявление хардкода, оценка RTL-сложности, подготовка карты экранов.
-
Проектирование архитектуры (3-7 дней) — выбор стека (String Catalogs/ARB/XML), настройка пайплайнов автоматизации (Crowdin/Lokalise), создание базовых строк.
-
Реализация (1-4 недели в зависимости от объёма) — внедрение i18n, плюрализации, RTL, форматирования. Параллельно — перевод контента.
-
Тестирование (3-7 дней) — функциональное (смена языка, RTL, отображение чисел), лингвистическое (LQA), скриншотное тестирование (локализованные стор-скриншоты).
-
Деплой и мониторинг (1-2 дня) — публикация в сторах, настройка аналитики (события на языки), обратная связь от пользователей.
Что входит в deliverables
- Исходный код с полной i18n-инфраструктурой
- Документация по добавлению нового языка (playbook)
- Файлы переводов (ARB/XML/xcstrings) + глоссарий
- Автоматизация: CI/CD интеграция с сервисами переводов
- Доступ к репозиторию с полной историей изменений
- Обучение команды заказчика (1-2 сессии)
- Гарантия на код — 6 месяцев, бесплатные фиксы багов локализации
Сроки и стоимость
| Этап |
Срок (ориентировочно) |
Что входит |
| Добавление одного нового языка (без RTL) |
2-3 дня технической работы + время перевода |
Настройка строк, тестирование, стор-скриншоты |
| Первичная локализация с нуля (10-15 экранов, без RTL) |
2-3 недели |
Архитектура, перевод, тестирование |
| Проект с RTL-поддержкой и динамическим переключением |
4-6 недель |
Всё включено + адаптация UI, пересборка кастомных компонентов |
Стоимость рассчитывается индивидуально на основе объёма кода, количества языков и сложности RTL. В среднем экономия бюджета за счёт автоматизации достигает 40%, а стоимость базового проекта по локализации (10–15 экранов, без RTL) составляет от 200 000 до 700 000 руб. Мы оцениваем проект бесплатно — свяжитесь, чтобы получить смету и план работ.
Почему стоит выбрать нас
Мы сертифицированные разработчики (Apple WWDC Scholarship, Google Associate Android Developer). За 5 лет на рынке реализовали более 50 проектов с локализацией, включая приложения для 15 языков с RTL. Гарантируем соблюдение App Store Review Guidelines (Section 4.2/5.1) и Google Play Policies (User Data). Наши клиенты отмечают сокращение времени вывода на новые рынки в среднем на 40% за счёт автоматизации переводов и продуманной архитектуры.
Дополнительную информацию об интернационализации и локализации можно найти в Wikipedia и спецификации RTL.
Получите консультацию по вашему проекту — оставьте заявку на сайте, мы подготовим детальный план и сроки. Закажите аудит локализации вашего приложения: первый этап показывает до 80% узких мест без затрат на реализацию.