Back to Guides
Руководство

10 распространённых ошибок i18n и как их избежать

Узнайте о самых распространённых ошибках интернационализации, которые допускают разработчики, и как их исправлять. Улучшите качество локализации вашего приложения с помощью лучших практик.

5 Минимальное время чтения
Автор: shipglobal.dev
#i18n#developer#user experience#best practices#internationalization#common mistakes

Интернационализация (i18n) кажется простой — пока вы не обнаружите, что немецкие пользователи видят обрезанные кнопки, японские — обрезанные фрагменты предложений, а арабоязычные пользователи сталкиваются с полностью испорченными макетами. Это не исключения. Это предсказуемые последствия типичных ошибок, которые большинство команд разработки допускают, когда впервые приступают к локализации. В этом руководстве мы рассмотрим 10 самых частых i18n-ошибок, подробно объясним, почему они происходят, и шаг за шагом покажем, как исправить каждую. Независимо от того, строите ли вы новое приложение или модернизируете существующее — избегание этих ловушек сэкономит вам недели на отладке.

Ошибка №1: Жестко закодированные строки

Хардкодированные строки — базовая ошибка i18n. Она возникает, потому что разработчики сначала сосредотачиваются на том, чтобы сделать фичи рабочими, и планируют «разобраться позже». Но позже обычно не наступает, и внезапно у вас оказывается тысячи строк, разбросанных по сотням файлов.

['Настройте ваше i18n-рамки до написания первой строки UI-кода', 'Используйте плагин линтера, чтобы находить хардкодированные строки в шаблонах и компонентах', 'Держите ключи перевода описательными и организуйте по функциям или страницам']

Настройте свой i18n-фреймворк, прежде чем писать первую строку UI-кода.

Используйте линтер-плагин, чтобы обнаруживать жестко закодированные строки в шаблонах и компонентах.

Делайте ключи переводов описательными и organizujte ih po funkciji или strani.

Типичный сценарий

1

Разработчик прямо в JSX пишет подпись кнопки: <button>Submit Order</button>.

2

Приложение выпускается на английском, всё работает. Спустя шесть месяцев компания выходит на рынок Германии.

3

Команда локализации обнаруживает 2.000+ хардкодированных строк. Обновление занимает 3 недели и вызывает 47 ошибок.

Почему это проблема

В зрелой кодовой базе жестко закодированные строки могут достигать тысяч. Последующая их экстракция требует изменения каждой файлa, повторного тестирования каждой компоненты и риск возникновения регрессий повсеместно.

Хардкодированные строки встроены прямо в исходный код, шаблоны или компоненты. Их нельзя извлечь, перевести или заменить во время выполнения без изменений самого кода.

Пользователи в локализациях, не являющихся английскими, видят элементы интерфейса, не переведенные, смешанные с переведенным содержимым — хаотичное и непрофессиональное впечатление.

Как исправить

Перенесите все текстовые элементы, видимые пользователю, из самого начала в файлы ресурсов.

1

Настройте фреймворк перевода (например, next-intl, react-i18next, vue-i18n) до написания вашей первой компоненты.

2

Создайте структуру файлов ресурсов (например, messages/de.json) и обращайтесь ко всем строкам через ключи перевода, например t('checkout.submitButton').

3

Добавьте правило линтинга или хуk Pre-Commit, который помечает сырые строковые литералы в UI-компонентах.

Ошибка №10: Переводить всё буквально

Не весь контент следует переводить. Названия брендов, имена юридических лиц, технические термины и некоторые названия продуктов должны оставаться на исходном языке. Чрезмерный перевод может вызвать юридические проблемы, несоответствия бренда и путаницу у пользователей.

Создайте глоссарий не переводить и поделитесь им со всеми переводчиками. Используйте заблокированные сегменты или отдельные пространства имён для марок и юридических терминов. Всегда предоставляйте примечания к контексту для неоднозначных строк, чтобы предотвратить ошибки перевода.

Ведите глоссарий 'не переводить' и делитесь им со всеми переводчиками.

Используйте заблокированные сегменты или отдельные пространства имен для брендовых и правовых терминов.

Всегда предоставляйте контекстные заметки для неоднозначных строк, чтобы предотвратить ошибки перевода.

Типичный сценарий

1

