Соглашения об именовании ключей в i18next определяют устойчивость масштабируемой системы переводов и напрямую влияют на поддерживаемость локализационного слоя в больших приложениях. При отсутствии единообразной структуры ключей словари превращаются в набор несвязанных строк, усложняющих сопровождение, рефакторинг и командную работу.
Основной подход — структурирование ключей в виде вложенных пространств, отражающих доменную модель приложения.
Типичная форма:
{
"auth": {
"login": {
"title": "Вход",
"submit": "Войти"
}
}
}
Внутренне i18next поддерживает доступ через точечную нотацию:
t('auth.login.title')
Иерархия уменьшает коллизии и позволяет группировать переводы по
функциональным зонам: auth, profile,
settings, checkout.
Ключевой принцип — отражение структуры предметной области, а не структуры интерфейса. Привязка к UI-компонентам приводит к дублированию и нестабильности при рефакторинге.
При росте проекта применяется разделение переводов по namespace:
i18n.init({
ns: ['common', 'auth', 'dashboard'],
defaultNS: 'common'
});
Структура ресурсов:
{
"auth": {
"login": "Вход",
"logout": "Выход"
}
}
Обращение:
t('login', { ns: 'auth' })
или с явным указанием:
t('auth:login')
Соглашение об именовании namespaces строится на принципе bounded context: каждый namespace соответствует самостоятельной функциональной области.
Альтернативный подход — плоская структура:
{
"auth_login_title": "Вход",
"auth_login_submit": "Войти"
}
Преимущества:
Недостатки:
В проектах с i18next flat-структура применяется редко и обычно ограничивается legacy-кодом.
{
"auth_login_title": "Вход"
}
Используется в проектах, ориентированных на backend-стандарты и API-совместимость. Удобен для генерации ключей.
{
"authLoginTitle": "Вход"
}
Применяется в frontend-экосистемах, но ухудшает читаемость при длинных составных ключах.
{
"auth-login-title": "Вход"
}
Редко используется из-за неудобства обращения через точечную нотацию.
Наиболее устойчивый подход:
{
"auth": {
"login": {
"title": "Вход"
}
}
}
Комбинирует читаемость и расширяемость.
Ключи должны отражать тип интерфейсного значения:
title — заголовки страниц и блоковlabel — подписи полейplaceholder — плейсхолдерыbutton или btn — действияerror — сообщения ошибокhint — подсказкиПример:
{
"profile": {
"form": {
"email": {
"label": "Электронная почта",
"placeholder": "Введите email"
},
"submit": {
"button": "Сохранить"
}
}
}
}
Такое разделение снижает неоднозначность значений и предотвращает смешивание контекстов.
В i18next используются стандартные суффиксы:
{
"cart": {
"item_one": "товар",
"item_other": "товаров"
}
}
Использование:
t('cart.item', { count: 3 })
Система автоматически выбирает форму на основе правил языка.
Соглашение: базовый ключ без суффикса (item)
используется как логический корень, а формы — как расширения
(_one, _few, _other).
Для различий значений в зависимости от контекста применяется суффикс
context:
{
"button": {
"save": "Сохранить",
"save_context_admin": "Сохранить изменения (админ)"
}
}
Либо через встроенный контекст:
t('button.save', { context: 'admin' })
Соглашение: контекст добавляется после основного ключа и не разрывает иерархию.
Антипаттерн — чрезмерно глубокие ключи:
{
"app": {
"page": {
"profile": {
"section": {
"form": {
"input": {
"email": {
"label": "Email"
}
}
}
}
}
}
}
}
Проблема — высокая стоимость рефакторинга и слабая читаемость.
Более устойчивый вариант:
{
"profile": {
"email": {
"label": "Email"
}
}
}
Принцип: глубина структуры должна отражать доменную иерархию, а не DOM-дерево.
Все языковые ресурсы в i18next обязаны сохранять идентичную структуру ключей.
Пример:
// en
{
"auth": {
"login": "Login"
}
}
// ru
{
"auth": {
"login": "Вход"
}
}
Несоответствие структуры приводит к fallback-ошибкам и непредсказуемому поведению интерфейса.
При использовании микрофронтендов или модульной архитектуры применяются доменные префиксы:
{
"billing.invoice.create": "Создать счёт"
}
или:
{
"billing": {
"invoice": {
"create": "Создать счёт"
}
}
}
Соглашение: верхний уровень всегда соответствует модулю системы.
Ключи не должны зависеть от текстового значения. Плохой пример:
{
"login_button_click_here": "Войти"
}
Изменение текста ломает семантику ключа.
Устойчивый вариант:
{
"auth": {
"login": {
"button": "Войти"
}
}
}
Ключи представляют идентификаторы смысла, а не текстовую форму.
Повторное использование допустимо только при совпадении контекста.
Общие строки выносятся в common namespace:
{
"common": {
"cancel": "Отмена",
"confirm": "Подтвердить"
}
}
Использование:
t('common:cancel')
Соглашение: общие элементы интерфейса изолируются от доменных словарей.
При изменении семантики ключа предпочтительнее добавление нового идентификатора, а не изменение существующего:
{
"auth": {
"login": "Вход",
"signIn": "Войти"
}
}
Удаление старых ключей производится после завершения миграционного периода, чтобы избежать поломок кэшей и старых сборок.
использование описательных фраз вместо идентификаторов:
{ "click_the_button_to_save_changes": "Сохранить" }смешение языков в ключах
включение HTML или UI-логики в ключи
дублирование структуры без доменной логики
В контексте i18next такие подходы приводят к росту технического долга и усложнению локализации.