语言代码对照表

常见语言的 ISO 639-1 两字母代码与中英文名称,用于网页 lang 属性、多语言 API 与内容协商。

原理解析

ISO 639 为自然语言分配代码:两位(zh、en、ja)与三位(zho、eng、jpn)。它们用于 HTML lang 属性、Content-Language 头、语言切换器等,比中文/英文名称更通用。

地区常叠加在语言之后,形成语言标签(BCP 47):zh-CN、en-US、pt-BR——前者是语言、后者是地区变体。同一语言不同地区在拼写、用词、日期格式上可能差异明显,i18n 必须区分。

实务上的最小可用做法:页面根元素标 lang,内容较长且语言不同的片段单独标 lang/hreflang,路由段只用 ISO 639-1 两字母并在需要地区差异时才追加地区码。这三步能覆盖绝大多数场景的可访问性与 SEO 需求,成本很低。真正需要额外投入的是内容本身的多语言版本管理(翻译、复数规则、日期与数字格式),那属于 i18n 工程而非语言代码问题,不要在代码层面找解法。

关于「代码」与「标签」的一个常见误解:ISO 639 只覆盖语言,不覆盖文字系统。像 he(希伯来语)这类语言可能使用拉丁或希伯来文字,zh-Hant 与 zh-Hans 的差异是文字系统而非语言,处理排版与字体时要看 script 子标签而不是语言码。日常 Web 场景语言码足够,但做多文字排版或无障碍朗读时,script 层的影响会显现出来。

什么时候该查这张表

这张表在你要给内容打上语言标记时有用:HTML lang 属性、HTTP Content-Language 头、搜索筛选、朗读与翻译路由,全都以语言代码为依据。打错的后果是搜索引擎读不懂页面语种、屏幕阅读器选错语音、hreflang 关系失效。

不该查的情况:你在做界面文案的多语言版本管理。语言代码解决的是「这段内容是什么语言」,而 i18n 文件的组织、复数规则、日期格式属于 i18n 工程范畴,两者不要混。

判断标准:凡是「机器需要据此做选择」的地方就写代码——lang、Accept-Language、hreflang;凡是「人看的界面」就写语言名或 Intl.DisplayNames 的结果。两者混用是常见错误来源。

特别注意两字母与三字母不是简单长短关系:ISO 639-1 的 zh 是「整个中文」,639-2/T 的 zho 是文献语言名,639-3 的 zho 则是 macrolanguage 集合(可细到 cmn/yue)。写数据库主键时必须明确选用哪一版,混用会造成静默的匹配失败。

边界与常见陷阱

  • lang 属性写在错误的元素上会继承错语言

    lang 是可继承属性。整页有多语言混排(如中文正文里嵌一段英文代码示例)时,只在 <html> 上写一次 lang="zh" 会让屏幕阅读器用中文读英文段落。可行的做法是给语言不同的片段单独标 lang="en",必要时再加 dir 指示书写方向;搜索引擎也能据此判断段落语种而非整页语种。

  • hreflang 必须双向互指且用规范 URL

    声明 en-US 指向 /en/x 的同时,/en/x 那一侧也必须回指 zh-CN,否则搜索引擎会忽略这组关系。三个细节常导致失效:① 用的 URL 带查询参数或缺少尾部斜杠,与实际 canonical 不一致;② 写了 x-default 但没指向任何真实版本;③ 相对 URL 与绝对 URL 混用。

  • Accept-Language 的 q 值决定优先级而非质量

    q=0.9 表示偏好度而不是「这个语言有 90% 的质量」。q=0 是显式排除,不是省略。真实场景里浏览器会发送一长串语言(连 q=0.05 的小语种也有),服务端应当解析前几个高 q 值做匹配,而不是拿整个列表当过滤器——否则一个含 30 种语言的请求会命中一条你没准备好的翻译。

  • 语言代码与地区变体混用会造成路由错配

    zh 与 zh-CN 都能表示中文,但不是同一个值:前者是 macrolanguage,后者特指大陆简体。同理 en 覆盖全部英语区,en-US / en-GB / en-AU 在拼写、日期、数字格式上差异真实存在。若 URL 设计成 /en/ 而内容里写 en-US,链接会指向一个不存在的路由。设计路由时语言段要统一用 ISO 639-1 两字母,地区信息放在查询参数或独立段落。

与相邻内容的分工

要查字符层面的编码方案(UTF-8、GBK、Shift-JIS 怎么把字符变成字节),用站内「字符编码」页;本页是语言标签(BCP 47 / ISO 639)层面的标识。

地区与国家代码(ISO 3166)、货币代码(ISO 4217)不在本页范围,站内另有对应速查页。

需要把日期、数字按目标语言格式化,用 Intl.DateTimeFormat / Intl.NumberFormat 配合本页的语言代码;本页不提供格式化实现。

