ISO 639-1 语言代码速查表 - 国际语言代码大全
国际化最容易在"检测到的语言和实际下发的语言不一致"这类地方出问题。本表按地区给出两位字母代码,并同时标注英文名与本国名,避免把 zh 与 zh-CN、pt 与 pt-BR 这类含地区变体的代码选混。做 HTML lang 属性、Accept-Language 协商、或在数据库里存统一 locale 主键时对照。读完能让浏览器与后端对同一套语言标识达成一致。
典型使用场景
面向做多语言站点、国际化路由和语言协商的开发者。ISO 639-1 是两字母语言代码(如 zh、ja、en),在实践中通常和地区码组合成 BCP 47 标签(zh-CN、en-US、pt-BR)一起用。本表覆盖 39 个常见语言与它们的地区变体,外加 Accept-Language 请求头和 HTML lang 属性的四种标准写法。用错的后果不是报错而是「静默失效」:lang 写错时屏幕阅读器用错发音规则朗读页面。
亚洲语言 12
zhzh-CNzh-TWzh-HKjakovithidmshibn欧洲语言 22
enen-USen-GBfrdeesitptpt-BRruplnlsvdanofieltrcshurouk中东与非洲语言 5
arhefaswaf其他语言 2
laeoHTTP Accept-Language 示例 4
Accept-Language: zh-CN,zh;q=0.9Accept-Language: en-US,en;q=0.9Accept-Language: ja,en;q=0.8Accept-Language: *HTML lang 属性 4
<html lang="zh-CN"><html lang="zh-TW"><html lang="en"><html lang="ja">参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
纯语言码(zh / ja / en) | 只需声明语言、不关心地区的场景直接用两字母码 | zh :: 中文 Chinese |
语言 + 地区(zh-CN / en-GB) | 同一语言不同书写习惯或用词时用地区子标签区分 | zh-CN :: 简体中文(中国大陆) |
<html lang=""> | 声明页面语言,驱动屏幕阅读器发音与浏览器翻译提示 | <html lang="zh-CN"> |
Accept-Language 头 | 客户端表达语言偏好,q 值表示优先级,服务端据此选内容 | Accept-Language: zh-CN,zh;q=0.9 |
通配 * | 接受任意语言,一般只作为最后兜底,不建议排在最前 | Accept-Language: * |
易错点与避坑指南
现象中文页面用屏幕阅读器朗读时,发音变成拼音或美式英语。
原因lang 属性写成了 zh 而不是 zh-CN,朗读引擎按默认规则猜发音。
处置按实际内容写精确标签:简体写 zh-CN,繁体写 zh-TW 或 zh-HK。
现象所有地区的英语用户都被强制看到同一套拼写。
原因语言键只用了 en,没有区分 en-US 与 en-GB,两者的日期、拼写、用词都不同。
处置路由用完整标签存储(en-GB / en-US),只在纯语言匹配时回退到 en。
现象Accept-Language 里把 q 值写在语言后面,服务端忽略了第二偏好。
原因q 值必须紧跟在对应语言段之后,格式固定为 语言;q=权重,权重范围 0 到 1。
处置按偏好从高到低排列并写成 zh-CN,zh;q=0.9,en;q=0.8。
现象繁体用户拿到了简体文案(或反之),但页面标题看起来没报错。
原因zh-HK、zh-TW 与 zh-CN 是三个独立标签,简繁资源若只按 zh 组织就无法区分。
处置资源文件按 zh-CN / zh-TW 分开维护,只在确实无差别时把 zh-HK 映射到 zh-TW。
排障路径
1确认请求实际携带的语言偏好
curl -sI https://example.com | grep -i accept-language没有输出说明请求未带该头,服务端只能回退默认语言。
2核对页面声明的语言标签
curl -s https://example.com | grep -o "<html lang=[^>]*>"应与实际文案语言一致,繁体页需看到 lang="zh-TW" 或 lang="zh-HK"。
命令示例
把语言代码解析成可读名称
node -e "
const d = new Intl.DisplayNames(['en'], { type: 'language' });
console.log(['zh-CN', 'ja', 'pt-BR', 'en-GB', 'ar'].map(c => c + '=' + d.of(c)).join(' '));
"Intl.DisplayNames 走 CLDR 数据库,能确认一个标签是否被标准识别;非法标签会直接抛 RangeError,可当作校验手段。
输出
zh-CN=Chinese (China) ja=Japanese pt-BR=Brazilian Portuguese en-GB=British English ar=Arabic
拆出语言与地区,并做 likely-subtag 补全
node -e "
for (const t of ['zh', 'zh-CN', 'zh-TW', 'en', 'pt-BR']) {
const l = new Intl.Locale(t);
console.log(t, 'language=' + l.language, 'region=' + (l.region || '-'), 'max=' + l.maximize().toString());
}
"maximize() 把 zh 补成 zh-Hans-CN,直接印证了「裸 zh 会被推定为简体」。zh-TW 则补成 zh-Hant-TW,脚本与地区同时确定。
输出
zh language=zh region=- max=zh-Hans-CN zh-CN language=zh region=CN max=zh-Hans-CN zh-TW language=zh region=TW max=zh-Hant-TW en language=en region=- max=en-Latn-US pt-BR language=pt region=BR max=pt-Latn-BR
按 q 值把 Accept-Language 排成回退顺序
node -e "
const h = 'zh-CN,zh;q=0.9,en;q=0.8,ja;q=0.7';
const parsed = h.split(',').map(s => { const p = s.trim().split(';q='); return { tag: p[0], q: p[1] ? +p[1] : 1 }; });
console.log(parsed.sort((a, b) => b.q - a.q).map(x => x.tag + '(' + x.q + ')').join(' > '));
"解析时把缺省 q 视为 1,然后按降序排出回退链;服务端挑第一个自己有翻译的即可。
输出
zh-CN(1) > zh(0.9) > en(0.8) > ja(0.7)
同一个数字在不同语言下格式不同
node -e "
console.log(new Intl.NumberFormat('de-DE', { style: 'currency', currency: 'EUR' }).format(1234.5));
console.log(new Intl.NumberFormat('ja-JP').format(1234567.891));
"德语用点作千位分隔、逗号作小数点,日语则相反。地区标签在这里直接改变输出形态。
输出
1.234,50 € 1,234,567.891
常见坑与注意事项
- 页面 lang 写错不会有任何报错,但屏幕阅读器会用错语种朗读,翻译提示与搜索收录判断也跟着错。
- 不要把通配 * 排在 Accept-Language 最前面:它会立刻匹配掉后面所有具体偏好,让协商结果变得毫无意义。
- 繁体用户拿到简体文案(zh-TW 写成 zh,或标签整体缺失)时页面看起来完全正常,只有实际用户会发现不对劲。
- 所有英语用户共用一套文案时,en-US 与 en-GB 的拼写差异会集中暴露在少数页面,别指望自动转换能兜住。
- 两字母码与地区后缀之间要用连字符(zh-CN),写成下划线或斜杠会被当成非法标签,q 值与语言顺序一起失效。
提示
- ISO 639-1 是两位字母代码,ISO 639-2 是三位字母代码(更详细)。
- 语言标签可以带地区后缀,如 zh-CN(简体中文)、zh-TW(繁体中文)。
- HTTP 请求头 Accept-Language 用于协商内容语言,服务器可据此返回对应版本。
- HTML 的 lang 属性帮助搜索引擎和屏幕阅读器正确识别语言。
- 国际化库(如 i18next、vue-i18n)使用这些代码作为语言包标识。
常见问题
zh、zh-CN、zh-TW、zh-HK 四个标签该选哪一个?
按内容而非按用户选。简体文案用 zh-CN,繁体文案用 zh-TW 或 zh-HK;只声明语言不区分地区时用 zh。关键在于 zh 不带脚本子标签,按 BCP 47 的推定规则会被补成简体,所以它并不等于「中文」这个中立概念——繁体用户拿到 zh 会看到简体内容。反过来 zh-TW 和 zh-HK 文本相同,差别只在地区规范(货币、日期格式),选哪个取决于目标市场。
en 和 en-US 的差别真的重要吗?
取决于你的内容是否随地区变化。拼写(colour / color)、日期格式、货币符号、报价惯例都按地区走,这时必须写 en-US 或 en-GB;如果页面只有语言无关的技术内容,写 en 就够,少一个地区标签还少一处维护点。实践上多数多语言站点采用 en-US 作默认英语分支,代价是英式用户看到的少量用词需要人工调整。
Accept-Language 里的 q 值到底怎么排序?
q 取 0 到 1 之间,越大越优先,省略时默认为 1,数值相同则按出现顺序决定。关键点是 q 值必须写在分号之后紧跟标签(zh-CN;q=0.9),写成别的形态(例如把 q 放到标签前面或用逗号分隔参数)会被解析器忽略,第二偏好直接失效。降序排好后才是回退顺序:zh-CN;q=0.9,zh;q=0.8 意味着优先精确匹配,匹配不到再退到纯语言码。
HTML lang 属性写错了会有什么后果?
不会报错,只会静默失效。屏幕阅读器会按 lang 声明选择发音规则,lang 写错就用错语种朗读中文段落;浏览器据此决定是否弹出翻译提示;搜索引擎据此判断是否需要给页面做替代版本;拼写检查与断词规则同样跟着它走。所以 lang 是唯一一处「写错不报错但结果全错」的声明,值得在模板里集中管理而不是散落在每个页面。
语言代码能不能直接当 URL 路由的一部分?
可以,而且这也是本表最常见的用法,但要注意大小写与分隔符。路由段建议统一小写(/pt-br 与 /zh-cn),因为 URL 大小写敏感性因服务器而异,写成大写可能在 Nginx 与 CDN 上 404。判断语言时先转成规范形式再比较,别直接用请求里的原始字符串做等值匹配。同时要预留一个无语言前缀的默认分支,否则搜索引擎抓不到根路径。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。