data-i18n必须显式覆盖所有可翻译文本节点及属性(如-placeholder、-title、-alt),lang属性须逐元素设置而非仅改documentelement,动态dom需手动触发翻译,深层嵌套(>6层)会导致节点漏处理,语言包须fetch加载并校验mime与bcp 47格式。

data-i18n标记必须覆盖所有可翻译文本节点及属性
只给加data-i18n="btn_submit",漏掉placeholder、title、aria-label,切换语言后输入框提示仍是英文,屏幕阅读器播报错乱——这是最常被忽略的硬伤。
-
data-i18n只更新textContent,对placeholder、alt、title等属性完全无效 - 必须显式使用
data-i18n-placeholder、data-i18n-alt、data-i18n-title等带后缀的属性 -
value属性一般不翻译(属于用户输入数据),但label标签内的文本必须标记,且for要与id严格对应 - 含HTML结构的文案(如“请阅读服务条款”)必须用
innerHTML替换,语言包中对应值需是可信纯HTML片段,否则有XSS风险
lang属性必须逐层设置,不能只改document.documentElement.lang
执行document.documentElement.lang = 'en'后,页面文字变了,但屏幕阅读器仍读中文、标点间距错乱、等宽代码块字体回退失效——问题出在浏览器和辅助技术根本不看继承,只认每个元素自身的lang属性。
- 所有带文本内容的语义化容器(
<h1></h1>、<p></p>、<section></section>、<blockquote></blockquote>)都应显式加lang属性,值与当前语言包一致 - 已有
lang的元素(如<pre class="brush:php;toolbar:false;" lang="bash"></pre>)切换语言时必须保留原始值,这是明确的多语言混排场景,不是bug -
<script></script>和<style></style>里设lang无效,这些节点不参与渲染 - 切换前先收集
document.querySelectorAll('[lang]'),对每个匹配元素执行el.lang = newLang
DOM深度超6层会导致data-i18n节点漏翻译
语言切换后部分按钮/提示文字没变,但document.querySelectorAll('[data-i18n]').length返回数量比预期少——不是JS写错了,而是遍历逻辑因性能阈值跳过了第7层及更深的节点。
- 用浏览器 Elements 面板右键 → “Reveal in Elements panel”,手动数从
body到目标data-i18n元素的层级,必须 ≤6 - 冗余
<div>堆叠结构(如六层嵌套<code><div><div><div><div><div><p data-i18n="msg"></p></div></div></div></div></div>)是典型诱因 - 用
<main></main>、<section></section>等语义标签替代无意义<div>,天然中断嵌套深度,也利于i18n工具识别作用域 <li>动态插入的DOM(弹窗、AJAX表格行)必须在<code>appendChild()后立即调用翻译函数,不会自动监听 - 路径统一为
./locales/${lang}.json,例如./locales/zh-HK.json、./locales/en-US.json - 必须用
fetch()加载,外层包try/catch,内部检查response.ok和response.headers.get('content-type')是否为application/json - 语言包结构必须扁平:
{"header_title": "首页", "form_email_required": "邮箱必填"},禁止嵌套对象 - fallback顺序:先试完整BCP 47码(如
zh-Hant),再截主语言(zh),最后退到默认语言(如en)
语言包加载必须用fetch+try/catch,路径和MIME校验缺一不可
把语言包硬编码进JS里,或用XMLHttpRequest老式写法,都会导致构建体积膨胀、热更新困难、404静默失败——尤其是服务器返回text/plain MIME时,response.json()直接抛错。
lang属性没同步、data-i18n漏了placeholder、DOM太深导致节点被跳过——这些点不逐个踩一遍,就永远在“看起来能跑”和“线上真实可用”之间反复横跳。