Файл перевода содержит имя компании 'CloudForge Inc.' и технический термин 'OAuth 2.0 Token' как обычные переводимые строки.

2

Испанский переводчик перевёл 'CloudForge' как 'ForjaNube' и 'OAuth 2.0 Token' как 'ficha OAuth 2.0'.

3

Результат: пользователи не найдут компанию под её настоящим названием, а разработчики, читающие испанскую документацию, будут сбиты с толку незнакомыми переведёнными техническими терминами.

Почему это проблема

Один неверно переведённый бренд может сделать договор недействительным. Исправление таких переводов требует проверки каждого строкового элемента на каждом языке — задача занимает несколько недель.

Если все строки отправлять на перевод без контекста, переводчики могут перевести названия брендов ('Apple' → 'Apfel'), правовые термины ('GmbH' → 'LLC') или технические обозначения, которые должны оставаться на английском.

Пользователи найдут продукты не под своим известным брендом, юридические документы будут ссылаться на неверную компанию, и техническая документация станет непонятной, если такие термины, как 'API Endpoint', переведены.

Так исправить это

Чётко помечайте непереводимые элементы и предоставляйте переводчикам пояснения к контексту.

1

Создайте глоссарий не переводить, который перечисляет все названия брендов, названия продуктов, юридические лица и специализированные термины, которые должны оставаться без изменений.

2

Используйте отдельное пространство имён или специальные ключи для не переводимого контента. Многие i18n-инструменты поддерживают заблокированные сегменты, которые переводчики не могут редактировать.

3

Добавьте комментарии и описания для файлов перевода, которые объясняют контекст: это имя бренда — не переводить или термин — оставить на английском.

Ошибка №2: Конкатенация строк

Склеивание фрагментов в целые предложения выглядит естественно на английском, но в других языках это не работает. Порядок слов, грамматика и структура предложений существенно различаются между языками, поэтому связанные строки невозможно перевести.

['Никогда не соединяй предложения через конкатенацию переведенных фрагментов', 'Используй именованные плейсхолдеры ('{name}') вместо позиционных ({0}) для ясности', 'Обеспечь комментарии с контекстом для переводчиков, объясняющие, что содержит каждый плейсхолдер']

Никогда не создавайте предложения путем конкатенации переведённых фрагментов.

Используй именованные плейсхолдеры ('{name}') вместо позиционных ({0}) для ясности

Обеспечьте переводчикам контекстные комментарии, объясняющие, что содержит каждый заполнитель.

Типичный сценарий

1

Разработчик пишет: 'You have ' + count + ' items in your ' + cartType + ' cart' — работает идеально на английском.

2

Немецкий переводчик получает три отдельных фрагмента и не может составить грамматически корректное предложение, потому что порядок слов нужно менять.

3

Результат: немецкие пользователи видят 'Sie haben 5 Artikel in Ihrem Warenkorb Standard' — неровно и непрофессионально.

Почему это проблема

Каждая связанная строка — это тикающая бомба. При 20 языках и 50 связанных строках у вас будет 1 000 потенциальных грамматических ошибок, которые нужно исправлять вручную.

Конкатенация строк, как 'Willkommen ' + userName + ', du hast ' + count + ' neue Nachrichten', требует фиксированного порядка слов. Переводчики получают фрагменты без контекста, которые они не могут переставить.

Пользователи видят грамматически неверные предложения. В немецком языке глагол часто стоит в конце. В арабском языке вся структура развёрнута. Результат читается как бессмыслица.

Как это исправить

Используйте параметризованные сообщения с именованными заполнителями, чтобы переводчики могли полностью переставлять предложение.

1

Замените конкатенацию одним ключом сообщения с плейсхолдерами: 'cart.summary': 'У вас {count} товаров в вашей корзине '{cartType}''.

2

Передавайте переменные как параметры в вашу функцию перевода: t('cart.summary', { count: 5, cartType: 'Premium' }).

3

Переводчики теперь могут свободно переставлять: 'В вашей корзине '{cartType}' находятся {count} товаров' — грамматически правильный немецкий.

Ошибка №3: Игнорирование множественного числа

У английского языка две формы числа: единственное и множественное. Разработчики часто думают, что все языки работают одинаково. Но это не так. Польский имеет 4 формы, арабский — 6, а даже такие языки, как француzский обрабатывают ноль иначе, чем английский.

