必须用 url 路径(如 /zh/、/en/)显式分发语言,而非依赖 navigator.language 或 localstorage,以避免 cdn 缓存错乱、seo 无法索引、首屏渲染延迟及辅助技术失效等问题。

怎么用 URL 路径做语言分流,而不是靠 localStorage 或 navigator.language
只靠 navigator.language 或 localStorage 决定语言,会导致 CDN 缓存错乱、SEO 无法索引多语言页、新用户首次访问语言错配。真实线上环境必须用 URL 显式分发语言。
常见错误现象:https://example.com/ 返回中文内容,但 Googlebot 抓取时拿到的是英文缓存;用户分享链接 https://example.com/?lang=ja,点击后页面跳转却丢失参数;CDN 把所有语言都缓存成同一份 HTML。
- 强制使用子目录结构,如
/zh/、/en/、/ja/,避免 query 参数(?lang=)——CDN 和搜索引擎更信任路径级语言标识 - 服务端根据路径前缀决定加载哪个语言包,并注入
document.documentElement.lang = 'zh-Hans'和对应 JSON 脚本(如<script src="/locales/zh.json"></script>) - 前端不主动读
navigator.language,而是从location.pathname解析语言码,比如/zh/about→zh,再 fallback 到zh-Hans或zh-CN - 所有内部链接必须带语言前缀,用相对路径会出错:写
<a href="/zh/contact"></a>,别写<a href="contact"></a> - HTML 中必须加
<link rel="alternate" hreflang="zh" href="/zh/">和<link rel="alternate" hreflang="x-default" href="/">,否则 Google 不知道这是同一页面的不同语言版本
为什么不能让所有语言共用一个 HTML 文件 + 客户端 JS 切换
这种方案在开发阶段看着省事,上线后会立刻暴露性能和可访问性问题:首屏渲染延迟、SEO 不收录非默认语言、屏幕阅读器卡在旧语言、字体回退失效。
典型症状:Chrome DevTools 的 Network 面板看到 en.json 加载耗时 800ms,但页面已开始渲染中文文案;Lighthouse 报告提示 “document language not declared”;盲人用户打开页面,VoiceOver 仍按英文规则朗读顿号和引号。
- 客户端切换依赖 JS 执行完成,禁用 JS 或慢网下用户看到原始
data-i18n键名或空白 -
document.documentElement.lang改了,但已有 DOM 元素的lang属性没同步更新,浏览器不会重排标点宽度或字体链 - CDN 缓存的是未替换文本的 HTML,每次请求都要等 JS 加载语言包再操作 DOM,TTFB 后还要额外 300–1200ms 渲染延迟
- 服务端无法感知用户语言偏好,API 请求头里还是默认
Accept-Language: en-US,en;q=0.9,后端返回的错误消息仍是英文
多区域工程化分流的关键配置点
不是“写个 switch 语句判断路径前缀”就完事。真正支撑多区域的,是构建、部署、缓存三环联动。
容易踩的坑:本地测试时一切正常,上线后发现 /ja/ 页面的 CSS 字体声明被 /en/ 的打包产物覆盖;用户从 /zh/ 点链接跳到 /en/blog,页面语言变了但 document.documentElement.lang 还是 zh-Hans。
- 构建时按语言生成独立输出目录:
dist/zh/、dist/en/、dist/ja/,每个目录包含完整 HTML + 对应语言的locales/JSON + 本地化 CSS 变量(如:root { --font-main: "PingFang SC", sans-serif; }) - CDN 配置按路径前缀路由:匹配
/zh/*→ 指向dist/zh/目录,且缓存键包含Accept-Language头(仅用于降级兜底,主逻辑靠路径) - HTML 模板中用占位符注入语言码:
,构建时由模板引擎替换成zh-Hans,不是运行时 JS 拼接 - 所有动态插入内容(AJAX 表格、弹窗)必须携带语言上下文:请求 API 时加
headers: {'X-Preferred-Lang': 'zh-Hans'},后端据此返回本地化字段(如日期格式、货币符号) - 不要用
Intl.DateTimeFormat().resolvedOptions().locale当前语言来源——它返回的是系统语言,不是用户选择的区域语言(比如日本用户选了繁体中文,但系统是 ja-JP)
BCP 47 语言标签怎么写才不出错
写成 zh_CN、chinese、zh-Hans-CN 都会触发浏览器 fallback 或完全忽略,导致字体、标点、语音全部错乱。
真实错误日志:Failed to set lang attribute: invalid BCP 47 tag "zh_CN"(控制台静默,但 getComputedStyle(document.body).fontFamily 显示 fallback 字体);screen reader reads punctuation as English(辅助技术把中文顿号读成英文 comma)。
- 主语言 + 连字符 + 书写变体(可选):正确写法是
zh-Hans(简体中文)、zh-Hant(繁体中文)、en-US(美式英语)、en-GB(英式英语) - 不要加地区码除非必要:
zh-Hans-CN和zh-Hans-SG在字体、标点、数字格式上基本一致,统一用zh-Hans更稳妥 - 服务器返回的 JSON 语言包文件名必须匹配:叫
zh-Hans.json,不是zh.json或cn.json;构建工具要能识别并映射路径 - CSS 中用属性选择器做差异化适配:
html[lang="zh-Hans"] .text { text-align: justify; },但不要写html[lang^="zh"]——会误命中zh-Hant - 第三方组件(如日历、富文本)初始化时传入的 locale 必须与
document.documentElement.lang严格一致,否则日期格式和星期顺序错乱
lang 属性和 hreflang 标签的双向一致性:HTML 根节点写了 lang="zh-Hans",但 <link rel="alternate" hreflang="zh-CN"> 里的值不匹配,Google 就当你是两个不同语言版本,而不是同一内容的不同书写变体。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











