navigator.language 返回浏览器UI语言的BCP 47标签(如"zh-CN"),但需归一化(转小写、取主语言码、排除无效值)后才能安全用作i18n初始语言;它是加载时快照,不响应系统语言变更。

navigator.language 返回的是什么值,能直接当语言代码用吗
navigator.language 返回浏览器 UI 语言的 BCP 47 标签,比如 "zh-CN"、"en-US"、"ja"、"pt-BR"。但它不是标准化的 locale 列表,可能带地区子标签(如 zh-TW),也可能不带(如 fr);有些旧版 Safari 甚至返回 "zh-cn" 小写形式。
不能直接当 key 去查你的翻译对象,必须做归一化处理:
- 统一转小写(避免大小写敏感匹配失败)
- 提取主语言部分:用
.split("-")[0]拿到"zh"、"en"、"fr"等基础语言码 - 显式排除无效值(如
"und"、空字符串、"qps-Ploc"这类占位符)
怎么用它决定初始 i18n 配置,而不是等页面加载完再切语言
关键是在 JS 执行早期(最好在 <script></script> 内联执行时)就确定语言,避免 DOM 渲染后又重绘文本。不要等 window.onload 或 React/Vue 初始化后再读 navigator.language。
实操建议:
- 把语言探测逻辑放在 HTML 的
中第一个<script></script>里(非 defer/non-async) - 用一个全局变量(如
window.__INITIAL_LOCALE__)暂存结果,后续 i18n 库初始化时直接读取 - 如果用 i18next,传给
init({ lng: window.__INITIAL_LOCALE__ });如果是自定义方案,用它来索引messages[lang] - 注意 fallback:当
navigator.language不在你支持的语言列表中时,必须有兜底(如"en"),不能留空
用户改了系统语言,网页会自动响应吗
不会。navigator.language 是只读静态快照,页面加载时取一次就固定了。即使用户中途切换系统语言,已打开的页面完全无感知。
这意味着:
- 别指望靠监听系统变化来“热更新”语言 —— 浏览器不提供这种 API
- 如果需要手动切换,得提供显式 UI(如语言下拉框),并重新挂载/刷新文案(或 reload 页面)
- 服务端渲染(SSR)场景下,
navigator.language根本不可用,必须靠请求头Accept-Language+ 客户端二次校准
常见错误:把 navigator.language 当作用户偏好,忽略地区差异
比如用户系统设为 "zh-CN",但你的文案只提供了 "zh" 版本,这时直接用 zh-CN 查会 miss;反过来,如果你有 "zh-Hans" 和 "zh-Hant",但只按 zh 匹配,就丢了语义区分。
更稳健的做法是按优先级尝试匹配:
- 先试完整标签:
"zh-CN" - 再试主语言:
"zh" - 最后 fallback 到默认语言(如
"en")
可以用一个数组表示优先级:["zh-CN", "zh", "en"],然后遍历检查是否在支持列表中。
真正容易被忽略的是:移动端 WebView(尤其是微信内置浏览器)常把 navigator.language 固定为 "zh-CN",哪怕用户手机设成英文 —— 这时候它已经不是真实用户语言了,得结合其他线索(如 URL 参数、localStorage 记录)交叉判断。

