['Используйте всегда ICU MessageFormat или эквивалентную библиотеку для форм множественного числа', 'Никогда не пишите собственную логику множественного числа — полагайтесь на правила CLDR', 'Тестируйте формы множественного числа на значениях 0, 1, 2, 5, 21 и 100, чтобы охватить все категории']

Всегда используйте ICU MessageFormat или эквивалентную библиотеку для форм множественного числа.

Никогда не создавайте собственную логику множественного числа — полагайтесь на правила CLDR.

Проверьте формы множественного числа на значениях 0, 1, 2, 5, 21 и 100, чтобы охватить все категории.

Типичный сценарий

1

Разработчик пишет: count + (count === 1 ? ' Datei' : ' Dateien') — корректная обработка немецкого.

2

Польский переводчик требует 4 формы: 1 plik, 2-4 pliki, 5-21 plików, 22-24 pliki. Простой тернарный оператор не может это выразить.

3

Результат: польские пользователи видят '5 pliki' (неправильная форма) вместо '5 plików' (правильная форма), и приложение выглядит сломанным.

Почему это проблема

Каждое счетное существительное в вашем приложении требует обработки множественного числа. При 50 таких строках и 20 языках это 1 000 правил множественного числа — невозможно вручную поддерживать.

Простые проверки if/else (count === 1 ? 'Datei' : 'Dateien') охватывают только немецкий и английский. CLDR определяет до 6 категорий множественного числа: zero, one, two, few, many и other. Для каждого языка существует своя подмножество.

Пользователи видят грамматически неправильные тексты, например '1 Nachrichten' или полностью неверные формы множественного числа. В формальных контекстах это подрывает доверие.

Как это исправить

Используйте ICU MessageFormat, который из коробки поддерживает все правила множества CLDR.

1

Определите сообщения с синтаксисом ICU: 'fileCount': '{count, plural, one {# файл} few {# файла} many {# файлов} other {# файла}}'.

2

Переводчики предоставляют все необходимые формы множественного числа для своего языка. Польский: '{count, plural, one {# файл} few {# файла} many {# файлов} other {# файла}}'.

3

Ваша i18n-библиотека автоматически во время выполнения выбирает правильную форму на основе правил CLDR активной локали.

Ошибка №4: Фиксированные ширины элементов UI

Дизайнеры создают пиксель‑точные макеты на английском языке, а разработчики реализуют их с помощью фиксированных ширин. Но переведённый текст может быть значительно длиннее или короче. Немецкий текст примерно на 30% длиннее английского, в то время как китайский текст может быть на 50% короче.

['Никогда не используйте фиксированные пиксели для элементов с переводимым текстом', 'Устанавливайте базовую линию на увеличение текста на 40% — некоторые языки могут увеличиться ещё больше', 'Используйте CSS Flexbox или Grid для макетов, которые адаптируются к различной длине содержания']

Никогда не используйте фиксированную ширину в пикселях для элементов с переводимым текстом.

Планируйте базовое увеличение текста на 40% — некоторые языки расширяются ещё больше.

Используйте CSS Flexbox или Grid для макетов, адаптирующихся к различной длине контента.

Типичный сценарий

1

Дизайнер создаёт навигационную панель из 5 кнопок, каждая шириной ровно 100 пикселей — на английском выглядит отлично.

2

Немецкий перевод: 'Settings' становится 'Einstellungen' (13 против 8 символов), 'Submit' становится 'Absenden' (8 против 6). Навигационная панель выходит за пределы.

3

Результат: на мобильных устройствах кнопки укладываются одна на другую или текст обрезается, что делает навигацию недоступной для немецких пользователей.

Почему это проблема

Каждый элемент с фиксированной шириной — потенциальная точка разрыва. Типичное приложение содержит сотни кнопок, подписей и карточек, которым приходится выдерживать увеличение текста.

Контейнер с фиксированной шириной (width: 120px) и кнопки фиксированного размера обрезаются или выходят за пределы, когда текст растягивается. CSS overflow: hidden скрывает содержимое без уведомления, в то время как overflow: visible разрушает макет.

