Технічна локалізація мобільних ігор: повний цикл
Які проблеми вирішує локалізація мобільних ігор?
Наша команда має 5+ років досвіду та понад 50 виконаних проєктів. Текст не влізає в кнопку німецькою? Діалог ламається арабською? Це типові наслідки відсутності локалізації. За 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}) дозволяють перекладачу бачити, що підставляється, і розставляти слова в правильному порядку. Ми завжди використовуємо їх у всіх проєктах — це гарантія якості перекладу. За нашими даними, використання іменованих плейсхолдерів зменшує кількість граматичних помилок перекладу на 40%.
Приклад із практики: RPG на Unity з 20 000 рядків
При локалізації арабською всі UI-елементи з'їжджали. Ми за 2 дні підключили I2 Localization з RTL-модулем, налаштували шрифт Noto Naskh Arabic і перевірили всі 50 екранів. У результаті гра вийшла на Близькому Сході зі зростанням встановлень на 60%. Використання Translation Memory дозволило заощадити 30% бюджету на переклад повторюваних рядків. Наприклад, для проєкту з бюджетом $10 000 економія завдяки повторному використанню рядків може сягати $3 000.
Як правильно налаштувати 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). Вартість розраховується індивідуально після аналізу обсягу контенту. Наприклад, локалізація казуальної гри на 2 мови коштує від $500. Замовте локалізацію та отримайте готове рішення під ключ. Зв'яжіться з нами для аудиту вашого проєкту — ми визначимо обсяг робіт і терміни.
Локалізація мобільних додатків: 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-uk/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_uk.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("uk") через 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: "uk_UA") дасть «4 травня», з Locale(identifier: "en_US") — «May 4». Ми використовуємо RelativeDateTimeFormatter (iOS 13+) та RelativeTimeFormatter через intl пакет — не винаходьте велосипед з ручним форматуванням.
NumberFormatter / NumberFormat.currency() для валют. Символ валюти, роздільники тисяч та дробової частини — все locale-специфічно. Хардкодити «₴» або «.» як роздільник — помилка. Locale(identifier: "uk_UA") + NumberFormatter.numberStyle = .currency з currencyCode = "UAH" дасть правильне форматування автоматично.
Типові помилки при локалізації
Конкатенація рядків замість форматування: "Hello, " + name + "!" працює для SVO-мов, але в японській ім'я йде перед зверненням. String(format: "greeting %@", name) з greeting = "%@ さん、こんにちは" в японському файлі — правильно. Фіксований розмір UI під текст: німецька в середньому на 30% довша за англійську. AutoLayout з правильними констрейнтами, adjustsFontSizeToFitWidth там де допустимо, динамічна зміна висоти комірок через UITableView.automaticDimension. Зображення з вбудованим текстом вимагають локалізованих версій або заміни на 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%. Ми оцінюємо проект безкоштовно — зв'яжіться, щоб отримати кошторис та план робіт.
Чому варто обрати нас
Ми сертифіковані розробники (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% вузьких місць без витрат на реалізацію.