若目的是让搜索引擎正确识别多语言站点的页面归属,hreflang 关系比 lang 属性更关键,且需双向互指。

实战片段

要点:① lang 是可继承属性,混排片段必须单独标注,否则屏幕阅读器会用整页语音读外语段落;② hreflang 必须双向互指且 URL 与 canonical 完全一致(含尾部斜杠),x-default 要指向真实存在的那一版;③ Accept-Language 的 q 是偏好度不是质量,q=0 是排除不是省略,解析时只取前几个高 q 值并归一到两字母,否则长列表会命中没准备的翻译。

<html lang="zh-CN">
  <head>
    <link rel="alternate" hreflang="zh-CN" href="https://oltool.net/reference/language-codes.html">
    <link rel="alternate" hreflang="en"    href="https://oltool.net/en/reference/language-codes.html">
    <link rel="alternate" hreflang="x-default" href="https://oltool.net/reference/language-codes.html">
  </head>
  <body>
    <p>中文正文,浏览器会选中文语音朗读。</p>

    <!-- 混排片段单独标注,否则会被整页 lang 覆盖 -->
    <p>
      参考 ISO&nbsp;639-1,
      <span lang="en">the two-letter code list</span>
      共收录 184 种语言。
    </p>
  </body>
</html>

<!-- 解析 Accept-Language:只取前几个高 q 值,不要拿全表当过滤器 -->
function negotiate(header?: string | null): string {
  const raw = (header ?? '').split(',').map(part => {
    const [tag, ...params] = part.trim().split(';')
    const q = params.find(p => p.trim().startsWith('q='))
    return { tag: tag.trim(), q: q ? Number(q.split('=')[1]) : 1 }
  })
  return raw
    .filter(x => x.q > 0 && x.tag !== '*')   // q=0 是显式排除
    .sort((a, b) => b.q - a.q)
    .slice(0, 3)                            // 只匹配前 3 个,其余可能没有翻译
    .map(x => x.tag.split('-')[0])           // 归一到 ISO 639-1 两字母
    .join(',') || 'en'
}

实践注解

  • ISO 639-1 与 639-2/3 的粒度不同639-1 是两字母(zh、en),639-3 覆盖到方言级(cmn 官话、yue 粤语)。中文场景里 zh 与 zh-Hans/zh-Hant 也不是同一层级:前者是语言,后者带文字系统。
  • BCP 47 的取值顺序有约定俗成zh-Hans-CN 依次是语言-文字-地区。只写 zh 时,字体选定、排序规则都要靠运行环境猜测,跨系统结果不一致;面向简体用户应显式写 zh-Hans。
  • 内容协商别只看 Accept-Language 的第一个值它带 q 权重且可能列出用户看不懂的语言。服务端应按权重排序并与已有译文求交集,全都不可用时回退到默认语言,而不是机械取首项。

数据来源

  • ISO 639-1 / 639-2 / 639-3
  • IETF BCP 47 (RFC 5646)
  • IANA Language Subtag Registry

上述编号、名称与定义均来自公开规范,本站不主张对规范数据本身的独创性;本页的编排方式、中文释义与实践注解由本站撰写。

ISO 639-1语言(中)语言(英)
zh中文Chinese
en英语English
es西班牙语Spanish
fr法语French
de德语German
ja日语Japanese
ko韩语Korean
ru俄语Russian
pt葡萄牙语Portuguese
it意大利语Italian
ar阿拉伯语Arabic
hi印地语Hindi
nl荷兰语Dutch
sv瑞典语Swedish
pl波兰语Polish
tr土耳其语Turkish
vi越南语Vietnamese
th泰语Thai

常见问题

ISO 639-1 和 ISO 639-2 有什么区别?

639-1 是两字母代码(如 zh、en),覆盖最常用的约 180+ 种语言,最常用于网页 lang 属性与 API。639-2 是三字母代码(如 zho、eng),覆盖更全、含更多濒危语言,常用于图书馆与文献编目。

Accept-Language 请求头怎么用?

客户端在请求里带 Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,服务端据此挑选最近的语言返回,权重 q 表示优先级。多语言站点应读取它做内容协商(配合 cookie/URL 让用户可覆盖)。

zh-CN 和 zh-TW 是 ISO 639 代码吗?

不是。zh 是 ISO 639-1 的语言码,CN/TW 是 ISO 3166 的地区码;"zh-CN"/"zh-TW" 是「语言-地区」组合,用于区分简体/繁体与区域习惯,但地区部分来自国家代码标准而非语言标准。

如何表示方言或地区变体(如 en-US、pt-BR)?

用「语言码-地区码」格式:语言取 ISO 639-1,地区取 ISO 3166-1 Alpha-2。en-US=美式英语,pt-BR=巴西葡萄牙语。地区部分可选,用于日期/货币/措辞本地化。