10 поширених помилок i18n та як їх уникати
Дізнайтеся про найпоширені помилки інтернаціоналізації, які роблять розробники, та як їх виправити. Покращуйте якість локалізації вашого застосунку за допомогою цих найкращих практик.
i18n здається нескладною — поки ви не зрозумієте, що німецькі користувачі бачать обрізані кнопки, японські користувачі отримують уривки речень, а користувачі, що говорять арабською, стикаються з повністю зламаними макетами. Це не випадкові випадки. Це передбачувані наслідки поширених помилок, які більшість команд розробників робить, коли вперше підходить до локалізації. У цьому посібнику ми розглянемо 10 найпоширеніших помилок i18n, пояснимо, чому вони трапляються, і крок за кроком покажемо, як виправити кожну з них. Неважливо, чи будуєте ви новий застосунок або модернізуєте існуючий — уникнення цих паст заощадить вам тижні налагодження та забезпечить користувачам по всьому світу бездоганний досвід.
Помилка №1: жорстко закодовані рядки
Ключова помилка i18n — це хардкодинг рядків. Вона трапляється, коли розробники зосереджуються спочатку на тому, щоб функції працювали, і планують «поправимо пізніше». Але пізніше ніколи не приходить, і раптом ти маєш тисячі рядків, розкиданих по сотням файлів.
['Встановіть i18n-фреймворк до того, як напишете перший рядок UI', 'Використовуйте плагін Linter, щоб виявляти хардкодовані рядки в шаблонах та компонентах', 'Зберігайте ключі локалізації описовими й організуйте їх за функцією або сторінкою']
Налаштуйте i18n-фреймворк перед написанням першого рядка UI-коду.
Використовуйте плагін для лінтера, щоб виявити вбудовані рядки в шаблонах та компонентах.
Забезпечте описові ключі перекладу та організуйте їх за функцією або сторінкою.
Типовий сценарій
Розробник пише назву кнопки безпосередньо у JSX: <button>Submit Order</button>.
Програма випущена англійською та працює бездоганно. Шість місяців потому компанія розширюється до Німеччини.
Команда локалізації виявляє понад 2 000 хардкодованих рядків. Оновлення триватиме 3 тижні та спричинить 47 помилок.
Чому це проблема
У розвиненій кодовій базі хардкодовані рядки можуть досягати тисяч. Їх витягнення згодом потребує змінити кожен файл, повторно тестувати кожен компонент і ризикувати регресіями всюди.
Хардкодовані рядки безпосередньо в тій частині коду, шаблонах або компонентах. їх не можна витягти, перекласти або замінити під час виконання без зміни самого коду.
Користувачі в локалях, які не використовують англійську, бачать елементи UI, що не перекладені, змішані з перекладеним вмістом — хаотичний та непрофесійний вигляд.
Як виправити це
Перенесіть усі рядки, які бачать користувачі, у файли ресурсів із самого початку.
Переконайтеся, що ви створили фреймворк перекладу (наприклад, next-intl, react-i18next, vue-i18n) перед написанням першого компонента.
Створіть структуру файлів ресурсів (наприклад, messages/de.json) і посилайтесь на всі рядки за допомогою ключів перекладу, таких як t('checkout.submitButton').
Додайте правило Linting або Pre-Commit Hook, які позначає неякісний string-literal у компонентах UI.
Помилка №10: Перекладати все дослівно
Не всі матеріали повинні бути перекладені. Примітні назви брендів, назви юридичних осіб, технічні терміни та деякі назви продуктів повинні залишатися в оригінальній мові. Надмірний переклад може викликати правові проблеми, невідповідність бренду та плутаність користувачів.
["Підтримуйте словник 'не перекладати' і діліться ним з усіма перекладачами.", 'Використовуйте заблоковані сегменти або окремі простори імен для назв брендів та юридичних термінів', 'Завжди надавайте нотатки з контекстом для двозначних рядків, щоб запобігати неправильному перекладу.']
Підтримуйте глосарій 'не перекладати' і поділіться ним із усіма перекладачами.
Використовуйте заблоковані сегменти або окремі простори імен для марок і правових термінів.
Завжди надавайте контекстні примітки для багатозначних рядків, щоб запобігти помилковим перекладам.
Типова ситуація
Файл перекладу містить назву компанії 'CloudForge Inc.' та технічний термін 'OAuth 2.0 Token' як звичайні рядки для перекладу.
Іспанський перекладач перекладає 'CloudForge' як 'ForjaNube' і 'OAuth 2.0 Token' як 'ficha OAuth 2.0'.
Результат: користувачі не знаходять компанію за її реальним ім'ям, а розробники, які читають іспанську документацію, заплутаються через невідомі перекладені технічні терміни.
Чому це проблема
Один неправильно перекладений бренд може зробити контракт недійсним. Виправлення перевищених перекладів вимагає перевірки кожного рядка на кожній мові — завдання на кілька тижнів.
Якщо всі рядки надано для перекладу без контексту, перекладачі можуть перекласти назви брендів ('Apple' → 'Apfel'), правові терміни ('GmbH' → 'LLC') або технічні позначення, які повинні залишитися англійською.
Користувачі не знаходять продукти під відомим брендом, правові документи посилаються на неправильну компанію, а технічна документація стає незрозумілою, якщо такі терміни, як 'API Endpoint', перекладаються.
Як виправити це
Чітко позначайте не перекладний вміст та надавайте контекстні нотатки перекладачам.
Створіть словник 'не перекладати', який перелічує всі назви брендів, назви продуктів, юридичні особи та спеціальні терміни, які повинні залишитися без змін.
Використовуйте окремий простір імен або спеціальні ключі для не перекладного вмісту. Багато інструментів i18n підтримують захищені сегменти, які перекладачі не можуть редагувати.
Додайте коментарі перекладачам/описи до файлів перекладу, які пояснюють контекст: 'Це назва бренду — не перекладати' або 'Термін — залишити англійською'.
Помилка №2: конкатенація рядків
Збирання речень з фрагментів здається логічним англійською, але не працює в інших мовах. Порядок слів, граматика та структура речення радикально відрізняються між мовами, через що з'єднані рядки не можна перекласти.
['Ніколи не з'єднуйте речення за допомогою перекладених фрагментів', 'Використовуйте іменовані заповнювачі ('{name}') замість позиційних ({0}) для ясності', 'Надавайте контекстні коментарі для перекладачів, щоб пояснити, що містить кожен заповнювач']
Ніколи не будуй речення, з'єднуючи перекладені фрагменти.
Використовуйте іменовані заповнювачі ('{name}') замість позиційних ({0}) для ясності
Надайте контекстні нотатки для перекладачів, які пояснюють, що містить кожен placeholder.
Типова ситуація
Розробник пише: 'You have ' + count + ' items in your ' + cartType + ' cart' — працює ідеально англійською.
Німецький перекладач отримує три окремі фрагменти і не може сформувати граматично правильне речення, оскільки порядок слів має змінитися.
Результат: Німецькі користувачі бачать 'Sie haben 5 Artikel in Ihrem Warenkorb Standard' — незграбно та не професійно.
Чому це проблема
Кожен з'єднаний рядок — це тикаюча бомба. За 20 мов і 50 з'єднаних рядків у вас буде 1 000 потенційних граматичних помилок, які потрібно виправити вручну.
"Вітати ' + ім'я користувача + ', у вас ' + count + ' нових повідомлень" з'єднання рядків вимагає певного порядку слів. Перекладачі отримують фрагменти без контексту, які вони не можуть переставляти.
Користувачі бачать граматично некоректні речення. У німецькій мові дієслово часто стоїть наприкінці. У арабській мові вся структура навпаки. Результат читається як нісенітниця.
Як виправити
Використовуйте ICU MessageFormat, який підтримує всі правила множини CLDR з коробки.
Замініть з'єднання на один ключ повідомлення з заповнювачами: 'cart.summary': 'У вас {count} товарів у вашій '{cartType}'-корзині'.
Перекладачі надають усі потрібні форми множини для своїх мов. Польська: '{count, plural, one {# plik} few {# pliki} many {# plików} other {# pliku}}'.
Перекладачі тепер можуть вільно переставляти: 'У вашій '{cartType}'-корзині знаходиться {count} товарів' — граматично правильна німецька.
Помилка №3: ігнорування множини
Англійська має дві форми множини: однина та множина. Розробники часто вважають, що всі мови працюють так само. Вони ні. Польська має 4 форми, арабська — 6, і навіть такі мови як французька мають нульову форму по-іншому, ніж англійська.
['Завжди використовуйте ICU MessageFormat або еквівалентну бібліотеку для форм множини', 'Ніколи не пишіть власну логіку множини — довіряйте правилам CLDR', 'Тестуйте множину з такими значеннями як 0, 1, 2, 5, 21 та 100, щоб охопити всі категорії']
Завжди використовуйте ICU MessageFormat або еквівалентну бібліотеку для кількісного вмісту.
Ніколи не пишіть власну логіку множини — довіряйте правилам CLDR.
Перевіряйте форму множини за значеннями, такими як 0, 1, 2, 5, 21 та 100, щоб охопити всі категорії.
Типова ситуація
Розробник пише: count + (count === 1 ? ' Datei' : ' Dateien') — коректно обробляє німецьку.
Перекладач з польської потребує 4 форм: 1 plik, 2-4 pliki, 5-21 plików, 22-24 pliki. Простітернарне вираз не може передати.
Результат: польські користувачі бачать '5 pliki' (некоректна форма) замість '5 plików' (правильна форма), і застосунок виглядає несправним.
Чому це проблема
Кожному злічуваному іменнику у вашому застосунку потрібне управління формами множини. За 50 таких рядків та 20 мов — 1 000 правил множини, які неможливо керувати вручну.
Proste перевірки if/else (count === 1 ? 'Datei' : 'Dateien') обробляють лише німецьку й англійську. CLDR визначає до 6 категорій множини: zero, one, two, few, many та other. Кожна мова використовує іншу підмножину.
Користувачі бачать неправильні форми множини, наприклад '1 повідомлення' або повністю хибні форми. У формальних контекстах це руйнує довіру.
Як виправити
Використовуйте ICU MessageFormat, який підтримує всі правила множини CLDR з коробки.
Визначте повідомлення за допомогою ICU-синтаксису: 'fileCount': '{count, plural, one {# Datei} other {# Dateien}}'.
Перекладачі надають усі потрібні форми множини для своєї мови. Польська: '{count, plural, one {# plik} few {# pliki} many {# plików} other {# pliku}}'.
Бібліотека i18n під час виконання автоматично обирає правильну форму відповідно до правил CLDR активної локалі.
Помилка №4: Жорстко задані ширини елементів інтерфейсу
Дизайнери створюють піксельно точні розкладки англійською мовою, а розробники реалізують їх із фіксованою шириною. Але перекладений текст може бути значно довший або коротший. Німецький текст приблизно на 30% довший за англійський, а китайський текст може бути на 50% коротший.
['Ніколи не використовуйте фіксовані піксельні ширини для елементів із перекладним текстом', 'Плануйте 40% розширення тексту як базову лінію — деякі мови розширюються ще більше', 'Використовуйте CSS Flexbox або Grid для макетів, що адаптуються до різних довжин вмісту']
Ніколи не використовуйте фіксовану ширину в пікселях для елементів з перекладним текстом.
Встановіть базовий рівень розширення тексту на 40% — деякі мови розширюються ще більше.
Використовуйте CSS Flexbox або Grid для макетів, що адаптуються до різної довжини вмісту.
Типова ситуація
Дизайнер створює навігаційну панель з 5 кнопками, кожна шириною точно 100 px — виглядає чудово англійською.
Німецьке перекладення: 'Settings' стає 'Einstellungen' (13 символів порівняно з 8), 'Submit' стає 'Absenden' (8 проти 6). Навігаційна панель виходить за межі.
Результат: на мобільних пристроях кнопки зводяться одна на одну або текст обрізається, що робить навігацію для німецьких користувачів непридатною.
Чому це проблема
Кожен елемент із фіксованою шириною — потенційна точка розриву. Типовий додаток містить сотні кнопок, міток та карток, які повинні витримувати розширення тексту.
Контейнер із фіксованою шириною (width: 120px) та кнопки з фіксованим розміром обрізаються або виходять за межі, коли текст розтягується. CSS overflow: hidden тихо приховує вміст, тоді як overflow: visible руйнує макет.
Користувачі бачать обрізані етикетки, наприклад 'Einstellu...' замість 'Einstellungen', або кнопки перекривають сусідні елементи. Критичні дії стають нечитаємими або неклікованими.
Як виправити це
Створюйте та впроваджуйте гнучкі макети, які адаптуються до довжини вмісту для всіх локалей.
Замініть фіксовані ширини на min-width, max-width та гнучкі розкладки. Використовуйте CSS Grid або Flexbox, щоб динамічно розподіляти простір.
Встановіть переноси для текстових контейнерів: використовуйте overflow-wrap: break-word і уникайте white-space: nowrap для перекладного контенту.
Перевірте інтерфейс за допомогою псевдолокалізації, яка подовжує усі рядки на 40%, щоб змоделювати найгірший випадок — ще до надсилання рядків перекладачам.
Помилка №5: форматування дат і чисел
Дані та числа здаються універсальними. Але 01/02/2025 означає 2 січня в США та 1 лютого в Європі. Коми та крапки змінюють значення чисел: 1,000.50 (США) проти 1.000,50 (Німеччина). Неправильна практика призводить до плутанини, помилок у даних та втрати довіри.
['Ніколи не форматувати дані або числа вручну за допомогою рядкових шаблонів — завжди використовуйте Intl API', 'Зберігайте всі дані у форматі ISO 8601 та валюти всередині як найменшу одиницю (цент)', 'Перевіряйте локалі, що використовують різні десяткові роздільники, різні порядок дати та різні календарні системи']
Ніколи не форматувати дані або числа вручну за допомогою рядкових шаблонів — завжди використовуйте Intl-APIs.
Зберігайте всі дані у ISO 8601, а валюти — в найменшій одиниці (цент) всередині.
Перевіряйте з локалями, що використовують різні десяткові роздільники, порядок дат та системи календаря.
Типова ситуація
Розробник форматують дату як MM/DD/YYYY і ціну як $1,234.50 — правильно для користувачів США.
Німецький користувач бачить 03/04/2025 і розуміє це як 3 квітня замість 4 березня — пропущені зустрічі або неправильні бронювання.
Результат: Користувач бронює квиток на рейс на неправильну дату і сумнівається у форматі ціни. Тікети підтримки зростають на 15% на німецькому ринку.
Чому це проблема
Форматування дат і чисел впливає на кожне відображення даних у вашому застосунку: таблиці, діаграми, форми, рахунки, звіти. Глобальне рішення охоплює сотні випадків.
Хардкодовані рядки формату, такі як toLocaleDateString('en-US') або ручне форматування за допомогою шаблонних літералів, ігнорують фактичну локаль користувача. Навіть якщо локаль правильна, неправильна система календаря (Gregorian vs Hijri) викликає проблеми.
Користувачі читають дані неправильно і вводять дані у неправильному форматі. Європейський користувач, який бачить 03/04/2025, може зрозуміти це як 3 квітня замість 4 березня — пропущені зустрічі або неправильні бронювання.
Як виправити це
Використовуйте вбудований Intl API або локалізовано-орієнтовану бібліотеку форматування для дат, часу, чисел і валют.
Замініть ручне форматування за допомогою Intl.DateTimeFormat(locale) для дат та Intl.NumberFormat(locale, { style: 'currency', currency }) для цін.
Зберігайте дані всередині у форматі ISO 8601 (YYYY-MM-DD) і форматувати їх лише для відображення відповідно до локалі користувача.
Перевірте з використанням щонайменше 5 різних локалей: en-US, de-DE, ja-JP, ar-SA та zh-CN, щоб охопити основні варіанти форматування.
Помилка №6: забуто RTL-мови
Умови з правою-на-віською (RTL) як арабська, іврит та фарсі використовуються більш ніж 500 мільйонами людей. Проте більшість застосунків розробляються лише для макета зліва-направо (LTR). Підтримка RTL — це не лише віддзеркалення тексту — інтерфейс повинен бути віддзеркалений.
['З самого початку використовуйте лише логічні CSS-властивості (inline-start/end, block-start/end)', 'Кожного спринт-огляду тестуйте свій застосунок у RTL, використовуючи dir=rtl на HTML-елементі', 'Створіть контрольний список RTL-тестування для навігації, іконок, форм та елементів прогресу']
Використовуйте з першого дня лише логічні CSS-властивості (inline-start/end, block-start/end).
Перевіряйте застосунок з режимом RTL на елементі HTML під час кожного спринт-огляду.
Створіть перевірочний список RTL для навігації, значків, форм та індикаторів прогресу.
Типовий сценарій
Розробник використовує margin-left: 16px та text-align: left по всій програмі — стандартна практика LTR.
Додаток запускається в Саудівській Аравії. Кнопки повернення показують вперед, бічні панелі з'являються з неправильної сторони, а чисельні дані вирівняні неправильно.
Результат: арабські користувачі залишають застосунок через 30 секунд. Команді знадобиться 4 тижні термінового CSS-рефакторингу, щоб виправити проблему.
Чому це проблема
Підтримка RTL охоплює кожен компонент вашого застосунку. Додати RTL після початку зазвичай вимагає переписати 30-50% CSS-правил і перевірити кожну піктограму та макет.
Властивості CSS, як margin-left, padding-right, text-align: left та float: left, жорстко задають напрямок. Ікони з орієнтацією ( стрілки, індикатори прогресу) вказують у неправильному напрямку. Навіть значення border-radius потрібно віддзеркалити.
Користувачі з арабською мовою бачать навігацію в неправильному куті, смуга прогресу рухається назад, а текст стикається з елементами UI. Додаток здається чужим і не зручним.
Як виправити це
Використовуйте логічні CSS-властивості та тестуйте RTL-розмітку з самого початку.
Замініть всі фізичні CSS-властивості на їх логічні еквіваленти: margin-left → margin-inline-start, padding-right → padding-inline-end, text-align: left → text-align: start.
Встановіть атрибут dir на кореневому HTML-елементі відповідно до активної локалі. Використовуйте CSS-псевдоклас :dir(rtl) для переоприділу RTL.
Перевірте всі піктограми на напрямок: замініть орієнтовані піктограми на віддзеркалені версії або використайте CSS transform: scaleX(-1) для контекстів RTL.
Помилка №7: зображення з текстом
Текст на зображеннях — чи то у головних банерах, кнопках, інфографіці чи знімках екрана — це локалізаційний кошмар. Кожне зображення з текстом має бути створене заново для кожної мови, що збільшує витрати на дизайн і затримує релізи.
['Ніколи не вставляйте перекладний текст безпосередньо у растрові зображення (PNG, JPG)', 'Використовуйте CSS-оверлеї з текстом на фонових зображеннях для головних банерів та CTA', 'Автоматизуйте генерацію знімків екрана для записів App Store та маркетингових сторінок']
Ніколи не вставляйте перекладний текст безпосередньо в растрові зображення (PNG, JPG).
Використовуйте CSS-оверлеї тексту на фонових зображеннях для героїчного банера та закликів до дії.
Автоматизуйте генерацію скріншотів для списків в App Store та маркетингових сторінок.
Типова ситуація
Дизайнер створює промо-банер із текстом 'Start Your Free Trial', який безпосередньо вставлений у зображення.
Команда локалізації перекладає всі рядки UI, але банер на німецькій версії все ще відображає англійський текст.
Результат: Німецька лендінг-сторінка має англійський банер, що збиває з пантелику. Створення локалізованих банерів для 15 мов займе 3 дні дизайну та затримає запуск.
Чому це проблема
Типова маркетинг-сторінка має 5–10 зображень з текстом. Для 15 мов це 75–150 варіантів зображень, які потрібно створювати, підтримувати та оновлювати при кожній зміні дизайну.
Текст, вбудований у зображення (PNG, JPG, SVG з вбудованим текстом) не може бути витягнутий інструментами перекладу. Кожна локалізована версія вимагає, щоб дизайнер вручну редагував вихідний файл, експортував та завантажив його.
Користувачі бачать зображення з текстом іншою мовою або, ще гірше, поєднання локалізованого інтерфейсу з неперекладеними зображеннями. Це виглядає неузгоджено і підриває довіру до бренду.
Як виправити це
Розділіть текст від зображень за допомогою накладень CSS, SVG із текстовими елементами, які можна перекладати, або динамічну генерацію зображень
Використайте CSS, щоб розмістити локалізований текст поверх зображення: встановіть шар тексту з використанням абсолютного позиціонування над контейнером зображення.
Для інфографіки або діаграм використовуйте SVG із елементами <text>, які посилаються на ключі перекладу, замість вставлення сирих рядків.
Для знімків екрана програми в маркетингових матеріалах автоматизуйте створення знімків екрана за допомогою інструментів, як Fastlane (Mobile) або Playwright (Web), які зроблять знімки для кожної локалі.
Помилка #8: Відсутні переклади не обробляються
Переклади під час розробки завжди неповні. Нові функції додають рядки швидше, ніж перекладачі можуть їх перекласти. Без правильної системи fallback відсутні переклади можуть призвести до збоїв, порожніх елементів UI або відображення користувачам сирих ключів перекладу.
['Завжди переконайтесь, що в налаштуваннях i18n є хоча б одна мова за замовчуванням (fallback)', 'Записуйте відсутні ключі перекладу у вашу систему моніторингу для відстеження', 'Встановіть мінімальний рівень покриття перекладу, перш ніж Locale буде онлайн']
Завжди налаштовуйте хоча б одну мову за замовчуванням (fallback) у вашій i18n-конфігурації.
Записуйте відсутні ключі перекладу у вашу систему моніторингу для відстеження.
Встановіть мінімальний рівень покриття перекладів, перш ніж локаль стане активною.
Типова ситуація
Розробник додає новий розділ 'Premium Features' із 15 новими ключами перекладу. Англійська версія випускається негайно.
Французькі переклади ще не готові. Французька сторінка відображає сирі ключі: 'premium.feature1.title', 'premium.feature1.description'.
Результат: користувачі французькою зіштовхуються з не працюючою сторінкою, повною назвою ключів розробника. Команда підтримки отримує багато звітів про помилки.
Чому це проблема?
Чим більше ваш застосунок, тим більша різниця між англійськими рядками та перекладами на інші мови. Програма з 100 мовами та 2000 рядками може в будь-який момент мати понад 10 000 відсутніх перекладів.
Без логіки fallback відсутні коди перекладу можуть повертати undefined, null або сирий рядок ключа (наприклад 'checkout.confirmButton'). Шаблонізатори можуть викидати помилки, сторінка може впасти або взагалі нічого не відобразити.
Користувачі бачать зламаний інтерфейс: порожні кнопки, відсутні мітки або заплутані рядки на кшталт 'nav.settings.title' замість реального тексту. Це збиває з пантелику і не професійно.
Як виправити це
Налаштуйте надійну ланцюг fallback та відстежуйте охоплення перекладів для всіх локалей.
Налаштуйте мильну ланцюг fallback у вашій i18n-конфігурації: відсутні ключі французькою (fr) автоматично переходять на англійську (en).
Додайте обробник відсутніх ключів (Missing-Key-Handler), який реєструє не перекладені ключі у вашу систему моніторингу (наприклад, Sentry, Datadog) без порушення користувацького досвіду.
Створіть панель покриття перекладу, що відстежує рівень заповнення для кожної локалі та блокує релізи, якщо покриття падає нижче порогового значення (наприклад 95%).
Помилка №9: проблеми з кодуванням символів
Проблеми кодування символів — це тихий вбивця локалізації. Усе виглядає добре в англійській та європейських мовах, але коли додаються китайська, японська, корейська, арабська або емодзі, з'являються спотворені символи (Mojibake). Такі баги зазвичай складно виявити.
['Використовуйте кодкування UTF-8 повсюдно — вихідні файли, база даних, відповіді API та HTML-мета-теги', 'Використовуйте utf8mb4 в MySQL (не лише utf8), щоб підтримати повний діапазон Юнікоду включаючи Emoji', 'Тестуйте з реальним вмістом у CJK, арабській та Emoji, щоб виявити проблеми з кодуванням раніше']
Використовуйте кодування UTF-8 повсюдно — вихідні файли, база даних, відповіді API та HTML-мета-теги
Використовуйте utf8mb4 у MySQL (не utf8), щоб підтримати повний діапазон Unicode включно з Emoji.
Тестуйте з реальним вмістом у CJK, арабською та емодзі, щоб рано виявити проблеми кодування.
Типова ситуація
Розробник налаштовує базу даних MySQL з латин1-каталогою (старий стандарт). Код програми використовує UTF-8.
Користувачі з Японії реєструються використовуючи свої реальні імена. База даних зберігає '田中太郎' як пошкоджені байти.
Результат: профіль користувача показує спотворений текст. Що ще гірше: пошук і сортування зламано для всіх імен CJK, що стосується тисяч користувачів.
Чому це проблема
Проблеми з кодуванням поширюються по всьому стеку. Неправильна настройка порівняння (collation) бази даних може пошкодити мільйони записів — виправлення вимагатиме дорогі міграції даних.
Невідповідність кодування протягом стека — UTF-8 у файлах джерел, Latin-1 у базі даних та Windows-1252 у відповідях API — знищує багатобайтові символи. Одна неправильно налаштована прошивка може перетворити '日本語' на '????' або '日本èª'.
Користувачі бачать спотворені тексти, знаки запитання або порожні поля там, де має бути їх мова. У найгіршому випадку введення у формі може бути пошкоджене в базі даних.
Як виправити це
Зобов'язати використання кодування UTF-8 послідовно на кожному рівні стеку застосунку.
Встановіть кодування UTF-8 для всіх вихідних файлів (налаштуйте ваш редактор та .editorconfig). Додайте <meta charset='UTF-8'> у ваш HTML та 'Content-Type: application/json; charset=utf-8' у відповідях API.
Налаштуйте базу даних на utf8mb4 (не лише utf8, що в MySQL є трьохбайтовим підмножиною). Встановіть зіткнення підключення на utf8mb4_unicode_ci.
Виберіть шрифти, що охоплюють ваші цільові системи письма: латиниця, кирилиця, CJK, арабська, Деванагарі. Використовуйте системні шрифти або Google Fonts з підмножинами мов для оптимального завантаження.
Перевірка вашої реалізації i18n
Тест подовження довжини
Збільшіть довжину всіх перекладених рядків на 30-40%, щоб змоделювати розширення тексту, що трапляється у мовах з багатьма словами, як німецька, фінська або грецька. Це охоплює контейнери з фіксованою шириною, обрізані мітки та переповнені кнопки, ще до початку перекладу. Багато інструментів псевдоблокалізації мають це вбудованою функцією.
"Senden" → "Ṡééééñðéñ_éxpáñðéð" (на 40% довший)
Псевдолокалізація
Псевдо-локалізація замінює кожен символ акцентованим еквівалентом (наприклад, 'a' → 'á') і обгортає рядки маркуваннями на зразок [!! та !!]. Це миттєво показує, які рядки захардкодені, а які з системи перекладу. Запустіть псевдо-локалізацію як частину вашого CI-пайплайна, щоб автоматично вловлювати регресії.
Кожен текст на екрані, який не обмежений позначеннями [!! !!], є хардкодованим і повинен бути винесений. Цей тест виявляє приблизно 95% пропущених рядків за менш ніж хвилину.
"Надіслати повідомлення" → "[!! Ñáçḥŕíçḥṫ ṡéñðéñ !!]"
Тест розмітки RTL
Навіть без арабських або івритських перекладів ви можете тестувати RTL-розклад, додавши dir='rtl' до кореневого елемента HTML. Це одразу виявляє помилки CSS за напрямком: неправильно вирівняні піктограми, відступи на неправильному боці, зламану навігацію та неправильно відсортовані гнучкі елементи. Зробіть це стандартною перевіркою у кожному огляді спринтів — перемикання займає 10 секунд і виявляє проблеми, які інакше потребували б тижнів виправлень у Production.
Перелік перевірок i18n
['Усі рядки, видимі користувачеві, винесено до файлів ресурсів', 'Не використовується зчеплення рядків для створення речень', 'Правила множин з ICU MessageFormat або еквівалента реалізовані', 'Форматування дати, часу та чисел із використанням локалізованих API', 'RTL-розмітка з арабським або єврейським вмістом протестована', 'Гнучкий інтерфейс без фіксованої ширини для елементів з текстом', 'Налаштована мова за замовчуванням (fallback) та протестована за відсутності ключів', 'Кодування UTF-8 узгоджене по всіх файлах і базах даних', 'Метадані App Store та Play Store для кожного ринку локалізовано', 'Знімки екрана та маркетингові матеріали для кожної мови оновлено']