lang属性必须显式设在每个含文本的语义标签上,如<h1>、<p>等,仅设html根节点无效;代码类元素保留原lang值;<title>、<meta>需单独设置;data-i18n需覆盖所有可翻译属性;动态DOM需手动触发翻译;bdi仅用于隔离不可控方向子串;lang值须符合BCP 47标准。

lang 属性必须写在每个含文本的语义标签上,不是只设在 <html>
只改 document.documentElement.lang 是不够的——浏览器和屏幕阅读器不会继承它。你看到 <p>北京</p> 里的顿号间距不对、<pre lang="bash"> 被中文字体覆盖、<img alt="logo"> 的替代文本没变音,根本原因就是这些元素自己没声明 lang。
-
<h1>、<p>、<section>、<footer>等所有含文本的语义化标签,都要显式加lang="zh-CN"(值与当前语言包一致) -
<pre lang="bash">、<code lang="sql">这类已有lang的代码类元素,切换语言时保留原值,这是合法混排场景 -
<title>、<meta name="description">不继承根节点lang,必须单独设,比如<title lang="ja-JP">ホーム</title> -
<script>和<style>内部不参与文本渲染,加lang没意义
data-i18n 要覆盖所有可翻译属性,不只是 innerText
只给按钮加 data-i18n="btn_submit",但漏掉 placeholder 或 aria-label,会导致表单提示、无障碍播报始终是英文。这不是翻译漏了,是标记没打全。
- 每个要翻译的元素至少有一个基础
data-i18n键;含placeholder就额外加data-i18n-placeholder;同理data-i18n-title、data-i18n-alt -
value属性属于用户输入数据,一般不翻译,跳过处理 - 含 HTML 结构的文案(如“请阅读使用条款”)必须用
innerHTML替换,且语言包里对应值要是可信纯 HTML 片段,否则有 XSS 风险
动态插入的 DOM 必须手动触发翻译,不会自动监听
AJAX 加载的弹窗、表格行、懒加载模块插入后,如果没调用翻译函数,里面的 data-i18n 标记就只是字符串,不会变成对应语言文本。这不是框架 bug,是设计使然——DOM 插入本身不触发国际化逻辑。
- 每次
appendChild、insertAdjacentHTML或框架级渲染(如 ReactuseEffect插入新节点)后,需显式调用你的翻译函数,例如i18n.translate(el) - 不要依赖 MutationObserver 全局监听:性能差、易漏边角 case(如
innerHTML = ...直接赋值) - 对第三方组件(如日历控件、富文本编辑器)注入的 DOM,也要在其回调或生命周期钩子中补调翻译
dir 和 bdi 不是“右对齐开关”,而是双向文本隔离机制
把 bdi 当成“让阿拉伯文右对齐”的工具,会破坏可访问性。它的作用是开启 Unicode 双向隔离(Bidi Isolation),防止父子方向污染,仅用于不可预知方向的独立子串。
立即学习“前端免费学习笔记(深入)”;
- 用户昵称、文件名、邮箱等来源不可控的内容,用
<bdi>user@مثال.com</bdi>,避免标点错位、复制粘贴顺序混乱 - 整段混排正文、
<input>或<textarea>内部不要套bdi——它们自身管理光标与方向 - 容器整体流向用
dir="rtl"或dir="auto"(后者适合首字符决定方向的场景,如 API 返回的昵称),dir="auto"在 Safari 13.0- 需降级为bdi
实际项目里最容易被忽略的,是 lang 值必须严格符合 BCP 47 标准:小写字母 + 连字符 + 地区码(如 zh-Hans、ar-SA),zh_cn 或 Chinese 都无效——浏览器和爬虫直接忽略,等于没写。



