Пользователи видят обрезанные ярлыки, например 'Einstellu...' вместо 'Einstellungen', или кнопки перекрывают соседние элементы. Ключевые действия становятся нечитаемыми или некликабельными.

Так устраняем проблему

Спроектируйте и реализуйте гибкие макеты, которые адаптируются к длине содержимого во всех локалях.

1

Заменяйте фиксированные ширины на min-width, max-width и используйте гибкие макеты. Применяйте CSS Grid или Flexbox для динамичного распределения пространства.

2

Устанавливайте перенос текста в контейнерах: используйте overflow-wrap: break-word и избегайте white-space: nowrap для переводимого контента.

3

Проверьте UI с использованием псевдолокализации, которая увеличивает все строки на 40% для моделирования худшего случая — ещё до отправки строк переводчикам.

Ошибка №5: Форматы дат и чисел

Данные и числа кажутся универсальными, но 01/02/2025 означает 2 января в США и 1 февраля в Европе. Запятые и точки в числах меняют значение: 1,000.50 (США) против 1.000,50 (Германия). Делать это неправильно приводит к путанице, ошибкам в данных и потере доверия.

['Никогда не форматируйте данные или числа вручную с помощью строковых шаблонов — всегда используйте Intl API', 'Сохраняйте данные в ISO 8601 и валюты в наименьшей единице (цент) внутри', 'Проводите тестирование с локалями, которые используют разные десятичные знаки, порядок дат и календари']

Никогда не форматируйте данные или числа вручную с помощью строковых шаблонов — всегда используйте Intl API.

Храните все данные в ISO 8601, а валюты — в самой мелкой единице (цент) внутри системы.

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

Типичный сценарий

1

Разработчик форматирует дату как MM/DD/YYYY и цену как $1,234.50 — правильно для пользователей США.

2

Пользователь из Германии видит дату 03/04/2025 и читает её как 3 апреля ( DD/MM/YYYY ). Цена $1,234.50 выглядит так, будто должна быть 1.234,50.

3

Результат: пользователь бронирует рейс на неверную дату и ставит под сомнение формат цены. Обращения в службу поддержки на немецком рынке растут на 15%.

Почему это проблема

Формат даты и чисел касается каждого отображения данных в вашем приложении: таблицы, диаграммы, формы, счета, отчеты. Глобальное исправление охватывает сотни экземпляров.

Жестко закодированные строки формата, такие как toLocaleDateString('en-US') или ручное форматирование с использованием шаблонных литералов, игнорируют фактическую локаль пользователя. Даже если локаль верна, но используется неправильная календарная система (Грегорианский против Хиджры) — возникают проблемы.

Пользователи читают данные неправильно и вводят данные в неверном формате. Европейский пользователь, видя 03/04/2025, может принять это за 3 апреля, а не за 4 марта — пропущенные встречи или неверные бронирования.

Как исправить это

Используйте встроенный API Intl или библиотеку форматирования с учетом локали для всех дат, времени, чисел и валют.

1

Замените ручное форматирование на Intl.DateTimeFormat(locale) для дат и Intl.NumberFormat(locale, { style: 'currency', currency }) для цен.

2

Храните данные внутри в ISO 8601 формате (YYYY-MM-DD) и форматируйте их только для отображения с использованием локали пользователя.

3

Проведите тестирование критических отображений дат и чисел с минимум 5 локалями: en-US, de-DE, ja-JP, ar-SA и zh-CN, чтобы охватить основные варианты форматирования.

Ошибка №6: Пропуск языков RTL

RTL-истории: Право-левые языки, такие как арабский, иврит и персидский, используются более чем 500 миллионами человек. Тем не менее большинство приложений проектируются только для макета слева направо (LTR). Поддержка RTL означает не просто разворот текста — все пользовательское интерфейс должно быть зеркальным.

['Используйте с первого дня исключительно логичные CSS-свойства (inline-start/end, block-start/end)', "Тестируйте ваше приложение с dir='rtl' на HTML-элементе на каждом спринт-ревью", 'Создайте RTL-тестовый чек-лист для навигации, иконок, форм и индикаторов прогресса']

С самого начала используйте только логические CSS-свойства (inline-start/end, block-start/end).

Тестируйте ваше приложение с dir='rtl' на HTML-элементе на каждом спринт-ревью.

