Nesting с интерполяцией

Базовое понимание nesting

Механизм nesting в i18next позволяет использовать одну переводную строку внутри другой. Это решает задачу повторного использования текстовых фрагментов и построения составных сообщений без дублирования ключей.

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

Классический синтаксис nesting:

{
  "welcome": "Добро пожаловать, $t(user.name)"
}

Здесь user.name — это отдельный ключ перевода, результат которого вставляется в строку welcome.


Отличие nesting от интерполяции

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

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

В коде:

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

Nesting же обращается к другим ключам переводов:

{
  "name": "Алексей",
  "greeting": "Привет, $t(name)"
}

Различие принципиальное:

  • интерполяция работает с данными, переданными в runtime
  • nesting работает с другими переводами внутри словаря

Синтаксис $t() в nesting

Основной инструмент nesting — функция $t() внутри строки перевода.

Общий формат:

$t(key, options)

Простейший пример:

{
  "site": {
    "name": "CodeBase"
  },
  "title": "Добро пожаловать в $t(site.name)"
}

Результат:

Добро пожаловать в CodeBase

Взаимодействие nesting и интерполяции

Одной из ключевых особенностей i18next является возможность комбинировать nesting и интерполяцию в одной строке.

Пример:

{
  "user": {
    "name": "Алексей"
  },
  "message": "Пользователь $t(user.name) имеет {{count}} уведомлений"
}

Вызов:

i18next.t('message', { count: 5 })

Результат:

Пользователь Алексей имеет 5 уведомлений

Здесь происходит два уровня обработки:

  1. $t(user.name) — nesting, извлечение перевода
  2. {{count}} — интерполяция runtime-значения

Порядок обработки выражений

i18next обрабатывает строку перевода поэтапно:

  1. Разбор nesting ($t(...))
  2. Рекурсивное разрешение вложенных ключей
  3. Применение интерполяции ({{...}})
  4. Обработка опций (если переданы)

Это означает, что nesting всегда вычисляется раньше интерполяции.

Пример:

{
  "currency": "USD",
  "price": "Цена: $t(currency) {{value}}"
}
i18next.t('price', { value: 100 })

Результат:

Цена: USD 100

Вложенность nesting (recursive nesting)

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

{
  "company": {
    "name": "TechCorp"
  },
  "product": {
    "name": "i18n Suite"
  },
  "description": "$t(company.name) разработала $t(product.name)"
}

Результат:

TechCorp разработала i18n Suite

Можно строить более глубокие цепочки:

{
  "a": "Level A",
  "b": "$t(a) → Level B",
  "c": "$t(b) → Level C"
}

Результат:

Level A → Level B → Level C

Циклические зависимости и проблемы рекурсии

При неправильной структуре переводов возможно возникновение циклов:

{
  "a": "$t(b)",
  "b": "$t(a)"
}

Такая конструкция приводит к бесконечной рекурсии или остановке по внутреннему лимиту глубины.

Типичные проблемы:

  • переполнение стека
  • fallback на ключ вместо значения
  • частичная резолюция строки

Рекомендуемая практика — избегать взаимных ссылок между ключами, особенно в shared namespaces.


Nesting с параметрами

Функция $t() может принимать параметры, аналогично обычному i18next.t().

{
  "items": "У вас {{count}} элементов",
  "summary": "$t(items, { count: 10 })"
}

Результат:

У вас 10 элементов

Это позволяет использовать одну базовую строку как шаблон для множества производных сообщений.


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

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

{
  "user": {
    "name": "Алексей",
    "full": "{{name}} Иванов"
  },
  "greeting": "Привет, $t(user.full)"
}

Результат:

Привет, Алексей Иванов

Порядок обработки:

  1. $t(user.full){{name}} Иванов
  2. интерполяция {{name}} не срабатывает, потому что параметры не переданы на уровень nesting

Чтобы это работало корректно, параметры нужно передавать через $t():

{
  "greeting": "Привет, $t(user.full, { name: 'Алексей' })"
}

Настройка префиксов и суффиксов nesting

По умолчанию i18next использует $t() как маркер nesting. Однако поведение можно кастомизировать через настройки интерполяции:

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

Важно понимать, что это влияет только на интерполяцию, но не изменяет синтаксис nesting. Nesting регулируется отдельной настройкой:

i18next.init({
  nestingPrefix: '$t(',
  nestingSuffix: ')'
})

Можно изменить стиль записи:

{
  "title": "Hello %{name}"
}

или альтернативные схемы в зависимости от конфигурации проекта.


Nesting внутри контекста и множественных форм

Nesting часто используется вместе с pluralization и context.

{
  "apple": "яблоко",
  "apple_plural": "яблоки",
  "basket": "Корзина содержит $t(apple, { count: {{count}} })"
}
i18next.t('basket', { count: 3 })

Результат:

Корзина содержит яблоки

Здесь nesting передаёт управление pluralization через вложенный ключ.


Оптимизация и производительность

Nesting увеличивает количество внутренних вызовов t(), поэтому при глубокой вложенности возможны накладные расходы.

Ключевые моменты оптимизации:

  • избегать избыточной вложенности более 2–3 уровней
  • минимизировать динамические вычисления внутри nesting
  • использовать статические строки для часто вызываемых переводов
  • избегать циклических зависимостей

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


Сочетание namespace и nesting

В проектах с namespace структурами nesting может ссылаться на ключи из других пространств:

{
  "common": {
    "appName": "Portal"
  },
  "home": {
    "title": "Добро пожаловать в $t(common:appName)"
  }
}

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


Поведение fallback при nesting

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

{
  "title": "Добро пожаловать в $t(missing.key)"
}

Результат может быть:

Добро пожаловать в missing.key

или fallback value, если он настроен через конфигурацию fallbackLng или defaultValue.


Практическая структура сложных переводов

В реальных проектах nesting используется для построения модульных сообщений:

{
  "brand": {
    "name": "NovaApp"
  },
  "auth": {
    "login": "Вход",
    "welcome": "Добро пожаловать в $t(brand.name). $t(auth.login)"
  }
}

Такой подход позволяет:

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

Взаимодействие nesting с форматированием строк

Nesting может содержать HTML или форматированные строки:

{
  "bold": "<strong>важный текст</strong>",
  "message": "Это $t(bold)"
}

Однако при использовании в UI-фреймворках важно учитывать экранирование и безопасность вывода, чтобы избежать XSS при неправильной обработке HTML-строк.


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

При комбинировании нескольких уровней:

{
  "level1": "$t(level2, { value: {{value}} })",
  "level2": "Значение: {{value}}"
}
i18next.t('level1', { value: 42 })

Результат:

Значение: 42

Параметры передаются только на уровень, где выполняется $t(), поэтому важно контролировать контекст передачи данных.