Глобализация (глобализация, също интернационализация, i18n) — процес на подготовка на мобилно приложение за работа с няколко езика и регионални формати без промяна на изходния код. Включва изнасяне на текстови ресурси от кода, поддръжка на различни формати за дати, числа и валути, отчитане на посоката на текста (LTR/RTL) и адаптиране на оформлението за различни езици. В iOS се използват NSLocalizedString и Localizable.strings, в Android — strings.xml в директории values-{lang}. Повече в документацията на Apple за интернационализация.
Основни
Глобализация (съкратено 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), сортиране по правилата на locale (Collator), регионални символи (разделители на хиляди, десетични знаци). В IT Sectr вграждаме i18n на етапа на архитектурата, а не добавяме по-късно — това спестява до 60% време при последваща локализация.
NSLocalizedString — основният Swift макрос за работа с преводи. Формат: NSLocalizedString(«key», comment: «описание за преводача»). Макросът автоматично замества низа от Localizable.strings за текущата локала на устройството (NSLocale.preferredLanguages). Ако преводът за ключ не бъде намерен, се връща самият ключ или стойността в development language (обикновено en). Apple препоръчва използването на смислени ключове, а не английски низове като ключове.
// Localizable.strings (en)
// "welcome_title" = "Добре дошли!";
// 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 автоматично отразява оформлението. NavDrawer, иконите за назад/напред, подравняването на текста трябва да работят и в двете посоки. В кода използвайте 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). Никога не използвайте compareTo() за низове, показвани на потребителя — той използва Unicode Code Point order, който не отчита регионални правила.
Архитектурни принципи — започнете i18n от първия commit. Всеки низ в кода трябва да премине през обвиваща функция (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) оформлението се показва правилно на 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. Оформлението трябва да се отразява огледално: меню отдясно, текст — отдясно наляво, икони за навигация — обърнати.
За глобално публикуване минимален набор: английски, испански, френски, немски, японски, китайски, корейски, португалски, руски, италиански. App Store изисква поне английска локализация. Всяка допълнителна локализация увеличава потенциалната аудитория. За локалния пазар са достатъчни 1–2 езика.
Резюме
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също