Разделители и специальные символы

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

Точечный разделитель как навигация по объектам

По умолчанию символ . используется как разделитель вложенности. Он позволяет обращаться к глубоко вложенным значениям внутри JSON-структуры переводов.

Пример структуры ресурсов:

{
  "translation": {
    "user": {
      "profile": {
        "name": "Имя пользователя"
      }
    }
  }
}

Ключ обращения:

t('user.profile.name')

Механизм интерпретации ключа:

  • user — первый уровень объекта
  • profile — вложенный объект
  • name — конечное значение

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


Отключение точечного разделителя

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

i18next.init({
  keySeparator: false
});

После отключения ключи интерпретируются как единые строки:

t('user.profile.name')

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

Альтернативный подход — изменение разделителя:

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

Теперь вложенность должна выражаться иначе:

t('user::profile::name')

Разделитель пространств имён

i18next поддерживает концепцию namespaces (пространств имён), которые позволяют разделять переводы по модулям приложения.

По умолчанию используется символ ::

t('common:button.submit')

Здесь:

  • common — пространство имён
  • button.submit — ключ внутри namespace

Структура ресурсов:

{
  "common": {
    "button": {
      "submit": "Отправить"
    }
  }
}

Отключение разделителя namespace

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

i18next.init({
  nsSeparator: false
});

Теперь ключи интерпретируются целиком:

t('common:button:submit')

будет считаться одним ключом, а не комбинацией namespace и пути.


Интерполяционные разделители

i18next использует специальные символы для подстановки значений в строки перевода.

По умолчанию:

  • начало выражения: {{
  • конец выражения: }}

Пример:

{
  "greeting": "Привет, {{name}}!"
}

Использование:

t('greeting', { name: 'Алексей' })

Результат:

Привет, Алексей!

Вложенные интерполяции

Интерполяция поддерживает множественные переменные:

{
  "welcome": "Пользователь {{firstName}} {{lastName}} вошёл в систему"
}
t('welcome', {
  firstName: 'Иван',
  lastName: 'Петров'
});

Конфигурация интерполяционных разделителей

Символы {{ и }} можно изменить:

i18next.init({
  interpolation: {
    prefix: '${',
    suffix: '}'
  }
});

Тогда ключи будут выглядеть так:

{
  "greeting": "Привет, ${name}!"
}

Экранирование интерполяции

По умолчанию i18next экранирует значения для защиты от XSS:

i18next.init({
  interpolation: {
    escapeValue: true
  }
});

При необходимости работы с HTML можно отключить экранирование:

i18next.init({
  interpolation: {
    escapeValue: false
  }
});

В этом случае строки могут содержать HTML-разметку без преобразования специальных символов.


Специальные символы в ключах

Ключи i18next формально являются строками, но ряд символов имеет служебное значение:

  • .
  • :
  • {{ }} (в контексте интерполяции)
  • /
  • -
  • |

При использовании этих символов в ключах возможны конфликты с механизмом парсинга.


Точки в ключах как проблема структуры

Ключи вида:

t('user.name.first')

могут означать либо:

  • вложенную структуру
  • либо буквальный ключ

Если структура данных плоская:

{
  "user.name.first": "Иван"
}

необходимо отключить разделитель:

i18next.init({
  keySeparator: false
});

Двоеточие в ключах

Аналогично namespace-разделителю:

{
  "common:submit": "Отправить"
}

Без отключения:

nsSeparator: ':'

такой ключ будет интерпретироваться как namespace + key.


Использование полного отключения парсинга

При работе с внешними словарями или CMS часто требуется полностью плоская модель ключей:

i18next.init({
  keySeparator: false,
  nsSeparator: false
});

Теперь ключи воспринимаются как неизменяемые строки:

t('user.name.first')
t('common:submit')

обрабатываются буквально.


Конфликты разделителей и стратегия их устранения

В i18next существует три основных уровня интерпретации ключа:

  1. Namespace-разделение (nsSeparator)
  2. Навигация по объекту (keySeparator)
  3. Интерполяция ({{ }})

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

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

t('auth:login.button.submit')

Интерпретация:

  • auth — namespace
  • login.button.submit — путь

Если структура не соответствует ожиданиям, результатом будет missing key.


Рекомендованная изоляция семантики ключей

Для сложных систем переводов используется стратегия разделения ответственности:

  • namespace — разделение модулей
  • ключи — плоские идентификаторы
  • интерполяция — только для динамических значений

Пример плоской модели:

{
  "auth_login_button_submit": "Войти"
}
i18next.init({
  keySeparator: false,
  nsSeparator: false
});

Экранирование специальных символов в значениях

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

Пример проблемного значения:

{
  "warning": "Значение {{value}} может быть опасным"
}

Если value содержит HTML или символы {}, требуется учитывать режим экранирования:

  • escapeValue: true — безопасный режим
  • escapeValue: false — прямой вывод

Поведение при отсутствии разделителей

При отключении всех разделителей i18next превращается в систему словаря с плоскими ключами:

  • отсутствует вложенная структура
  • отсутствует namespace-интерпретация
  • интерполяция остаётся единственным динамическим механизмом

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