Создайте RTL-тестовый чек-лист для навигации, значков, форм и индикаторов прогресса.

Типичный сценарий

1

Разработчик использует margin-left: 16px и text-align: left по всему приложению — стандартная правая слева (LTR).

2

Приложение запускается в Саудовской Аравии. Кнопки назад показывают вперед, боковые панели появляются на неправильной стороне, а числовые данные выравниваются неверно.

3

Результат: арабские пользователи покидают приложение через 30 секунд. Команда нуждается в 4 неделях экстренного рефакторинга CSS, чтобы исправить проблему.

Почему это проблема

RTL-поддержка затрагивает каждый элемент вашего приложения. Внедрить её после начала разработки обычно требует переписывания 30-50% CSS-правил и проверки каждого значка и макета.

Свойства CSS, такие как margin-left, padding-right, text-align: left и float: left жестко задают направление. Значки с указанием направления (стрелки, индикаторы прогресса) показывают в неверном направлении. Даже значения border-radius нужно зеркально отражать.

Арабские пользователи видят навигацию в неправильном углу, индикаторы прогресса идут в обратном направлении, а текст сталкивается с элементами интерфейса. Приложение кажется чужим и неудобным.

Как исправить это

Используйте логичные CSS-свойства и тестируйте RTL-версию с самого начала.

1

Замените все физические CSS-свойства на логические эквиваленты: margin-left → margin-inline-start, padding-right → padding-inline-end, text-align: left → text-align: start.

2

Установите dir-атрибут на корневом элементе HTML в зависимости от активной локали. Используйте CSS-псевдокласс :dir(rtl) для RTL-специфичных переопределений.

3

Проверьте все иконки на направление. Замените иконки со значением направления на зеркальные версии или используйте CSS-трансформацию: scaleX(-1) для контекстов RTL.

Ошибка №7: Изображения с текстом

Встраивание текста в изображения — будь то в геро баннере, кнопках, инфографике или скриншотах — является локализационным кошмаром. Каждое изображение с текстом должно быть создано заново для каждого языка, что увеличивает затраты на дизайн и задерживает релизы.

['Никогда не вставляйте переводимый текст прямо в растровые изображения (PNG, JPG)', 'Используйте CSS-текстовые оверлеи поверх фоновых изображений для главных баннеров и CTA', 'Автоматизируйте создание скриншотов для листингов App Store и маркетинговых страниц']

Никогда не вставляйте переводимый текст непосредственно в растровые изображения (PNG, JPG).

Используйте CSS-текстовые наложения поверх фоновых изображений для hero-баннеров и CTA.

Автоматизируйте создание скриншотов для страниц App Store и маркетинговых страниц.

Типичный сценарий

1

Дизайнер создаёт промо-баннер с текстом 'Start Your Free Trial', встроенным прямо в изображение.

2

Команда локализации переведёт все UI-строки, но баннер на немецкой версии по-прежнему отображает английский текст.

3

Результат: немецкаяLanding-page имеет раздражающий английский баннер. Создание локализованных баннеров для 15 языков займет 3 дня дизайна и задержит запуск.

Почему это проблема

Типичная маркетинговая страница содержит 5–10 изображений с текстом. При 15 языках это будет 75–150 вариантов изображений, которые нужно создавать, поддерживать и обновлять при каждом изменении дизайна.

Текст, встроенный в изображения (PNG, JPG, SVG с встроенным текстом), не может быть извлечён инструментами перевода. Каждой локализованной версии требуется, чтобы дизайнер вручную редактировал исходный файл, экспортировал его и загрузил.

Пользователи видят изображения с текстом на иностранном языке, или, что ещё хуже, смесь переведённого интерфейса и непереведённых изображений. Это выглядит непоследовательным и подрывает доверие к бренду.

Как это исправить

Разделите текст от изображений с помощью наложения CSS, SVG с переводимыми текстовыми элементами или динамической генерацией изображений.

1

Используйте CSS, чтобы разместить переводимый текст поверх фоновых изображений: разместите текстовый слой с помощью абсолютного позиционирования над контейнером изображения.

2

Для инфографики или диаграмм используйте SVG с элементами <text>, которые ссылаются на ключи перевода, вместо вставки сырых строк.

3

