Локалізація та інтернаціоналізація мобільних застосунків

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 12 з 12Усі 1735 послуг
Локалізація мобільної гри
Середній
від 1 тижня до 3 місяців
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Локалізація мобільних додатків: i18n, RTL, динамічне переключення мови

Локалізація—не просто переклад строк. Дата «04/05/2024» у США означає 5 квітня, в Європі—4 травня. Сума «1,000.50» в більшості країн—тисяча з половиною, в Германії—один та п'ятдесят центів. Кількість слів для «1 файл», «3 файли», «5 файлів» в українській—три різні форми; арабська має шість форм множинного числа. Якщо архітектура додатку не враховує це з самого початку, локалізація перетворюється на серію патчів.

Базова інфраструктура: строки, формати, плюралізація

iOS: Localizable.strings та String Catalogs

Історично строки в iOS зберігалися в Localizable.strings—простому форматі key=value. З Xcode 15 з'явилися String Catalogs (.xcstrings)—JSON-based формат, який зберігає всі локалі в одному файлі, показує статус перекладу (перекладено/застарілі/відсутні) та інтегрований з UI Xcode.

String(localized: "welcome_title") в Swift 5.7+ замість NSLocalizedString("welcome_title", comment: ""). Коротше, типобезпечніше. String Interpolation в локалізованих строках: String(localized: "items_count \(count)") з правилом плюралізації в .xcstrings—система автоматично вибирає правильну форму для мови.

Плюралізація через .stringsdict (старий підхід) або прямо в String Catalog з NSStringPluralRuleType. Для української потрібно визначити форми one (1 файл), few (3 файли), many (5 файлів), other (fallback). Пропустити few для української—означає отримати «5 файлів» там де повинно бути «3 файли».

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 зменшується, ресурси потрібних локалей завантажуються через 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 генерує типизований код. Плюралізація через {count, plural, one{# файл} few{# файли} many{# файлів} other{# файлів}} в ARB.

Для великих додатків з 50+ мовами—easy_localization з підтримкою YAML/JSON/CSV форматів та lazy loading перекладів: не все 50 мов завантажуються відразу, тільки потрібна.

RTL: письмо справа наліво

Арабська, іврит, перська, урду—RTL (Right-to-Left) мови. Це змінює не тільки напрямок тексту, але всю раскладку UI: кнопка back справа, іконки дзеркально, паддинги та марджини інвертовані.

На iOS все робиться через semanticContentAttribute та Auto Layout. Layout constraint-и з leading/trailing (не left/right) автоматично інвертуються при RTL. UIView.semanticContentAttribute = .forceRightToLeft для конкретного компонента. Системні компоненти (UINavigationController, UITableView, UIStackView) переключаються автоматично при RTL-локалі. Проблеми виникають з кастомними UI, де розробник жорстко використав left/right констрейнти або frame-based layout.

На Android android:supportsRtl="true" в AndroidManifest включає RTL-підтримку. start/end замість left/right в XML-атрибутах: paddingStart, layout_marginEnd, textAlignment="viewStart". LayoutInflater з android:layoutDirection="rtl" для preview. Іконки з напрямком (стрілки, шевроны) потрібно дзеркалювати—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 для debugging.

Динамічне переключення мови

Переключення мови без перезапуску додатку—нетривіальне завдання, особливо якщо система побудована на системній локалі.

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.

Flutter—найпростіший з трьох. LocalizationsDelegate перезагружається при зміні locale в MaterialApp. Зберігаємо вибрану мову в провайдері (Riverpod/Provider/Bloc), зміна locale в MaterialApp перестраює дерево з новими строками. Практично без бойлерплейту при використанні easy_localization.

Форматування дат, чисел, валют

DateFormatter (iOS) та DateFormat (Android, intl)—завжди з явним locale, ніколи без нього. DateFormatter().dateStyle = .medium з locale = Locale(identifier: "uk_UA") даст «4 травня 2024 р.», з Locale(identifier: "en_US")—«May 4, 2024».

NumberFormatter / NumberFormat.currency() для валют. Символ валюти, розділювачи тисяч та дробної частини—все locale-специфічно. Хардкодити «₴» або «,» як розділювач—помилка. Locale(identifier: "uk_UA") + NumberFormatter.numberStyle = .currency з currencyCode = "UAH" даст правильне форматування автоматично.

Відносний час («2 години тому», «вчора»): RelativeDateTimeFormatter (iOS 13+) та RelativeTimeFormatter через intl пакет на Flutter/Android—не вигадуйте велосипед з ручним форматуванням.

Типові помилки при локалізації

Конкатенація строк замість форматування: "Hello, " + name + "!" працює для SVO-мов, але в японській ім'я йде перед ображенням. String(format: "greeting %@", name) з greeting = "%@ さん、こんにちは" в японському файлі—правильно.

Фіксований розмір UI під текст. Німецька в середньому на 30% довша за англійську. AutoLayout з правильними констрейнтами, adjustsFontSizeToFitWidth де допустимо, динамічна зміна висоти ячейк через UITableView.automaticDimension.

Зображення з embedded текстом—вимагають локалізованих версій або заміни на text overlay.

Графік

Додавання однієї нової мови в уже локалізований додаток (тільки переклад строк, без RTL)—2–3 дні технічної роботи + час перекладу. Первинна настройка інфраструктури локалізації з нуля, включаючи RTL-підтримку та динамічне переключення мови—2–4 тижні.