HTML国际化必须分四层:引擎层处理data-i18n映射与fallback,资源层用扁平JSON键名对齐,DOM层显式设lang于每个语义标签并限深≤6,状态层同步localStorage、根lang及动态节点翻译。

HTML国际化必须分层,不分层就是埋雷
只靠一个 data-i18n 属性打标记、用 document.documentElement.lang = 'zh-Hans' 一改了事,表面能切语言,实际标点错乱、屏幕阅读器读错、字体回退失效——这不是国际化,是给后续维护挖坑。
四层结构缺一不可:引擎层、资源层、DOM层、状态层
真正可维护的 HTML i18n 架构不是“写个翻译函数”,而是四层各司其职:
-
引擎层:负责扫描
data-i18n、触发替换、处理属性后缀(如data-i18n-placeholder)、校验 BCP 47 格式、管理 fallback 逻辑;它不碰 DOM 结构,只做纯数据映射 -
资源层:每个语言一个扁平 JSON 文件(
./locales/en-US.json),键名严格对齐,缺失键留空字符串而非跳过,避免渲染空白;禁止嵌套对象或动态 key -
DOM 层:所有含文本的语义化标签(
<h1>、<p>、<section>、<label>)必须显式设lang,值与当前语言包一致;已有lang="bash"的<pre>不覆盖,保留多语言混排能力 -
状态层:语言选择存在
localStorage,切换时同步更新document.documentElement.lang+ 所有已渲染元素的lang属性 +data-i18n对应文案;AJAX 插入的新节点(如弹窗、表格行)插入后必须立即调用引擎的translate(),不能等下次全局扫描
DOM 深度超 6 层会漏翻译,不是 bug 是设计缺陷
当 data-i18n 出现在 <div><div><div><div><div><p data-i18n="msg"></p></div></div></div></div></div> 这种纯 CSS 堆叠结构里,遍历逻辑大概率截断——控制台查不到报错,但那段文字永远不更新。
- 用浏览器 Elements 面板右键 → “Reveal in Elements panel”,手动数从
<body>到目标元素的层级,必须 ≤6 - 把冗余
<div>替换为<main>、<section>、<article>等语义标签,天然降低深度,也利于引擎识别作用域 - SSR 渲染首屏时,如果
data-i18n节点在第 7 层才出现,服务端初始化脚本很可能直接跳过——必须检查服务端渲染输出的 HTML 结构深度
语言包加载失败静默变白屏?这是没做工程化兜底
硬编码语言包、用 XMLHttpRequest 不校验状态码、fetch 后不检查 response.headers.get('content-type'),都会导致语言包加载失败却无提示,整页文案消失。
立即学习“前端免费学习笔记(深入)”;
- 路径统一为
./locales/${lang}.json,fallback 顺序:先试完整码(zh-HK),再截主语言(zh),最后退到en-US - fetch 必须包
try/catch,内部检查response.ok和response.headers.get('content-type')?.includes('application/json') - 语言包内容必须是 UTF-8 编码,BOM 头会导致解析失败;JSON 中所有键必须小写+英文点号分隔(
user.login.title),中文 key 或驼峰命名会破坏工具链兼容性



















