
简介面向Go语言开发者这份资源提供了完整的ISO 639-1语言代码列表涵盖两字符代码、英文名称与本地名称内置init函数实现快速读取可有效解决国际化开发中语言代码映射与检索不便的问题。压缩包共10个文件、约9KB核心为5个Go源码文件含初始化逻辑与测试代码另附Markdown文档、CI配置、Git忽略规则及License结构精简便于直接集成或学习。该资源已有921人学习使用适合需要处理多语言映射的Web应用、内容管理系统或基础库维护者。通过内置的Codes、Names、NativeNames、Languages四个列表读者无需手工维护数据即可便捷获取全部语言信息同时测试文件与文档能帮助快速理解API用法是轻量高效的i18n辅助工具。 做国际化开发这几年我几乎每天都要跟语言代码打交道。在项目里要判断用户浏览器语言、做多语言资源文件命名、给第三方平台传语言参数背后都绕不开一个基础标准——ISO 639-1。这个标准定义了一套两字母的语言代码比如 en 代表英语、zh 代表中文、ja 代表日语看起来简单但真用起来你会发现里面坑不少比如中文到底用 zh 还是 zh-CN葡萄牙语为什么有 pt 和 pt-BR 两套老系统里 iw 和 he 哪个才是希伯来语的正确代码。这篇就把 ISO 639-1 从定义到实战一次讲透给搞国际化、多语言系统、数据分析的同学一份能直接抄作业的完整指南。1. 内容整体设计与思路拆解1.1 ISO 639-1 到底是什么ISO 639-1 是国际标准化组织发布的语言代码标准用两个拉丁字母表示一种主要语言。它归属于 ISO 639 整个语言代码体系这套体系一共有六个部分其中 639-1 是最早也最普及的一套。打个比方如果语言是一辆辆车ISO 639-1 就像是给每辆车发的两字母车牌。它解决的问题很朴素世界上的语言上千种如果每个系统都用自己发明的写法比如英语写成 english、English、EN、eng那系统之间对接数据时就会乱成一锅粥。有了统一的代码大家只要认准 en 就是英语系统之间传参数就再也不会产生歧义。这套代码的覆盖范围大约是 184 个主流语言条目覆盖了全世界绝大多数人口使用的语言。为什么不是所有语言因为 639-1 的设计初衷是覆盖“主要语言”那些使用人数极少、或者已经消亡的语言由 ISO 639-2三字母代码和 ISO 639-3更完整的语言标识体系去兜底。这里要先建立一个概念ISO 639-1 是上层建筑里的核心子集不是全部。1.2 为什么在项目里必须用它我做过多语言站点的架构最深的体会是语言代码选型是一个前期省事、后期省命的事。如果项目初期不用 ISO 639-1而是用自定义语言标识比如用数字 1 表示英语、2 表示中文短期表结构看着简洁但等到要接第三方支付、地图、推送服务时你会发现每个平台都有自己的语言代码体系到时候要做一张巨大的映射表去转换而且极易出错。ISO 639-1 作为行业通用标准它的价值主要体现在三块通用性几乎所有主流操作系统、浏览器、第三方 API、前端框架都会原生遵循这套标准比如浏览器通过 navigator.language 返回的值就是 BCP 47 标签而 BCP 47 的核心组成部分之一就是 ISO 639-1 代码。稳定性代码一旦确定基本不会变动。这套标准从 1988 年发布以来虽然有过少量调整比如希伯来语的代码从 iw 改成了 he但整体格局非常稳定不用担心“过两年语言代码升级”这种事。可读性相比一串数字 IDen、fr、de 这样的人类可读代码在排查问题、查看日志、调试接口时都更直观看日志时一眼能看出是哪个语言的数据出了问题。1.3 项目里做语言代码管理的基本思路一个规范的项目里语言代码不应该散落在业务代码里到处硬编码。我一般会拆成三层来治理第一层是原始标准层直接依赖一份权威的 ISO 639-1 代码表通常来自 npm 包、GitHub 开源数据集或者 Unicode CLDR 的数据这一层保证代码的“合法性”。第二层是业务映射层因为实际业务需求往往比标准更复杂比如你做跨境业务需要区分繁体中文和简体中文虽然 ISO 639-1 只用 zh 表示中文但业务上需要 zh-Hant 和 zh-Hans 这样的扩展标签这一层就是做标准代码和业务代码之间的桥接。第三层是展示层负责把代码映射成用户看得懂的语言名称比如 en 要显示“英语”“English”还是“英文”取决于你产品界面的目标受众。这个分层思路不只是代码规范更是一种数据治理思维。语言代码看起来是小事但它是贯穿全系统的“主数据”一旦治理不好后期做数据统计、用户画像、内容分发都会出现裂缝。2. 核心细节解析与实操要点2.1 两字母代码的格式与归属规则ISO 639-1 的代码格式就是两个小写字母比如 ar阿拉伯语、de德语、es西班牙语、fr法语、ru俄语。这里要特别强调标准本身规定字母必须小写在 URL 路径、文件命名、请求参数里都要统一小写避免因大小写不一致导致匹配失败。在整套 ISO 639 体系中代码归属遵循“唯一性”原则一种语言在 639-1 里只能有一个代码一个代码也只能对应一种语言。但也存在部分重叠的情况比如中文在 639-1 里是 zh在 639-2 里同时存在 chi 和 zho 两个代码一个用于 terminological 用途一个用于 bibliographic 用途这个知识点在后面排查数据问题时非常有用。还要注意 639-1 里有少量“集体语言”代码最典型的就是 zh。它不是指某一种具体的中文方言而是涵盖官话、粤语、吴语、闽南语等整个汉语族。所以在做精细化运营时如果你要单独标识粤语的资源ISO 639-1 就满足不了需求需要下沉到 639-3 里的 yue 代码。2.2 语言代码与地区代码的组合逻辑真正的生产环境里单独用 en 或 zh 往往不够用因为同一种语言在不同地区有拼写和用词的差异。这就引出了 BCP 47 标签体系它的标准格式是“语言-地区”比如en-US美式英语en-GB英式英语pt-BR巴西葡萄牙语pt-PT欧洲葡萄牙语zh-CN简体中文中国zh-TW繁体中文台湾这里补充一个很多新手会搞错的知识点BCP 47 里的语言部分就是 ISO 639-1 的代码地区部分则来自 ISO 3166-1 alpha-2 标准。两者组合起来才是完整的语言标识。所以在设计多语言系统时资源文件的命名、cookie 里的语言标记、接口里的 lang 参数都应该支持“语言-地区”这种扩展格式而不是只支持两字母基础代码。还有一点需要留意部分地区代码的大小写有约定俗成的规范语言代码小写、地区代码大写en-US但实际匹配的时候应该不区分大小写因为 HTTP Accept-Language 头里可能出现各种大小写混合的写法。严谨的做法是在解析时统一转成小写或统一转成小写加连字符的规则再处理。2.3 使用 ISO 639-1 数据时要注意的边界问题我在实际项目里整理语言代码表时发现有几个边角问题特别容易被忽略第一种是“代码存在但资源缺失”。比如你的产品只做了英文和日文但用户浏览器设置为 fr系统正确的行为应该是回退到默认语言而不是直接报错。这需要在代码设计时就约定好 fallback 链。第二种是“同语言不同区域的资源复用”。比如 en-GB 和 en-US如果产品没有专门做英式英语的翻译应该允许 en-GB 回退到 en而不是直接当作不支持的语言。第三种是“标准代码与平台私有代码的冲突”。比如有些老平台用 zh 表示简体中文用 zh-TW 表示繁体但当你接入新的国际化服务时对方可能要求 zh-CN你要在映射层就把这些差异全部消化掉。做好这些边角逻辑比单纯引入一套 ISO 639-1 代码表重要得多。标准只是给了你一个正确的“地图”能不能开好车还得看你的业务逻辑怎么设计。3. 实操过程与核心环节实现3.1 在 Node.js 项目里集成 iso-639-1 库前端和后端项目中集成 ISO 639-1 数据最省事的方式是直接使用开源的 npm 包 iso-639-1。它封装了 136 种语言的代码、英文名称和原生名称并且提供了简洁的查询 API。安装的过程很简单在项目根目录执行npm install iso-639-1如果你用的是 Yarn 或者 pnpm对应的命令是yarn add iso-639-1 pnpm add iso-639-1装完之后在代码里引入并做基础查询import ISO6391 from iso-639-1; // 根据代码获取英文名称 console.log(ISO6391.getName(en)); // English // 根据代码获取原生语言名称 console.log(ISO6391.getNativeName(zh)); // 中文 // 获取所有支持的语言代码 const allCodes ISO6391.getAllCodes(); console.log(allCodes.length); // 136 console.log(allCodes.slice(0, 10)); // [aa, ab, ae, af, ak, am, an, ar, as, av] // 从名称反向查询代码 console.log(ISO6391.getCode(Chinese)); // zh这套 API 设计得很朴素但实际上踩过坑的人都知道朴素反而好维护项目里不需要仙人掌一样复杂的方法getCode 和 getName 两个方法已经覆盖了 90% 以上的日常需求。3.2 制作一份可用的语言下拉选择器在用户中心或设置页里语言切换是国际化产品的标准功能。基于 iso-639-1 库我可以直接生成一个按原生名称排序的语言下拉列表代码大概长这样import ISO6391 from iso-639-1; const supportedLanguages [en, zh, ja, ko, fr, de, es]; const options supportedLanguages .map(code ({ code, nativeName: ISO6391.getNativeName(code), englishName: ISO6391.getName(code) })) .sort((a, b) a.nativeName.localeCompare(b.nativeName, zh-Hans-CN)); // 渲染时在 select 里遍历 options这里有个很关键的设计细节排序规则要按原生名称排序还是按英文名称排序我建议在面向全球用户的产品里按原生名称排序因为德国用户看到 “Deutsch” 比看到 “German” 的识别速度更快。同时为了兼容某些地区的排序习惯需要用 localeCompare 并指定排序地区。如果项目里有“推荐语言”或“热门语言”的需求可以在数组头部用 unshift 插入额外配置比如把“简体中文”放在最前面并加一个“推荐”徽标。3.3 批量处理语言代码的典型场景除了简单的查询实际项目里还经常遇到批量转换的需求。比如导出用户语言分布报表需要把代码映射成可读名称或者对接邮件服务商时要把内部语言代码转换成对方要求的语言代码。我封装过这样一个工具函数import ISO6391 from iso-639-1; function normalizeLanguageCode(input) { if (!input) return ; // 去掉可能存在的地区后缀提取基础语言代码 const baseCode input.split(-)[0].toLowerCase(); // 对个别代码做兼容映射 const legacyMap { iw: he, in: id, ji: yi, jw: jv, sh: sr }; if (legacyMap[baseCode]) { return legacyMap[baseCode]; } // 验证是否是合法的 ISO 639-1 代码 return ISO6391.getAllCodes().includes(baseCode) ? baseCode : ; }这段代码解决了两个高频痛点一个是浏览器或老系统可能会返回带地区后缀的标签比如 zh-CN我们需要取前半部分另一个是有些老系统还在用废弃的代码比如 iw、in需要做兼容映射到新代码。用过一段时间后你会发现写语言代码的兼容逻辑跟处理时区一样本质上就是在做“旧世界”和“新世界”之间的翻译工作。遇到一个老系统传过来的语言代码第一步永远是查标准、查映射而不是想当然地按字面处理。3.4 前端展示语言名称的多语言适配iso-639-1 库本身提供的英文名称和原生名称能满足大部分场景但如果你的产品界面语言是法语、日语直接用 getNativeName 会带出一些奇怪的结果。更好的做法是在代码库之上叠加一层自己维护的翻译字典。比如产品界面是日文我需要把语言列表翻译成日语就维护一个对象const languageDisplayNames { en: 英語, zh: 中国語, ja: 日本語, ko: 韓国語, fr: フランス語, de: ドイツ語 };这个方案的灵活性最高因为产品的目标用户可能只需要 10 种语言选项而不是 136 种而且团队对语言名称的翻译有自己的一套标准比如“中文”和“汉语”的取舍这些都没法让第三方库替你做决定。4. 常见问题与排查技巧实录4.1 大小写和不规范代码导致匹配失败这是我在联调接口时遇到最多的一个问题。第三方平台返回的语言代码可能是 En、EN、en-US、zh_cn 等各种风格如果直接拿来做对象键查询极容易匹配不到数据。排查思路是在入口处统一清洗。不管是接收请求参数、读取 cookie、还是解析 Accept-Language 头一律先转小写、把下划线替换成连字符、按连字符切分取第一段再做后续处理。用一个统一的 normalize 函数处理所有入口能规避一大半诡异问题。下面是一个兼容多种写法的清洗函数function cleanLanguageCode(raw) { if (!raw) return en; // 默认语言兜底 return raw .trim() .replace(/_/g, -) .toLowerCase() .split(-)[0]; } console.log(cleanLanguageCode(ZH-CN)); // zh console.log(cleanLanguageCode(en_US)); // en console.log(cleanLanguageCode(fr-FR)); // fr这个函数极其简单但放到整个系统里能统一所有入口的语言代码格式让后续的业务逻辑不用重复处理脏数据。4.2 废弃语言代码的兼容处理ISO 639-1 历史上出现过几个代码更替最具代表性的是旧代码新代码对应语言更替原因iwhe希伯来语代码调整inid印度尼西亚语代码调整jiyi依地语代码调整jwjv爪哇语代码调整sh移除塞尔维亚-克罗地亚语语言拆分很多老系统的数据库里可能还存着旧代码如果不做兼容在对接时会发现某部分用户的语言数据“凭空消失”。建议在老系统升级或数据迁移时把这组映射关系固化到代码里而不是靠人工记忆。4.3 zh 和 cmn、wuu 这类代码的关系ISO 639-1 只有一个 zh 代表所有中文但在实际项目里我们会收到各种“中文变体”的代码比如 cmn官话、wuu吴语、yue粤语、nan闽南语。这些代码是 ISO 639-3 的条目在 639-1 体系里根本不存在。早期的做法是把 cmn、yue 等统一映射到 zh但后来做精细化运营的产品越来越多比如短视频平台要针对粤语用户推广东语内容这个时候的合理方案是UI 界面语言仍然用 zh-Hans、zh-Hant 这类粗粒度标签。内容语言标识用 zh、yue、nan 等细粒度代码存到内容元数据里。这样的区分会让系统更灵活既保证界面翻译的完整性又允许内容层做更细的差异化。4.4 语言代码与 Unicode 区域子标签的配合使用有同学会把 zh-Hans 误解为 ISO 639-1 的一部分其实 Hans简体中文并不是 ISO 639-1 的代码它是 Unicode CLDR 定义的“文字子标签”。完整的 BCP 47 结构是zh-Hans中文字符集-简体zh-Hant中文字符集-繁体zh-Hans-CN中文字符集-简体-中国在存储和传输时这三个层级要分清第一层是语言第二层是文字第三层是地区。系统设计时建议把三者的校验逻辑分开语言部分用 ISO 639-1 校验文字部分用 CLDR 合法值校验地区部分用 ISO 3166-1 alpha-2 校验。4.5 验证代码合法性时容易踩的坑用正则去判断“两个小写字母”是最简单的验证方式但这种方式会把 aa、zz 这种“不存在”的代码也当成合法代码。严谨的做法是用权威数据源给出的代码列表去校验比如 iso-639-1 包的 getAllCodes()。还有一个细节ISO 639-1 的代码是稳定的但不是完全“冻结”的标准委员会会不定期进行少量更新。所以在一个长期维护的项目里建议把语言代码数据作为依赖包定期升级而不是把一份 JSON 拷贝到项目里就再也不动。实在要拷贝也要在 README 里记录数据快照的版本和时间方便后续追溯。5. 实操心得与避坑建议最后说几点我做国际化项目时积累的个人经验。第一语言代码和语言资源文件要分开管理。代码是代码资源文件是资源文件两者不要混在一个配置里。代码表达的是“用户用的是哪种语言”资源文件表达的是“界面文案用哪套翻译”虽然它们通常是 1:1 对应但一旦出现资源缺失需要回退的场景混在一起会让你排查得很痛苦。第二所有涉及语言代码的外部接口都要在接入文档里写清楚“支持的代码列表”和“不支持时的回退策略”。我在对接推送平台时吃过亏对方文档写着支持 zh但实际传 zh 不生效传 zh-CN 才生效这种细节只能靠联调时一点点踩出来。第三线上日志里要记录原始语言标签和清洗后的代码。比如用户请求带的是 zh-Hant-TW经过系统清洗后变成 zh如果只记录清洗后的代码后面想排查繁体用户的行为数据就无从下手。保留原始值和加工值是数据可回溯的基本功。第四如果你做的是数据分析、用户画像系统建议在数仓建模时把语言代码建成维度表并且包含“标准代码、英文名、原生名、所属语系、是否 RTL从右到左书写”等字段。这样下游报表、推荐系统做语言维度分析时直接 join 维度表就行不用每个人各写一套翻译逻辑。ISO 639-1 看似简单但它是一个全球基础设施级别的标准。把它的来龙去脉、边界场景、兼容策略摸清楚你的国际化项目就能少走很多弯路。希望这篇实操笔记能帮你把语言代码这块地基打牢。本文还有配套的精品资源点击获取