data-i18n必须显式标注每个可翻译节点,不可继承;语言包需三层fallback且结构扁平;切换语言须同步更新document.documentelement.lang及所有子元素lang属性;动态内容插入后须立即调用翻译函数。

data-i18n标记必须显式打在每个可翻译节点上
JS不会自动推断哪个元素要翻译,也不会根据class或id去查语言包。漏标一个button、一个select的option、甚至SVG里的text,切换语言后那里就永远是旧文案。
常见错误是只给父容器加data-i18n,指望子节点继承——没用。必须逐个标注:
<h1 data-i18n="header_title"></h1>-
<input data-i18n-placeholder="search_hint">(不是只写data-i18n) -
<select data-i18n="form_country"><option value="CN">中国</option></select>→ 这样不行,得遍历option并用"form_country.options"查数组 -
<text data-i18n="svg_download">下载</text>(SVG内文本需单独识别SVGTextElement类型)
别在<script></script>、<style></style>、<pre class="brush:php;toolbar:false;"></pre>里加data-i18n——它们不渲染为可见文本,替换无效。
JSON语言包加载失败时页面会全白,必须有fallback链
fetch('./locales/en-US.json')失败不是小概率事件:路径写错、CORS、网络抖动、服务器返回404或非application/json MIME类型,都会让response.json()抛异常或静默失败。一旦没兜底,所有textContent变成undefined,用户看到满屏data-i18n="xxx"键名。
正确做法是三层fallback:
- 先试用户选的完整BCP 47码(如
zh-HK) - 再截主语言(
zh)查./locales/zh.json - 最后退到硬编码默认对象:
{ "header_title": "Welcome", "login_btn": "Login" }
关键点:所有语言包结构必须严格扁平、键名完全一致;某语言暂未翻译,也要保留键并设为空字符串"btn_submit": "",否则查不到key就跳过,留白。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
只改document.documentElement.lang对已渲染元素完全无效
浏览器和屏幕阅读器按每个元素自身的lang属性决定语音引擎、字体回退、标点间距、RTL断行——不是继承来的。你执行document.documentElement.lang = 'ja-JP',但页面里已有<p lang="en">API</p>,它依然读英文、用英文字体、按英文规则断行。
所以切换语言时必须同步更新两处:
-
document.documentElement.lang(用于CSS适配、SEO) - 所有已有
lang属性的子元素(如<pre class="brush:php;toolbar:false;" lang="bash"></pre>、<blockquote lang="fr"></blockquote>),除非明确要保留原语言
局部混排内容(如代码块、英文术语、日文引文)必须显式写lang="en"或lang="ja-JP",不能指望全局覆盖。
动态插入内容必须在appendChild()后立刻翻译
弹窗、AJAX表格行、Toast提示、innerHTML +=拼接的内容,都不会被初始翻译函数扫描到。等DOM插入完成再调用一次翻译函数,否则永远是原始键名。
实操建议:
- 封装一个
t('common_error')函数,内部查当前激活语言包,避免重复查querySelectorAll - 在
modalEl.appendChild(content)之后,立即执行translateElement(content) - 对
select动态添加的option,要单独遍历并赋值,不能只靠父级data-i18n
最容易被忽略的是表单控件的value(按钮文字)和textContent同时存在时的覆盖逻辑——建议统一用textContent,避免value在提交时意外暴露原始键名。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










