Работа с HTML в переводах

Работа с HTML внутри переводов в i18next относится к наиболее чувствительным аспектам интернационализации, поскольку объединяет текстовые ресурсы, шаблонизацию и вопросы безопасности рендеринга. Основная сложность заключается в том, что переводимые строки часто содержат разметку, а механизм интерполяции i18next по умолчанию ориентирован на текстовые значения.


HTML как часть переводимой строки

Переводы нередко содержат встроенные HTML-элементы:

{
  "welcome": "Добро пожаловать в <strong>систему</strong>"
}

При простом выводе через t() результат интерпретируется как строка:

t('welcome')

Итогом становится экранированный или «сырой» HTML в зависимости от контекста рендеринга.

Ключевая проблема: i18next не управляет DOM и не интерпретирует HTML автоматически.


Интерполяция и экранирование HTML

Механизм интерполяции в i18next включает защиту от XSS по умолчанию:

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

Параметр escapeValue определяет поведение:

  • true — HTML-символы экранируются (<&lt;)
  • false — значения вставляются как есть

Типичная ошибка архитектуры переводов — отключение экранирования ради поддержки HTML:

interpolation: {
  escapeValue: false
}

Такой подход переносит ответственность за безопасность на слой данных переводов и повышает риск XSS-инъекций.


Разделение текста и разметки

Базовый принцип работы с HTML в переводах заключается в разделении структуры и контента.

Перевод:

{
  "message": "Нажмите на <link>эту ссылку</link>"
}

Рендеринг через компонентный слой:

import { Trans } from "react-i18next";
<Trans
  i18nKey="message"
  components={{
    link: <a href="/docs" />
  }}
/>

В рамках react-i18next теговая структура переводов трансформируется в реальные React-элементы, исключая необходимость вставки «сырого» HTML.


Использование HTML-тегов в ключах перевода

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

{
  "description": "Система поддерживает <b>модульную архитектуру</b> и <i>расширяемость</i>"
}

При использовании Trans:

<Trans i18nKey="description" />

HTML-теги интерпретируются как маркеры компонентов, а не как DOM-разметка.


Проблема dangerouslySetInnerHTML

В React-проектах часто используется прямой рендеринг HTML:

<div dangerouslySetInnerHTML={{ __html: t('htmlContent') }} />

Этот подход:

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

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


Смешивание текста и компонентов

Механизм Trans позволяет включать динамические компоненты в текстовые блоки:

{
  "terms": "Продолжая, принимается <0>пользовательское соглашение</0>"
}
<Trans
  i18nKey="terms"
  components={[<a href="/terms" />]}
/>

Позиционные теги (<0>, <1>) используются для строгого контроля структуры, где порядок элементов фиксирован.


HTML-атрибуты и вложенные структуры

Поддерживаются вложенные конструкции:

{
  "info": "<div><strong>Важно:</strong> <span>данные обновляются ежедневно</span></div>"
}

Однако такой формат ухудшает:

  • переносимость переводов между системами
  • читаемость JSON
  • возможность автоматической проверки

Архитектурно предпочтительнее заменять структуру на компонентную модель:

{
  "info": "Важно: данные обновляются ежедневно"
}

И оформлять разметку на уровне UI.


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

i18next поддерживает вставку динамических значений:

{
  "greeting": "Здравствуйте, {{name}}"
}

При использовании HTML важно учитывать экранирование:

t('greeting', { name: '<b>Иван</b>' })

При escapeValue: true результат будет безопасным текстом, а не HTML.


Контекстные ограничения HTML в переводах

Использование HTML внутри переводов обычно ограничивается следующими сценариями:

  • выделение текста (<strong>, <em>)
  • ссылки (<a>)
  • структурные маркеры для Trans

Любая более сложная разметка (таблицы, формы, интерактивные блоки) нарушает границу ответственности между локализацией и UI-слоем.


Безопасность при работе с HTML в i18next

Ключевые принципы:

  • перевод не должен содержать исполняемый HTML
  • экранирование должно оставаться включённым
  • компоненты предпочтительнее строковой разметки
  • динамические значения должны рассматриваться как небезопасные

В архитектуре i18next перевод рассматривается как данные, а не как шаблон DOM.


Альтернативы HTML в переводах

Вместо HTML внутри строк применяются:

  • компонентные слоты (Trans)
  • структурные JSON-переводы
  • отдельные ключи для частей интерфейса
  • композиция UI на уровне приложения

Пример декомпозиции:

{
  "title": "Добро пожаловать",
  "subtitle": "Система управления контентом"
}
<h1>{t('title')}</h1>
<p>{t('subtitle')}</p>

Рендеринг списков и структурированных блоков

HTML-списки внутри переводов часто заменяются объектной моделью:

{
  "features": [
    "Быстрая обработка",
    "Модульная структура",
    "Поддержка расширений"
  ]
}
const items = t('features', { returnObjects: true });

Такой подход устраняет необходимость использования <ul> внутри переводов и переносит структуру в код.


Итоговая модель работы с HTML в i18next

HTML внутри переводов рассматривается как крайний случай, возникающий при необходимости минимальной разметки. В стандартной архитектуре i18next предпочтение отдаётся:

  • компонентной композиции через react-i18next
  • безопасной интерполяции без отключения экранирования
  • структурированным переводам без встроенной разметки
  • контролируемому использованию Trans вместо innerHTML