Работа с HTML внутри переводов в i18next относится к наиболее чувствительным аспектам интернационализации, поскольку объединяет текстовые ресурсы, шаблонизацию и вопросы безопасности рендеринга. Основная сложность заключается в том, что переводимые строки часто содержат разметку, а механизм интерполяции i18next по умолчанию ориентирован на текстовые значения.
Переводы нередко содержат встроенные HTML-элементы:
{
"welcome": "Добро пожаловать в <strong>систему</strong>"
}
При простом выводе через t() результат интерпретируется
как строка:
t('welcome')
Итогом становится экранированный или «сырой» HTML в зависимости от контекста рендеринга.
Ключевая проблема: i18next не управляет DOM и не интерпретирует HTML автоматически.
Механизм интерполяции в i18next включает защиту от XSS по умолчанию:
i18next.init({
interpolation: {
escapeValue: true
}
});
Параметр escapeValue определяет поведение:
true — HTML-символы экранируются (< →
<)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-подобной разметкой в строках переводов применяется как промежуточный слой между текстом и компонентами:
{
"description": "Система поддерживает <b>модульную архитектуру</b> и <i>расширяемость</i>"
}
При использовании Trans:
<Trans i18nKey="description" />
HTML-теги интерпретируются как маркеры компонентов, а не как DOM-разметка.
В React-проектах часто используется прямой рендеринг HTML:
<div dangerouslySetInnerHTML={{ __html: t('htmlContent') }} />
Этот подход:
Такая модель допустима только при полном контроле над источником переводов и их валидацией.
Механизм Trans позволяет включать динамические
компоненты в текстовые блоки:
{
"terms": "Продолжая, принимается <0>пользовательское соглашение</0>"
}
<Trans
i18nKey="terms"
components={[<a href="/terms" />]}
/>
Позиционные теги (<0>, <1>)
используются для строгого контроля структуры, где порядок элементов
фиксирован.
Поддерживаются вложенные конструкции:
{
"info": "<div><strong>Важно:</strong> <span>данные обновляются ежедневно</span></div>"
}
Однако такой формат ухудшает:
Архитектурно предпочтительнее заменять структуру на компонентную модель:
{
"info": "Важно: данные обновляются ежедневно"
}
И оформлять разметку на уровне UI.
i18next поддерживает вставку динамических значений:
{
"greeting": "Здравствуйте, {{name}}"
}
При использовании HTML важно учитывать экранирование:
t('greeting', { name: '<b>Иван</b>' })
При escapeValue: true результат будет безопасным
текстом, а не HTML.
Использование HTML внутри переводов обычно ограничивается следующими сценариями:
<strong>,
<em>)<a>)TransЛюбая более сложная разметка (таблицы, формы, интерактивные блоки) нарушает границу ответственности между локализацией и UI-слоем.
Ключевые принципы:
В архитектуре i18next перевод рассматривается как данные, а не как шаблон DOM.
Вместо HTML внутри строк применяются:
Trans)Пример декомпозиции:
{
"title": "Добро пожаловать",
"subtitle": "Система управления контентом"
}
<h1>{t('title')}</h1>
<p>{t('subtitle')}</p>
HTML-списки внутри переводов часто заменяются объектной моделью:
{
"features": [
"Быстрая обработка",
"Модульная структура",
"Поддержка расширений"
]
}
const items = t('features', { returnObjects: true });
Такой подход устраняет необходимость использования
<ul> внутри переводов и переносит структуру в
код.
HTML внутри переводов рассматривается как крайний случай, возникающий при необходимости минимальной разметки. В стандартной архитектуре i18next предпочтение отдаётся:
Trans вместо
innerHTML