动态注入文本必须与语言上下文同步,否则引发混排、占位符失效或XSS;核心是“塞前已翻译、塞后可响应切换”,推荐data-i18n属性配合i18next.domElements()或显式translate,动态元素需插入后立即标记并手动触发翻译,服务端富文本须带lang字段预渲染。

动态注入的文本在国际化环境下,必须和当前语言上下文保持同步,否则会出现中英文混排错位、占位符未替换、甚至 XSS 漏洞。核心不是“怎么塞进去”,而是“塞之前是否已翻译、塞进去后是否仍可响应语言切换”。
data-i18n 属性 + i18next.init() 后自动填充
这是最轻量且可维护的方案:所有待翻译的静态节点(包括动态插入的 <p>、<label>)统一加 data-i18n 属性,i18next 初始化完成后调用 i18next.domElements() 或手动遍历触发翻译。
- 动态创建的元素需在插入 DOM 后立即标记,例如:
const p = document.createElement("p"); p.dataset.i18n = "welcome_message"; document.body.appendChild(p); - i18next 默认不监听新增节点,必须显式调用
i18next.services.domUtil?.translate(p)(v23+)或使用插件如i18next-browser-languagedetector配合init({ interpolation: { escapeValue: false } })确保安全 - 避免在
data-i18n值里拼接变量,如data-i18n="greeting {{name}}"—— 应改用data-i18n-options='{"name": "Alice"}'并让 i18next 解析
textContent 赋值前必须走 t() 函数,不能直接拼字符串
当用 JavaScript 动态生成文本内容(比如 API 返回文案、表单验证提示),绝不能写 el.textContent = "用户名不能为空",而必须通过翻译函数包裹。
- 正确写法:
el.textContent = i18next.t("validation.username_required"); - 若语言切换后需更新,应监听
i18next.on("languageChanged", () => { el.textContent = i18next.t(...) }),而不是只执行一次 - 注意:i18next 的
t()返回的是纯字符串,天然适配textContent;若误用innerHTML且翻译内容含 HTML(如强调标签),需开启interpolation: { escapeValue: false },但必须确保翻译资源本身可控
服务端返回的富文本字段必须带 language 字段并预渲染
CMS 或后台接口返回的 HTML 片段(如文章正文、公告栏),如果含多语言内容,不能靠前端 JS 翻译 —— 它们通常已含样式、链接、图片,且结构复杂。
立即学习“前端免费学习笔记(深入)”;
- 后端应在响应中明确返回
lang字段(如{"content": "<p>欢迎</p>", "lang": "zh"}),前端据此决定是否需要二次处理 - 若内容来自用户输入且需保留格式,必须由服务端完成翻译后再返回,避免前端用 innerHTML 注入未翻译的原始 HTML
- 绝对禁止将服务端返回的 raw HTML 直接赋给
innerHTML后再调用i18next.domElements()—— i18next 不解析子节点内的属性,data-i18n在动态插入的 HTML 字符串里不会被识别
最容易被忽略的是:动态注入的文本一旦写入 DOM,就脱离了 i18next 的响应式追踪。语言切换时,只有显式重新调用 t() 或 domUtil.translate() 才会更新,不存在“自动刷新”。别假设插件能帮你监听所有新节点。



