Для скриншотов приложений в маркетинговых материалах автоматизируйте создание скриншотов с помощью инструментов, таких как Fastlane (Mobile) или Playwright (Web), которые делают скриншоты для каждой локали.

Ошибка №8: Необработанные отсутствующие переводы

Переводы во время разработки всегда неполные. Новые функции добавляют строки быстрее, чем переводчики успевают их перевести. Без корректной обработки запасного варианта отсутствующие переводы вызывают сбои, пустые элементы UI или отображение неотформатированных ключей перевода пользователям.

['Всегда добавляйте как минимум один язык-запас в вашей i18n-настройке', 'Логируйте отсутствующие ключи перевода в вашу систему мониторинга для отслеживания', 'Установите минимальный порог охвата переводов, прежде чем локаль может выйти в продакшн']

Всегда настраивайте как минимум один язык-запас в вашей i18n-конфигурации.

Задавайте недостающие ключи перевода в вашу систему мониторинга для отслеживания.

Установите минимальный уровень охвата перевода, прежде чем локаль будет запущена.

Типичный сценарий

1

Разработчик добавляет новый раздел 'Premium Features' с 15 новыми переводными ключами. Англоязычная версия выпускается немедленно.

2

Французские переводы ещё не готовы. Французская страница показывает сырые ключи: 'premium.feature1.title', 'premium.feature1.description'.

3

Результат: французские пользователи видят сломанную страницу, полную имен ключей разработчика. Служба поддержки получает десятки баг-репортов.

Почему это проблема

Чем больше ваше приложение, тем больше разрыв между английскими строками и переводами на другие языки. Приложение с 100 языками и 2000 строками может в любой момент иметь более 10000 отсутствующих переводов.

Без логики fallback отсутствующий ключ перевода возвращает undefined, null или сам не отформатированный ключ (например 'checkout.confirmButton'). Шаблонные движки могут выдавать ошибки, вызывать сбой страницы или ничего не выводить.

Пользователи видят сломанный интерфейс: пустые кнопки, отсутствующие подписи или непонятные строки вроде 'nav.settings.title' вместо реального текста. Это сбивает с толку и выглядит не профессионально.

Как это исправить

Настройте надежную цепочку резервного копирования (fallback) и контролируйте покрытие переводов во всех локализациях.

1

Настройте цепочку языков fallback в вашей i18n-конфигурации: отсутствующие французские ключи (fr) автоматически переходят на английский (en).

2

Добавьте обработчик пропавших ключей, который будет записывать непереведённые ключи в вашу систему мониторинга (например, Sentry, Datadog), не нарушая пользовательский опыт.

3

Создайте панель покрытия переводами, которая отслеживает степень готовности локали и блокирует релизы, если покрытие ниже порога (например, 95%).

Ошибка №9: проблемы кодировки символов

Проблемы с кодировкой — скрытые убийцы локализации. Всё выглядит нормально на английском и европейских языках, но как только вы добавляете китайский, японский, корейский, арабский или эмодзи, появляются искажённые символы ( Mojibake ). Эти баги сложно обнаружить.

['Всегда используйте кодировку UTF-8 повсеместно — в исходниках, базе данных, ответах API и HTML-мета-тегах', 'Используйте utf8mb4 в MySQL (а не utf8), чтобы поддержать полный диапазон Unicode, включая эмодзи', 'Проводите тестирование с реальным контентом на CJK, арабском и эмодзи, чтобы раннее выявление проблем с кодированием']

Используйте UTF-8-кодировку повсюду — исходники, база данных, ответы API и HTML-мета-теги.

Используйте utf8mb4 в MySQL (не utf8), чтобы поддержать полный диапазон Unicode включая эмодзи.

Проверьте на реальном контенте в CJK, арабском и emoji, чтобы рано обнаруживать проблемы кодирования.

Типичный сценарий

1

Разработчик настраивает базу данных MySQL с latin1-порядком сортировки (старый стандарт). Исходный код приложения использует UTF-8.

2

Японские пользователи регистрируются своим настоящим именем. База данных сохраняет '田中太郎' как поврежденные байты.

3

Результат: профиль пользователя отображает искажённый текст. Ещё хуже: поиск и сортировка ломаются для всех имен на CJK, что затрагивает тысячи пользователей.

Почему это проблема

