Багатомовні інтерфейси та локалізація
1) Принципи
1. Мова - не скін. Змінюються тексти, формати, напрямок письма, ілюстрації, юридичні блоки і навіть навігація.
2. Спочатку ключі, потім тексти. Структуруйте смислові ключі і параметри - переклади приходять пізніше.
3. Псевдолокалізація - до виходу. Ловіть переповнення, «жорстко пришиті» рядки і приховані англіцизми.
4. Фолбеки передбачувані.'ru-UA → ru → en'. Ніяких «тихих» провалів.
5. Безпека. Ніякого HTML з перекладу в DOM без санітайзу; плейсхолдери тільки позиційні/іменовані.
6. A11y-еквівалентність. Alt-тексти, aria-лейбли, скорочення - все локалізується.
2) Стратегія локалей
Системні коди: 'language-REGION'( наприклад,'pt-BR','en-GB').
Вибір локалі: профіль користувача → налаштування; запасний - авто-детект по браузеру/гео (з підтвердженням).
Мульти-регіон: відрізняйте мову від права: 'es-ES'≠'es-MX'( різні закони/платежі/ліміти).
Фолбек-ланцюжок: UI - найближча мова; правові тексти - строго регіональна версія, інакше блок і запит підтвердження.
3) Інформаційна архітектура та контент
Ключові області: навігація, CTA, помилки, форми, підказки, повідомлення, листи, PDF/банери.
Текстові розширення: резерв ширини + 30-40% (німецький/фінський). Лейаут - еластичний (flex/grid).
Тон/стиль: словник бренду (терміни, без «перекладу сленгу» в критичних місцях).
Зображення/іконки: уникайте тексту в картинках; якщо він потрібен - зберігайте локальні версії.
4) Архітектура i18n
Ключі: `domain. section. intent` → `payments. withdraw. error. insufficient_funds`.
Плейсхолдери: іменовані ('{ amount}','{ minutes}'), форматується поза рядком.
ICU MessageFormat: множинність, рід, узгодження.
Файли: по локалі і доменах ('/i18n/{ locale }/{ domain} .json'), чанки вантажаться ліниво.
Сервер/клієнт: універсальний рендер, локаль в cookie + HTTP-Vary.
json
{
"betslip": {
"placed": "Ставка на сумму {amount} {currency} принята",
"timeout": "Ожидаем подтверждение… ~{seconds, plural, one {# сек} few {# сек} many {# сек} other {# сек}}"
}
}
5) Форматування: числа, дати, валюти, одиниці
Використовуйте «Intl»:js const nf = new Intl.NumberFormat('uk-UA', { style:'currency', currency:'UAH' });
nf.format(2000); // 2 000,00 ₴
const df = new Intl.DateTimeFormat('tr-TR', { dateStyle:'medium', timeStyle:'short' });
df.format(new Date());
const pl = new Intl.PluralRules('ru-RU');
Мінорні одиниці: зберігайте суми в центах/копійках; форматуйте на клієнті.
Відносний час: `Intl. RelativeTimeFormat`.
Одиниці: `Intl. NumberFormat({ style:'unit', unit:'meter' })`.
Календар/тиждень: 1-й день тижня і формат дати - по локалі.
6) RTL і напрямок листа
Підтримайте'dir = «rtl»'для'ar','he','fa'; використовуйте'dir = «auto»'для користувацького контенту.
Інвертуйте іконки/chevron'и; дзеркальті каруселі і степпери.
Числа/символи валют - LTR-вікна (уникайте змішаного BiDi хаосу).
CSS-логічні властивості ('inline-start/end') замість left/right.
7) Форми і введення
Імена/адреси: допускайте апострофи/діакритику/подвійні прізвища.
Телефони: E.164 зберігання; маски - м'які, з підтримкою вставки.
Адресні формати: порядок полів по країні; індекс/штат можуть бути відсутні.
Клавіатури: 'inputmode','autocomplete'коректні для локалі.
Плейсхолдери: приклади на локальній мові/форматі.
8) Псевдолокалізація та тестування
Автоматично замінюйте рядки на'【 Вимкніть ěţš 】'+ подовження'+ + +'( ~ 35%).
Включайте псевдолокаль в dev-збірку як «qps-ploc».
Скріншоти з контекстом для перекладачів: підсвічування плейсхолдерів і довгих текстів.
Тестуйте: обрізки, переноси, переповнення, «жорстко пришиті» рядки, RTL.
9) Повідомлення, листи, шаблони
Шаблон письма і теми - на кожну локаль; розділяйте тексти і верстку.
Дати/суми в темі - форматуються по локалі.
Посилання «Налаштувати сповіщення» - завжди мовою листа.
SMS: коротко, без багатострокових лапок; UTM - без локалізації.
10) Безпека і надійність
Ніколи не інтерпретуйте переклад як HTML, використовуйте безпечні вставки.
Плейсхолдери - тільки дані, не розмітка.
Логи/метрики - безсекретні, але з локаллю для трейсингу проблем.
Фолбек при недоступності файлу перекладів - «тихий» (покажіть англійську + телеметрія).
11) Продуктивність
Чанки переказів за маршрутами/доменами; передзавантаження для частих.
Кеш CDN с `ETag`/`Cache-Control`.
Уникайте ререндерів при зміні локалі - контекст i18n з мемоізацією.
12) Специфіка iGaming
Дисклеймери та відповідальна гра: формулювання залежать від країни (18 +/21 +, органи регулювання, лінії допомоги).
KYC/AML: юридично коректні терміни (наприклад, «Джерело коштів», «Бенефіціарний власник»), варіанти відмінків/пологів.
Платіжні методи: назви локальні (PIX, Papara, SEPA) і умови (ЕТА/комісії) - строго по регіону.
Коефіцієнти та формат: 'decimal/fractional/american'- локальні пояснення і приклад.
Юридичні тексти: незмінні регіональні версії; заборона фолбека на іншу юрисдикцію.
13) Токени дизайн-системи (приклад)
json
{
"i18n": {
"fallback": ["en"],
"rtl": ["ar", "he", "fa"],
"textExpansionPct": 0.35,
"screenshotHints": true
},
"typography": {
"lineHeight": { "ui": 1.4, "dense": 1.3 },
"hyphens": "auto",
"tabularNums": true
},
"layout": {
"minLabelWidth": 96,
"gap": { "sm": 8, "md": 12, "lg": 16 }
},
"a11y": {
"ariaMirroring": true,
"altTranslate": true,
"contrastAA": true
}
}
14) Сніппети
React + i18next (ліниве завантаження, ICU):ts import i18n from 'i18next';
import ICU from 'i18next-icu';
import { initReactI18next } from 'react-i18next';
i18n.use(ICU).use(initReactI18next).init({
lng: 'uk-UA',
fallbackLng: ['ru', 'en'],
load: 'languageOnly',
interpolation: { escapeValue: false },
resources: {} // пусто — грузим лениво
});
export async function loadNamespace(ns: string, lng = i18n.language){
const mod = await import(`/i18n/${lng}/${ns}.json`);
i18n.addResourceBundle(lng, ns, mod.default, true, true);
}
ICU плуралізація (рос/укр):
json
{
"notifications": "{count, plural, one {# уведомление} few {# уведомления} many {# уведомлений} other {# уведомления}}"
}
Intl для валют/дат:
js const money = (v, c, l) => new Intl.NumberFormat(l, {style:'currency', currency:c}).format(v/100);
const rel = (v, unit, l) => new Intl.RelativeTimeFormat(l, {numeric:'auto'}).format(v, unit);
// money(250000,'EUR','de-DE') → 2.500,00 €
RTL-клас на корені:
js const rtl = new Set(['ar','he','fa']);
document.documentElement.dir = rtl.has(locale.split('-')[0])? 'rtl': 'ltr';
Псевдолокаль (dev):
js const pseudo = s => s.replace(/[aAeEiIoOuU]/g, m => ({a:'à',e:'ê',i:'ï',o:'ô',u:'û'}[m.toLowerCase()] m)).replace(/([^\s])/g,'$1\u0301');
15) Порожні/помилки/грейсфул деградації
Немає перекладу ключа: показуємо англійську + логуємо'missing _ key'.
Немає локального файла: фолбек і банер «Частина інтерфейсу англійською».
Занадто довгий текст: мультирядковий,'line-clamp'за місцем, tooltip з повним текстом.
16) Метрики та контроль якості
Coverage% по ключах/локалях (цільовий ≥ 98%).
Time-to-Translate (TTT) для нових релізів.
Bug rate L10n: візуальні обрізки, RTL-дефекти, помилкові формати.
Reading ease (суб'єктивне опитування) і NPS per locale.
Юридична валідація по регіонах (чеклист комплаенса).
17) Антипатерни
Конкатенація рядків у коді («Ви виграли» + amount + «!») - ламає граматику.
Текст у зображеннях/іконках без локальних версій.
Жорсткі ширини під англійську.
Підміна права країни мовою (використовувати'es-ES'для Мексики).
Переклад через HTML з CMS без санітайзу.
Один і той же ключ з різними сенсами в різних місцях.
18) QA-чек-лист
Рядки та ключі
- Іменовані плейсхолдери; немає конкатенації.
- ICU-плуралізація/рід де потрібно.
- Фолбек-ланцюжок працює.
Лейаут і доступність
- Запас ширини + 30-40%;'line-clamp', перенесення слів.
- Alt/aria-лейбли локалізовані.
- RTL дзеркалить іконки/навігацію; Числа читаються.
Формати
- Дати/валюти через'Intl.'; суми з мінорних одиниць.
- Адреса/телефон/ім'я - гнучкі правила по країні.
Безпека/перформанс
- Переклади не виконують HTML; XSS виключений.
- Ліниві чанки, кеш CDN, без зайвих ререндерів.
iGaming-специфіка
- Дисклеймери/18 +/лінії допомоги - по юрисдикції.
- Тексти KYC/AML юридично вивірені.
- Платіжні назви/ЕТА/комісії - локальні.
19) Документація в дизайн-системі
Розділи: i18n Tokens, Guides (ICU/Plural/RTL), Patterns (Emails/SMS/Toasts), Legal Strings per Region.
Інструменти: псевдолокаль, скріншотер екранів, звіт coverage, лінтер ключів.
Процес: глосарій, Translation Memory, контекстні скріншоти, рев'ю носієм мови.
Коротке резюме
Багатомовний UI - це системна робота на рівні архітектури, дизайну, контенту і права. Організуйте ключі і фолбеки, використовуйте ICU і'Intl', підтримайте RTL, заздалегідь проженіть псевдолокаль і забезпечте юридичну коректність регіональних формулювань. Тоді продукт буде відчуватися рідним - від коефіцієнтів і платежів до листів і довідки - в кожній країні і для кожного користувача.