22 авг. 2025 г.·7 мин

i18n в Vue 3 для 500+ ключей — без сюрпризов в продакшне

Практический рабочий процесс i18n во Vue 3 для крупных приложений: правила именования ключей, обработка плюралов, проверки QA и шаги релиза, чтобы избежать отсутствующих переводов в продакшне.

i18n в Vue 3 для 500+ ключей — без сюрпризов в продакшне

Что ломается при 500+ i18n‑ключах

Как только в приложении появляется несколько сотен строк, первым, что обычно начинает давать сбои, оказывается не Vue I18n, а согласованность. Люди добавляют ключи в разных стилях, дублируют одну и ту же идею под разными именами, и никто не уверен, какие сообщения можно безопасно удалить.

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

Когда перевод отсутствует, пользователи обычно видят одну из трёх проблем: пустой интерфейс (кнопка без подписи), «сырые» ключи (например, checkout.pay_now) или странный fallback, когда часть страницы внезапно переключается на другой язык. Ничто из этого не выглядит как мелкая ошибка — приложение кажется сломанным.

Именно поэтому рабочий процесс i18n во Vue 3 важнее конкретной библиотеки. Библиотека сделает то, что вы от неё попросите. В масштабе команды часто не договорены критерии «готово».

Обычный пример: разработчик выпускает новый поток «Invite teammate» с 40 новыми строками. Файл английского обновили, а французский — нет. В staging всё выглядит хорошо, потому что тестировщик работает на английском. В продакшне французские пользователи видят смешение переведённого и непереведённого интерфейса, а служба поддержки получает скриншоты с сырыми ключами.

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

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

Установите несколько правил до добавления новых строк

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

Начните с определения, что такое «концепт», и держите один источник правды для него. Если одна и та же идея интерфейса встречается в пяти местах (например, «Save changes»), нужен один ключ, а не пять вариантов вроде save, saveChanges, save_update и saveBtn. Дубликаты со временем меняют смысл, и пользователи чувствуют эту несогласованность.

Далее решите, где живёт форматирование. Команды часто случайно делят это: где‑то в сообщениях уже есть пунктуация и регистр, а где‑то это добавляет код. Выберите один подход и придерживайтесь его.

Практический дефолт:

  • Помещайте грамматику, пунктуацию и форматирование, видимое пользователю (например, «(optional)»), в само сообщение.
  • Оставляйте чистое форматирование данных в коде (даты, валюта, единицы), затем передавайте результат в i18n.
  • Используйте плейсхолдеры для имён и счётчиков, а не конкатенацию строк.
  • Рассматривайте HTML в сообщениях как особый случай с чётким правилом (разрешён или нет).

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

И, наконец, выберите и задокументируйте стратегию fallback. Если ключ отсутствует, что увидит пользователь: имя ключа, текст дефолтной локали или безопасное общее сообщение? В продакшне многие команды предпочитают падать на дефолтную локаль и логировать проблему, чтобы пользователи не блокировались, а вы всё равно получали сигнал о проблеме.

Если вы строите Vue 3 приложения с генератором вроде AppMaster (Vue3 web UI плюс реальный бэкенд), эти правила всё равно применимы. Относитесь к переводам как к продуктному контенту, а не к «просто дев‑тексту», и вы избежите большинства неожиданных проблем.

Правила именования ключей, которые остаются читаемыми

После нескольких сотен строк согласованность — главный множитель эффективности. Выберите один стиль ключей (большинство команд использует точечные пути вроде billing.invoice.title) и сделайте его правилом. Смешивание точек, слэшей, snake_case и случайного регистра замедляет поиск и ревью.

Используйте стабильные ключи, которые переживут изменения копирайта. Ключ вроде «Please enter your email» сломается, как только маркетинг слегка поправит фразу. Предпочитайте имена, описывающие намерение: auth.email.required или auth.email.invalid.