Проблемы кодировки распространяются по всему стеку. Неправильно настроенная сортировка базы данных может повредить миллионы записей — исправление требует дорогостоящей миграции данных.

Несоответствующее кодирование на всём стеке — UTF-8 в исходниках, Latin-1 в базе данных и Windows-1252 в ответе API — разрушает многобайтовые символы. Одна неправильно сконфигурированная ступень превращает '日本語' в '????' или '日本èª'.

Пользователи видят искажённые тексты, знаки вопроса или пустые ячейки там, где должен быть их язык. В худшем случае данные формы повреждаются навсегда в базе.

Как исправить это

Обеспечьте единообразную кодировку UTF-8 на каждом уровне вашего стека приложений.

1

Установите кодировку UTF-8 во все исходники (настройте редактор и .editorconfig). В HTML добавьте <meta charset='UTF-8'> и в ответы API — 'Content-Type: application/json; charset=utf-8'.

2

Настройте базу данных на utf8mb4 (а не только utf8, который в MySQL является подмножеством 3 байт). Установите сопоставление соединения на utf8mb4_unicode_ci.

3

Выберите шрифты, охватывающие ваши целевые наборы символов: латиницу, кириллицу, CJK, арабский и Деванагари. Используйте системные стек-шрифтов или Google Fonts с языковыми подмножествах для оптимальной загрузки.

Протестируйте вашу реализацию i18n.

Тест на увеличение длины

Увеличьте все переведённые строки на 30–40%, чтобы смоделировать расширение текста, которое встречается в языках с богатым лексиконом, например немецком, финском или греческом. Это касается контейнеров с фиксированной шириной, обрезанных ярлыков и переполненных кнопок до начала перевода. Многие псевдо‑локализационные инструменты предлагают это как встроенную функцию.

"Senden" → "Ṡééééñðéñ_éxpáñðéð" (40 % длиннее)

Псевдолокализация

Псевдо-локализация заменяет каждый символ на акцентированный эквивалент (например, 'a' → 'á') и окружает строки маркерами вроде [!! и !!]. Это позволяет сразу увидеть, какие строки закодированы вручную, а какие — из системы перевода. Запускайте псевдо-локализацию как часть вашего CI-пайплайна, чтобы автоматически ловить регрессии.

Каждый текст на экране, который не заключён в [!! !!]-markierungen, hardкодирован и должен быть вынесен в локализацию. Этот тест выявляет 95% пропущенных строк за менее чем минуту.

"Отправить сообщение" → "[!! Ñáçḥŕíçḥṫ ṡéñðéñ !!]"

Тест раскладки RTL

Даже без арабских или ивритских переводов вы можете проверить RTL-макет, добавив dir='rtl' к корневому элементу HTML. Это сразу обнаруживает проблемы с направлением CSS: неправильно выровненные иконки, отступы на неправильной стороне, сломанная навигация и неправильно отсортированные flex-элементы. Сделайте это стандартной проверкой в каждом спринт-ревью — переключение занимает 10 секунд и помогает поймать проблемы, которые иначе потребовали бы недель на исправления в продакшене.

Контрольный список i18n

['Все видимые пользователю строки вынесены в файлы ресурсов', 'Не используется конкатенация строк для формирования предложений', 'Правила множественного числа с ICU MessageFormat или эквивалент реализованы', 'Форматирование дат, времени и чисел выполняется с использованием locale-aware API', 'RTL-верстка с арабским или ивритским содержимым протестирована', 'Гибкий UI без фиксированной ширины для текстовых элементов', 'Настроен запасной язык и протестировано при отсутствии ключей', 'Кодировка UTF-8 консистентно во всех файлах и базах данных', 'Метаданные App Store и Play Store локализованы для каждого рынка', 'Скриншоты и маркетинговые материалы для каждого языка обновлены']

Поделиться статьей

Готов перевести ваше приложение?

Переведите ваше приложение iOS, Android или Web на более чем 29 языков с переводом на основе искусственного интеллекта.

Начать бесплатно

Связанные материалы

Руководство

Выбор целевых языков для вашего приложения

Руководство на основе данных по выбору правильных языков для локализации приложения. Узнайте, какие языки принесут вам лучший ROI — исходя из размера рынка, ARPU и конкуренции.

7 min
target languagesmarket researchlocalization strategy