Вложенные ключи и точечная нотация

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

Типичная структура ресурсов выглядит как JSON с уровнями вложенности:

{
  "header": {
    "title": "Главная страница",
    "subtitle": "Добро пожаловать"
  },
  "auth": {
    "login": {
      "title": "Вход",
      "button": "Войти"
    },
    "logout": "Выйти"
  }
}

Каждый уровень отражает логическую группировку интерфейсных строк. Вместо плоского пространства имён используются доменные блоки: header, auth, profile, errors и так далее.

Доступ к таким значениям осуществляется через строковые ключи, в которых вложенность отражается специальным синтаксисом.


Точечная нотация и механизм разрешения ключей

В i18next по умолчанию используется точечная нотация для обращения к вложенным ключам. Это означает, что вложенные уровни объекта разделяются символом .:

i18next.t('header.title');   // "Главная страница"
i18next.t('auth.login.title'); // "Вход"
i18next.t('auth.logout');    // "Выйти"

Алгоритм разрешения ключа работает следующим образом:

  1. Строка ключа разбивается по символу-разделителю (по умолчанию .).
  2. Происходит последовательный обход вложенного объекта ресурсов.
  3. На каждом уровне выбирается соответствующее свойство.
  4. Если путь полностью совпадает — возвращается строка перевода.

Таким образом, ключ auth.login.button интерпретируется как доступ к:

resources.auth.login.button

Параметр keySeparator и управление точечной нотацией

Механизм разделения ключей на сегменты управляется настройкой keySeparator. По умолчанию он равен '.', однако поведение можно изменить или полностью отключить.

Отключение точечной интерпретации

Если требуется использовать ключи, содержащие точки как часть имени, точечную нотацию можно отключить:

i18next.init({
  keySeparator: false
});

В таком случае ключ:

i18next.t('auth.login.title');

будет восприниматься как единая строка, а не путь.

Изменение разделителя

Возможна замена разделителя на другой символ:

i18next.init({
  keySeparator: '>'
});

Тогда доступ к вложенным структурам будет выглядеть так:

i18next.t('auth>login>title');

Конфликт точек в ключах и способы обработки

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

Пример конфликтной ситуации:

{
  "auth.login.title": "Вход"
}

При стандартной конфигурации i18next будет интерпретировать это как вложенность:

auth -> login -> title

а не как единый ключ.

Способы решения конфликта

1. Отключение keySeparator

i18next.init({
  keySeparator: false
});

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

{
  "auth": {
    "loginTitle": "Вход"
  }
}

3. Изменение разделителя

i18next.init({
  keySeparator: '/'
});

Вложенные ключи и массивы

i18next поддерживает доступ не только к объектам, но и к массивам внутри переводов.

Пример ресурса:

{
  "errors": {
    "validation": [
      "Поле обязательно",
      "Неверный формат",
      "Слишком короткое значение"
    ]
  }
}

Доступ осуществляется через индекс:

i18next.t('errors.validation.0'); // "Поле обязательно"
i18next.t('errors.validation.2'); // "Слишком короткое значение"

Такой подход позволяет использовать массивы для списков сообщений, подсказок и вариантов интерфейса.


Разрешение ключей в глубоко вложенных структурах

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

{
  "dashboard": {
    "widgets": {
      "weather": {
        "title": "Погода",
        "units": {
          "celsius": "Цельсий",
          "fahrenheit": "Фаренгейт"
        }
      }
    }
  }
}

Запросы:

i18next.t('dashboard.widgets.weather.title');
i18next.t('dashboard.widgets.weather.units.celsius');

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


Взаимодействие с namespace и вложенными ключами

В i18next вложенность ключей часто комбинируется с неймспейсами. Неймспейс добавляет ещё один уровень логической изоляции ресурсов.

Пример:

i18next.init({
  ns: ['common', 'auth'],
  defaultNS: 'common'
});

Ресурс:

// auth.json
{
  "login": {
    "title": "Вход"
  }
}

Доступ:

i18next.t('auth:login.title');

Здесь auth — namespace, а login.title — вложенный ключ внутри него.


Особенности интерполяции и вложенных ключей

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

{
  "auth": {
    "welcome": "Добро пожаловать, {{name}}"
  }
}
i18next.t('auth.welcome', { name: 'Алексей' });

В этом случае сначала происходит разрешение ключа через вложенность, затем подстановка переменных.


Типичные ошибки при работе с вложенными ключами

Несовпадение структуры ресурсов и ключей

Если структура не соответствует запросу:

i18next.t('auth.login.title');

но ресурс определён как:

{
  "auth": {
    "loginTitle": "Вход"
  }
}

результатом будет fallback или сам ключ.


Неправильное использование точек в ключах

Ключи с точками без отключения keySeparator интерпретируются как путь:

{
  "auth.login": "Вход"
}

При вызове:

i18next.t('auth.login');

будет попытка найти:

auth -> login

а не строковый ключ.


Слишком глубокая вложенность

Избыточная вложенность усложняет поддержку:

a.b.c.d.e.f.g

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


Поведение fallback при отсутствии ключей

Если вложенный ключ не найден, i18next возвращает:

  • сам ключ (по умолчанию),
  • значение defaultValue, если оно указано.
i18next.t('auth.login.submit', { defaultValue: 'Отправить' });

Это поведение позволяет безопасно работать с неполными структурами переводов, особенно при постепенной локализации интерфейса.


Оптимизация структуры вложенных ключей

Рациональная организация вложенности предполагает:

  • группировку по доменам интерфейса (auth, profile, settings);
  • ограничение глубины вложенности до 2–4 уровней;
  • использование семантических групп вместо технических;
  • избегание дублирования ключей на разных уровнях.

Такая структура облегчает масштабирование переводов и снижает вероятность конфликтов ключей при росте приложения.