Группируйте ключи сначала по области продукта или поверхности UI, затем по назначению. Думайте в тех же корзинах, что уже есть в приложении: auth, billing, settings, support, dashboard. Это упрощает просмотр файлов локали и уменьшает дубли, когда одна идея нужна на двух экранах.

Внутри каждой области держите небольшой набор шаблонов для часто встречающихся элементов UI:

  • Кнопки: *.actions.save, *.actions.cancel
  • Ярлыки: *.fields.email.label, *.fields.password.label
  • Подсказки/хелп: *.fields.email.hint
  • Ошибки/валидация: *.errors.required, *.errors.invalidFormat
  • Уведомления/тосты: *.notices.saved, *.notices.failed

Динамические сообщения должны описывать, что изменяется, а не как. Называйте сообщение по намерению и используйте параметры для переменных частей. Например, billing.invoice.dueInDays с {days} понятнее, чем billing.invoice.dueIn3Days.

Пример (хорошо работает в i18n‑рабочем процессе Vue 3): orders.summary.itemsCount с {count} для количества и orders.summary.total с {amount} для суммы. Когда кто‑то видит ключ в коде, он должен понимать, к чему он относится и зачем нужен, даже если финальная формулировка изменится позже.

Правила для плюралов и форматирования сообщений без сюрпризов

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

Используйте простую подстановку для ярлыков и короткого UI‑текста, который не зависит от числа (например, «Welcome, {name}»). Переключайтесь на ICU для всего, что зависит от счётчика — это держит все формы в одном месте и делает правила явными.

{
  "notifications.count": "{count, plural, =0 {No notifications} one {# notification} other {# notifications}}"
}

