Angular 本地化数据生成工具 generate-locales-tool:CLDR 驱动的 locale 文件管线全解析

发布时间:2026/9/10 4:17:18
Angular 本地化数据生成工具 generate-locales-tool:CLDR 驱动的 locale 文件管线全解析 Angular 本地化数据生成工具 generate-locales-toolCLDR 驱动的 locale 文件管线全解析【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular导读packages/common/locales/generate-locales-tool/是 Angular 仓库中负责将 Unicode CLDRCommon Locale Data Repository通用区域设置数据仓库数据转换为框架可用的 TypeScript locale 文件的生成工具。本文以该工具的 README 为骨架结合其目录下的源码实现完整讲解 Angular 内部 locale 数据的三大文件集划分、默认 localeen的定位、基础货币数据文件的生成逻辑、普通 locale 文件的数组结构与性能优化手段以及 CLDR 数据通过 Bazel 仓库注入的工程机制。读完本文你将理解 Angular 的 locale 数据从 CLDR 原始数据到angular/common/locales中每个xx.ts文件的完整链路以及框架侧如何通过LocaleDataIndex按索引读取这些数据。Angular 的国际化数据三大文件集Angular 的国际化i18n完全依赖 CLDR 提供的区域数据。该工具将 locale 数据拆分为三类文件集分工明确、各司其职angular/core内的默认 locale 文件即locale_en.ts为enlocale 提供数据是本地开发中最常使用的 locale。基础货币信息文件位于angular/common/src/i18n基于默认 locale 生成记录各货币代码如USD对应的符号、窄符号与小数位。普通 locale 文件即angular/common/locales下按语言生成的各类 locale 数据包含日期、复数、货币等信息。工具目录下的 bin/ 子目录提供了对应这些输出文件的多个入口脚本包括get-base-currencies-file基础货币文件、get-base-locale-file默认 locale 文件、get-closure-locale-fileClosure 格式文件以及write-locale-files-to-dist批量写全部 locale 文件其 Bazel 标签统一在 packages/common/locales/index.bzl 中注册。默认 locale 文件angular/core中的locale_en.ts默认 locale 文件位于angular/core包内为enlocale 提供国际化数据。该文件在生成逻辑上与angular/common/locales下生成的其他 locale 文件并无本质区别只是被放置在 core 包中以满足本地开发场景的默认需求因此其细节可参照下文locale 文件章节理解。基础货币信息angular/common/src/i18n中的职责分离angular/core并不提供处理货币的指令或语法货币格式化属于angular/common的 i18n 能力例如currency管道。正是这种关注点分离的设计决定了core中的默认 locale 不包含任何货币信息而货币数据以独立文件形式存放在angular/common/src/i18n下。货币数据的结构约定基础货币信息以对象形式存储每个货币代码如USD映射到一个数组数组依次描述符号、窄符号、小数显示位数const baseCurrencies { CAD: [CA$, $, 2], NZD: [NZ$, $], USD: [$], };上述示例中NZD缺少第三项、USD缺少窄符号这并非疏漏而是有意为之USD的窄符号就是$本身无需再显式指定小数位同理。工具不为冗余信息设置显式值以节省字节byte savings。源码中的生成逻辑这一约定在 locale-base-currencies.ts 的generateBaseCurrencies函数中有精确实现符号读取自localeData.main(numbers/currencies)窄符号取自symbol-alt-narrow字段仅当symbol存在且与货币代码不同时才写入符号仅当窄符号存在且与符号不同时才写入窄符号第 48-61 行小数位数取自supplemental/currencyData/fractions中的_digits仅在存在时追加并根据已有数组长度按位补齐undefined占位第 62-71 行。生成的数组类型被定义为联合类型BaseCurrencySymbols[string]、[string | undefined, string]、[string, undefined, number]或[string | undefined, string, number]即允许按需省略窄符号或小数位。最终文件导出CURRENCIES_EN常量locale-base-currencies.ts 第 33 行框架侧通过CurrencyIndex枚举Symbol 0、SymbolNarrow 1、NbOfDigits 2读取数组各位置该枚举定义在 packages/core/src/i18n/locale_data_api.ts 第 174-178 行。locale 文件CLDR 数据的框架化组织除默认 localeen单独生成外该工具为 CLDR 提供数据的其余所有 locale 逐个生成 locale 文件。一个 locale 文件目前承载以下数据日期时间设置描述日期如何格式化例如周一在特定 locale 下的标签数字设置描述数字如何格式化例如正号plus symbol是什么字符货币设置描述当前 locale 下货币的格式化方式货币符号基于给定 locale 的货币符号映射例如在en-AU中USD对应的符号文字方向性文本按 RTL 还是 LTR 显示。数组化存储与按索引读取所有数据被组织进一个数组框架通过对应的索引读取特定数据。索引定义在 packages/core/src/i18n/locale_data_api.ts 的LocaleDataIndex中共 22 个槽位索引名称内容0LocaleIdlocale 标识1DayPeriodsFormat日周期格式用2DayPeriodsStandalone日周期独立用3DaysFormat星期名称格式用4DaysStandalone星期名称独立用5MonthsFormat月份名称格式用6MonthsStandalone月份名称独立用7Eras纪元名称8FirstDayOfWeek每周第一天9WeekendRange周末范围10DateFormat日期格式11TimeFormat时间格式12DateTimeFormat日期时间格式13NumberSymbols数字符号14NumberFormats数字格式15CurrencyCode当前货币代码16CurrencySymbol当前货币符号17CurrencyName当前货币名称18Currencies全部货币符号映射19Directionality文字方向rtl/ltr20PluralCase复数规则函数21ExtraData附加数据额外日周期等值得注意的实现细节LocaleDataIndex刻意使用const对象而非 TSenum其注释说明原因是 TS 枚举会编译为 IIFE 副作用、即使未被使用也无法被 tree-shakelocale_data_api.ts 第 132-136 行。数组的组装顺序locale-file.ts 中的generateBasicLocaleString展示了数据数组的精确拼装顺序第 39-60 行[locale, ...dateTimeTranslations, ...dateTimeSettings, ...numberSettings, ...currencySettings, currencies, directionality, plural]其中getDateTimeTranslations产出日周期、星期、月份、纪元的 format/stand-alone 名称每类按[narrow, abbreviated, wide, short?]排列locale-file.ts 第 143-222 行getDateTimeSettings产出[firstDayOfWeek, weekendRange, dateFormats, timeFormats, dateTimeFormats]其中格式各含[short, medium, long, full]第 75-81 行、第 229-244 行getNumberSettings产出数字符号与格式两组数组符号数组按decimal, group, list, percentSign, plusSign, minusSign, exponential, superscriptingExponent, perMille, infinity, nan, timeSeparator排列并在 locale 定义了货币专用符号时追加currencyDecimal/currencyGroup第 91-121 行getDirectionality依据scriptMetadata/{script}/rtl是否为YES返回rtl或ltr第 66-69 行复数函数通过getPluralFunction生成见下文。复数函数的生成与压缩plural-function.ts 使用cldr包的extractPluralRuleFunction从 CLDR XML 数据中提取各语言按解析后的 bundle 名的 cardinal 复数规则函数然后做三类压缩由于生成的函数只接收数字删除n Number(val)与isNaN(n)校验逻辑第 36-37 行用数字字面量替换字符串返回值且必须与angular/common的Plural枚举取值对应zero→0、one→1、two→2、few→3、many→4、other→5注释明确指出不直接引用枚举是为了避免对该包产生依赖第 40-47 行XML 数据在模块加载时解析一次避免每次调用重复解析第 13-18 行。附加数据extra文件除主 locale 文件外工具还为每个 locale 生成extra/locale.ts附加数据文件locale-extra-file.ts。普通 locale 文件默认只含通用AM/PM日周期而 extra 文件承载更细分的日周期名称与规则如noon、midnight、morning1、afternoon1等其数组结构与 locale_data_api.ts 的ExtraLocaleDataIndex对应ExtraDayPeriodFormats、ExtraDayPeriodStandalone、ExtraDayPeriodsRules。相关日周期规则与继承逻辑实现在 day-periods.ts 中getDayPeriodRules会按supplemental/parentLocales沿父级语言回溯继承如 CLDR v39 起nn完全继承自no第 69-78 行同时代码还处理了dayPeriods与dayPeriodRules键不一致的边缘情况CLDR v41 的hi-Latn受影响见代码内追踪的 CLDR-15563。性能优化省略冗余数据与数组去重工具内置两层性能优化目标是尽可能压缩生成的 locale 文件体积第一层省略与基础货币一致的数据由于angular/common/src/i18n已包含默认 locale 的货币符号对于某个 locale 内与基础货币数据一致的货币工具直接省略让框架回退使用默认 locale 的货币符号避免重复数据。该逻辑位于 locale-currencies.ts 的generateLocaleCurrencies逐一比较每个货币的符号与窄符号是否与baseCurrencies中的对应项相同相同则直接return跳过该货币第 37-47 行。同文件中的getCurrencySettings则负责找出该 locale 地区当前流通的货币依据supplemental/currencyData/region查找_from存在且_to缺失的条目产出[currencyCode, symbol, displayName]三元组找不到时会抛出Unable to find currency for locale错误第 57-94 行。第二层数组级去重用undefined指代前值如果某段 locale 数据与前一个索引的数据相同生成工具不再重复写出该数据而是置为undefined框架在读取时会自动回退到前一个值。以文档中的示例[ // ... labelsForDayPeriodsNarrow, labelsForDayPeriodsAbbreviated, ];若labelsForDayPeriodsAbbreviated与labelsForDayPeriodsNarrow相同工具便不为其设置值最终压缩为[labelsForDayPeriodsNarrow, undefined]。该机制的实现位于 array-deduplication.ts 的removeDuplicates通过JSON.stringify比较相邻元素相同则推入undefined否则保留原值数组首个元素恒为有值。可选的shouldTrim参数会进一步裁剪数组尾部的undefined第 28-44 行、第 46-52 行。文件注释同时强调去重依赖于含义相近的数据分组存放这一前提因此工具始终按语义分块如月份与星期分开构造数组。最后的体积压缩undefined替换为u在generateLocale与generateLocaleExtra的最后一步字符串化结果中的所有undefined会被替换为常量标识u文件中const u undefined;使数组体积进一步缩小locale-file.ts 第 52-54 行、locale-extra-file.ts 第 18-24 行。例如[x, y, undefined, z, undefined, undefined]最终变为[x, y, u, z, u, u]。CLDR 数据的来源与工程集成通过 Bazel 仓库注入 CLDR 数据CLDR 数据通过 Bazel 仓库拉取工具通过cldr_json_data与cldr_xml_data两个 Bazel 仓库解析所需数据视所需数据格式而定。CldrData类cldr-data.ts读取运行环境变量JS_BINARY__RUNFILES与CLDR_JSON_DATA_RUNFILES_PATH定位数据目录并通过受限的 glob 列表加载 JSON 文件cldr-data.ts 第 19-24 行cldr-core/scriptMetadata.json cldr-core/supplemental/*.json cldr-dates-full/main/**/*.json cldr-numbers-full/main/**/*.json之所以有意限制 glob是因为加载未使用的数据会显著拖慢生成过程本地开发重新生成 locale 数据时尤为明显。加载的 JSON 随后被填充进cldrjs库getLocaleData通过new cldrjs(localeName)实例化并校验 bundle 是否存在缺失时返回nullcldr-data.ts 第 76-89 行。CldrData还从availableLocales.json读取全部可用 locale、从aliases.json读取语言别名如deprecated、macrolanguage等别名原因类型定义于 cldr-data.ts 第 50-55 行。Bazel 目标与文件生成入口packages/common/locales/index.bzl 定义了全套生成宏generate_base_currencies_file、generate_base_locale_file、generate_closure_locale_file与generate_all_locale_files。每个宏都通过js_run_binary调用对应入口脚本并统一标记no-remote-exec——注释说明原因CLDR 文件数量过多超出远程执行环境RBE的单次任务文件数上限。generate_all_locale_files会为每个 locale 生成三个文件locale.ts主数据、global/locale.js全局脚本、extra/locale.ts附加数据。工具自身的依赖cldr、cldrjs、tinyglobby等在 generate-locales-tool/BUILD.bazel 中声明。不再入库的生成文件locale 文件与默认货币文件不再是会进入 Git 仓库的源码文件这与旧版 Gulp 构建文件作为仓库内容提交不同。这一改动带来两个显著收益升级 CLDR 不再产生巨大 diff数据变更只体现在生成结果而非版本控制历史文件无法被手动篡改过去开发者可能直接手工改动 locale 文件而没有任何工具报错导致文件与 CLDR 不同步甚至损坏现在所有 locale 文件均由工具产出保证了数据一致性。小结从 CLDR 到框架运行时的完整链路纵观整个工具Angular 的 locale 数据管线可以概括为四个环节数据源Bazel 仓库提供 CLDR JSON/XML 原始数据由CldrData统一加载并交给cldrjs解析生成generate-locales-tool各模块按LocaleDataIndex定义的 22 个槽位拼装数组应用省略与基础货币一致的数据与相邻重复数据置undefined两级去重最后将undefined替换为u常量压缩体积注入通过index.bzl中的 Bazel 宏将生成结果写入angular/common/locales含extra/与global/默认 locale 与基础货币文件分别进入angular/core与angular/common/src/i18n消费框架运行时如formatDate、getCurrencySymbol、getNumberOfCurrencyDigits等 API按LocaleDataIndex/ExtraLocaleDataIndex索引读取数组未显式设置的值自动回退到前一个索引或默认 locale 的基础数据。这套设计以关注点分离 按索引存取 去重压缩为核心既保证了 locale 数据与 CLDR 源的严格同步又将包体积开销控制在最小。读者若需深入可继续研读工具目录下的 cldr-data.ts、locale-file.ts、locale-currencies.ts 与框架侧的 locale_data_api.ts以及 packages/common/locales/index.bzl 中的生成宏定义。【免费下载链接】angularDeliver web apps with confidence 项目地址: https://gitcode.com/GitHub_Trending/an/angular创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考