lang属性必须在首屏HTML中硬编码声明,JS动态修改无效;值须严格符合BCP 47规范(如zh-CN),局部混排内容需显式标注lang,charset与语言无关且必须为UTF-8。

只改 不足以适配不同语言页面——它只解决字符解码问题,和语言本身无关;真正影响多语言呈现的是 lang 属性、BCP 47 语言码规范、局部语言标注,以及服务端/首屏的初始声明方式。
lang 属性必须在首屏 HTML 中写死,JS 动态设置无效
浏览器、屏幕阅读器(NVDA/VoiceOver)、Chrome 翻译按钮、SEO 抓取器,全部只读取初始 HTML 的 。后续执行 document.documentElement.lang = "ja-JP" 不会触发任何重解析:语音引擎不切换、翻译按钮不激活、:lang() 样式不更新、拼写检查不生效。
- SSR 项目:根据
Accept-Language请求头或用户登录态,在模板中直接注入正确值,例如 - 静态站(Hugo/Jekyll):每个语言版本生成独立 HTML 文件,
lang硬编码进模板,不依赖 JS - 纯前端 SPA:语言切换时必须整页刷新(
window.location.href = "/ja/"),或重写document.documentElement.outerHTML(但 ARIA 缓存难清理,Safari 兼容性差,不推荐)
lang 值必须严格符合 BCP 47,大小写和分隔符不能错
写错 lang 不报错,但等于没写。搜索引擎忽略、屏幕阅读器朗读错、:lang(zh) 样式完全不匹配。
- ✅ 正确写法:
zh-CN、en-US、pt-BR、zh-Hans(注意是短横线-,不是下划线_) - ❌ 典型错误:
zh_CN、Chinese、zh-ch、cn、zh-hans-cn(IANA 不收录三段式,Chrome 静默降级为zh) - 选
zh-CN还是zh-Hans?多数 CMS、SEO 工具、翻译插件只认前者;后者仅当你需强调“简体字”且明确排除港澳台繁体场景时才用
局部混排内容必须显式加 lang,不能靠继承
只定义主语言,不影响内部英文引文、代码块、日文术语的识别。不加 lang,整段就按根语言处理——结果是英文单词被中文字体挤压、日文假名宽度异常、拼写检查失效。
- 外文引用:
Je suis français.
- 代码片段:
(curl -X POST
bash不是标准语言码,en更稳妥) - 技术名词:
,方便 IDE 插件做英文语义高亮useState - 切换语言时,必须遍历所有已带
lang属性的元素同步更新,除非你明确想保留原语言(比如一段日文引用始终该是日语)
charset 和 lang 完全无关,别混着配
是告诉浏览器用什么编码解码字节流,跟语言无关。UTF-8 能覆盖所有语言文字,不需要也不应该按语言切换 charset。
- 错误做法:
专用于中文 → 实际上会崩掉 emoji、特殊符号、甚至导致整个页面乱码 -
charset必须放在最前面(DOCTYPE 之后、任何其他标签之前),否则可能被浏览器忽略 - 确认 HTTP 响应头
Content-Type: text/html; charset=utf-8与一致,否则以响应头为准;可在 DevTools → Network → Response Headers 中验证
最容易被忽略的点是:很多人以为改了 lang 就等于完成了多语言适配,其实只是刚跨过语义门槛;真正的难点在于局部语言标注的完整性、服务端首次渲染的准确性,以及切换时对已有 DOM 中所有 lang 属性的批量同步——漏掉任意一个,都可能导致屏幕阅读器读错、翻译失败或字体回退异常。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