Пишите сообщения со счётчиками так, чтобы их было легко переводить. Предпочитайте полное предложение и держите плейсхолдер числа (#) рядом с существительным. Избегайте хитрых приёмов вроде повторного использования одного ключа для «1 item» и «2 items» в коде. Переводчикам нужен весь текст, а не догадки о том, как он будет склеиваться.

Планируйте минимум для =0, one и other, и задокументируйте, что вы подразумеваете под 0. В одних продуктах хотят «0 items», в других — «No items». Выберите один стиль и придерживайтесь его, чтобы интерфейс выглядел согласованно.

Также следите за языками с большим числом категорий плюрала, чем вы ожидаете. Многие языки не укладываются в «one vs many». Если позже добавить новую локаль, сообщение, содержащее только one и other, может оказаться грамматически неправильным.

Перед релизом протестируйте плюралы с реальными значениями в UI, а не только глазами просмотрите JSON. Быстрая проверка, которая ловит большинство проблем: 0, 1, 2, 5 и 21.

Если вы строите Vue3 веб‑приложение (например, внутри AppMaster), делайте тесты прямо на экране, где текст появляется — там сначала проявляются проблемы с версткой, усечённым текстом и неуклюжим построением фраз.

Организация файлов локалей для роста

Одно рабочее пространство для всех локалей
Создавайте бэкенд, веб‑интерфейс и мобильные приложения в одном месте и уменьшайте дрейф i18n.
Начать

После нескольких сотен строк один большой en.json становится узким местом. Люди одновременно правят один файл, конфликты слияния растут, и теряется понимание, где лежит тот или иной текст. Хорошая структура удерживает рабочий процесс i18n стабильным, даже когда продукт продолжает меняться.

Рекомендуемые структуры

Для 2–5 локалей обычно достаточно разделения по фичам. Держите одинаковую структуру файлов в каждой локали, чтобы добавление ключа было предсказуемым:

  • locales/en/common.json, locales/en/auth.json, locales/en/billing.json
  • locales/es/common.json, locales/es/auth.json, locales/es/billing.json
  • locales/index.ts (загружает и мержит сообщения)

Для 20+ локалей масштабируйте ту же идею, но затрудняйте рассинхронизацию. Считайте английский источником истины и добейтесь, чтобы каждая локаль имела те же папки и имена файлов. Если появляется новая область (например, notifications), она должна существовать для каждой локали, даже если текст временный.

Разделение по доменам уменьшает конфликты слияния: два человека могут добавлять строки в разные файлы, не мешая друг другу. Домены должны соответствовать архитектуре приложения: common, navigation, errors, settings, reports, плюс папки с фичами для больших областей.

Поддержание согласованных ключей

Внутри каждого файла держите одинаковую форму ключей во всех локалях: одинаковая вложенность, одинаковые имена ключей, разный текст. Избегайте «творческих» ключей для каждого языка, даже если фраза тяжело переводится. Если в английском есть billing.invoice.status.paid, каждая локаль должна иметь точно такой же ключ.

Централизуйте только то, что действительно повторяется везде: подписи кнопок, общие ошибки валидации и глобальная навигация. Фича‑специфичный текст держите рядом с доменом фичи, даже если он кажется переиспользуемым. «Save» принадлежит common. «Save payment method» — billing.

Длинные тексты

Длинная справочная информация, шаги онбординга и шаблоны писем быстро становятся неразборчивыми. Несколько правил помогают:

  • Помещайте длинные тексты в отдельный домен (например, help или onboarding) и избегайте глубокой вложенности.
  • Предпочитайте короткие абзацы вместо одной гигантской строки, чтобы переводчики работали безопасно.
  • Если маркетинг или поддержка часто правят текст, держите такие сообщения в отдельном файле, чтобы уменьшить дев‑шум в других местах.
  • Для писем храните subject и body отдельно и держите плейсхолдеры согласованными (имена, даты, суммы).

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

Пошаговый рабочий процесс по добавлению и выпуску строк

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

Начните с добавления ключа в базовую локаль (обычно en). Пишите дефолтный текст как реальную копию, а не плейсхолдер. Это даёт продукту и QA что читать при ревью и предотвращает «таинственные строки» позже.

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

// simple param
$t('billing.invoiceDue', { date: formattedDate })

// plural
$t('files.selected', count, { count })

Если переводы не готовы, не оставляйте ключи отсутствующими. Добавьте временные переводы в другие локали или пометьте их как pending в согласованном формате (например, префикс TODO:). Важно, чтобы приложение рендерилось предсказуемо, а ревьюеры могли увидеть незавершённый текст.

Перед мержем запускайте быстрые автоматические проверки. Сделайте их скучными и строгими: отсутствующие ключи в локалях, неиспользуемые ключи, несоответствие плейсхолдеров (отсутствует {count}, {date} или неправильные фигурные скобки), неверные формы плюрала для поддерживаемых языков и случайные переопределения.

Наконец, выполните короткий UI‑просмотр хотя бы в одной не‑базовой локали. Выберите язык с более длинными строками (обычно немецкий или французский), чтобы поймать переполнение, усечение текста и неуклюжие переносы. Даже если ваш Vue 3 UI генерируется или поддерживается вместе с другими частями продукта (например, Vue3 веб‑приложение, созданное AppMaster), этот шаг важен, потому что верстка меняется по мере добавления фич.

Относитесь к этим шагам как к определению готовности для любой фичи, добавляющей текст.

Частые ошибки, которые команды продолжают повторять

Собирайте Vue3-приложение быстрее
Соберите Vue3 веб‑приложение и сохраняйте согласованность UI по мере роста продукта.
Попробовать AppMaster

Самый быстрый путь сделать локализацию болью — относиться к i18n‑ключам как к «просто строкам». После нескольких сотен ключей мелкие привычки перерастают в баги в продакшне.

Ключи, которые дрейфуют, конфликтуют или лгут

Опечатки и различия в регистре — классические причины отсутствия текста: checkout.title в одном месте и Checkout.title в другом. В ревью кода это выглядит нормально, а потом в проде тихо отработает fallback.

Ещё одна распространённая проблема — повторное использование одного ключа для разных смыслов. «Open» может означать «Open ticket» на экране поддержки и «Open now» на странице магазина. Если использовать один ключ, один из экранов будет неправилен в других языках, и переводчики начнут гадать.

Простое правило: один ключ = одно значение. Если смысл меняется, заведите новый ключ, даже если английский текст одинаков.

Баги с версткой, вызванные предположением о «форме строки»

Команды часто хардкодят пунктуацию, пробелы или кусочки HTML в переводах. Это работает, пока язык не потребует другой пунктуации, или пока ваш UI не экранирует/не рендерит разметку иначе. Держите разметку в шаблонах, а сообщения — фокусируйтесь на тексте.

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

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

Если хотите, чтобы i18n‑рабочий процесс во Vue 3 оставался спокойным при 500+ ключах, относитесь к ключам как к части API: стабильными, специфичными и протестированными, как и всё остальное.

Шаги QA, которые ловят пропавшие переводы рано

Сделайте системные сообщения предсказуемыми
Используйте Business Process Editor, чтобы стандартизировать тосты, уведомления и системные сообщения.
Собирать автоматизации

Отсутствующие переводы легко пропустить, потому что приложение «работает» — просто падает на ключ, неправильную локаль или пустую строку. Относитесь к покрытию переводов как к тестам: нужно быстрое обратное уведомление до релиза.

Автоматические проверки (на каждый PR)

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

  • Просканируйте код на использование $t('...') и t('...'), затем проверьте, что каждый используемый ключ есть в базовой локали.
  • Сравните наборы ключей между локалями и падайте сборку, если где‑то отсутствуют ключи (если только ключ не в коротком списке исключений, например «en‑only legal notes»).
  • Помечайте орфанные ключи, которые есть в файлах локали, но нигде не используются.
  • Валидируйте синтаксис сообщений (плейсхолдеры, блоки ICU/плюралов). Одна сломанная строка может упасть страницу во время выполнения.
  • Считайте дубликаты ключей или несовпадающий регистр за ошибки.

Держите список исключений коротким и под контролем команды, а не «чтобы CI прошёл».

Проверки во время выполнения и визуальные (staging)

Даже с CI нужен сетевой фильтр в staging, потому что реальные пути пользователей вызывают строки, про которые вы забыли.

Включите логирование отсутствующих переводов в staging и добавляйте достаточно контекста для быстрой исправки: локаль, маршрут, имя компонента (если доступно) и отсутствующий ключ. Сделайте это шумным. Если это легко игнорировать, это будет проигнорировано.

Добавьте псевдо‑локаль и используйте её для быстрого UI‑прогона. Простой подход — трансформировать каждую строку (сделать её длиннее и добавить маркеры), чтобы проблемы с версткой выпирали: например, [!!! 𝗧𝗲𝘅𝘁 𝗲𝘅𝗽𝗮𝗻𝗱𝗲𝗱 !!!]. Это ловит обрезанные кнопки, сломанные заголовки таблиц и отсутствующие пробелы до релиза.

И, наконец, выполните короткую предрелизную проверку основных пользовательских путей в 2–3 локалях: вход, оплата/чекаут, основные настройки и новая фича, которую релизите. Тут вы поймаете «переведено, но плейсхолдер неправильный».

Добавление новых языков и постоянные изменения копирайта

Добавление нового языка превращается в хаос, если воспринимать это как «копирайт‑работу», а не как маленький релиз продукта. Проще всего сохранить стабильность рабочего процесса i18n, если приложение собирается даже при незавершённой локали, но при этом пробелы видны до того, как их увидят пользователи.

При добавлении новой локали начните со создания той же структуры файлов, что и у исходной локали (обычно en). Переводы — потом, сначала — структура.

  • Создайте новую папку/файл локали с полным набором ключей, скопированным из источника.
  • Пометьте значения как TODO‑плейсхолдеры, чтобы пропуски были видимы в QA.
  • Добавляйте локаль в переключатель языков только после покрытия базовых сценариев.
  • Пройдитесь по экрану за экраном, чтобы поймать проблемы с разметкой (длиннее слова, переносы).

Переводы часто приходят поздно, поэтому заранее решите, что значит «частично готово» для вашего продукта. Если фича клиентская, рассмотрите feature‑флаг, чтобы фича и её строки выходили вместе. Если нужно выпустить без всех переводов, предпочтительнее явный fallback (например, английский), чем пустые метки, но делайте это заметным в staging.

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

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

Держите заметки для переводчиков рядом с ключом. Если ваш JSON‑формат не поддерживает комментарии, храните заметки в небольшом сопутствующем документе или рядом в метаданных (например, «используется на экране успеха чекаута»). Это особенно полезно, когда Vue 3 веб‑приложение генерируется из инструмента вроде AppMaster и над копирайтом работает много людей.

Пример: выпуск фичи с 60 новыми строками

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

В одном спринте команда выпускает три вещи: новую страницу Settings, экран Billing и три шаблона письма (квитанция, неудачный платёж, окончание пробного периода). Это около 60 новых строк — и здесь обычно начинается беспорядок.

Команда договаривается группировать ключи по фиче, затем по поверхности. Создаётся новый файл на фичу, и ключи везде следуют одному паттерну: feature.area.element.

// settings
"settings.profile.title": "Profile",
"settings.security.mfa.enable": "Enable two-factor authentication",

// billing
"billing.plan.current": "Current plan",
"billing.invoice.count": "{count} invoice | {count} invoices",

// email
"email.receipt.subject": "Your receipt",
"email.payment_failed.cta": "Update payment method"

Перед началом переводов плюральные строки тестируют на реальных значениях, а не на догадках. Для billing.invoice.count QA проверяет 0, 1, 2 и 5 с подготовленными данными (или простым dev‑переключателем). Это рано ловит неловкие случаи вроде «0 invoice».

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

В этом спринте QA нашёл два пропавших ключа: одну подпись в Billing и одну тему письма. Команда исправила их до релиза.

При решении, блокировать релиз или позволить fallback, они руководствуются простым правилом: пользовательские экраны и транзакционные письма блокируют релиз; низкорисковый админ‑текст может временно падать на дефолтный язык, но только с тикетом и чётким дедлайном.

Следующие шаги и простой чеклист релиза

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

Чеклист релиза (за 5 минут до мёржа)

  • Ключи: соответствуют паттерну именования и имеют чёткую область (страница, фича, компонент).
  • Плюралы: подтвердите, что формы плюрала рендерятся корректно хотя бы в одном языке с разными формами.
  • Плейсхолдеры: убедитесь, что переменные присутствуют, имеют одинаковые имена везде и выглядят корректно на реальных данных.
  • Fallbacks: подтвердите, что поведение при отсутствии ключа соответствует вашей политике.
  • Экраны: spot‑check самых уязвимых экранов (таблицы, тосты, модалы, пустые состояния).

Что измерять (чтобы проблемы проявлялись рано)

Выберете несколько простых показателей и проверяйте их регулярно: доля пропущенных ключей в прогоне тестов, количество непереведённых строк в не‑базовых локалях и количество неиспользуемых ключей (строк, которые больше нигде не встречаются). Отслеживайте их по релизам, чтобы видеть тренды, а не разовые провалы.

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

Если вы строите внутренние инструменты, AppMaster (appmaster.io) может быть практичным способом держать UI‑копирайт и ключи переводов в согласованности между Vue3 веб‑приложением и мобильными приложениями, так как всё управляется в одном месте.

Запланируйте одну небольшую задачу по i18n в каждом спринте: удалить мёртвые ключи, исправить несоответствия плейсхолдеров и просмотреть недавние пропуски. Небольшие чистки обходятся лучше, чем экстренные поиски переводов в продакшне.

Легко начать
Создай что-то невероятное

Экспериментируйте с AppMaster с бесплатной подпиской.
Как только вы будете готовы, вы сможете выбрать подходящий платный план.

Попробовать AppMaster