Apache Airflow UI 国际化翻译实战指南:从 Locale 注册到 Breeze 完整性校验 Apache Airflow UI 国际化翻译实战指南从 Locale 注册到 Breeze 完整性校验【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow本篇指南基于 Airflow 仓库的翻译技能文档 SKILL.md 编写系统讲解如何为 Airflow UI 新增或更新界面翻译包括 locale 目录搭建、supportedLanguages与复数后缀等三处关键配置、breeze ui check-translation-completeness脚手架与校验命令、全局翻译规则术语保留英文、占位符、复数形式、热键并深入到 i18n 初始化代码 与 Breeze 校验命令源码 层帮助你独立完成一次可合并的 Airflow 界面本地化任务。一、任务判定新增翻译还是更新已有翻译翻译工作分为两类判定方法很简单检查目标语言的目录是否已存在于airflow-core/src/airflow/ui/public/i18n/locales/locale/下。目录已存在→ 走「更新已有翻译」流程本文第四节目录不存在→ 走「新增翻译」流程需要先完成三处配置文件更新本文第三节。当前仓库locales/目录下已包含 ar、ca、de、el、en、es、fr、he、hi、hu、it、ja、ko、nl、pl、pt、ru、th、tr、zh-CN、zh-TW 共 21 个语言目录其中en/是默认语言default locale也是所有翻译的唯一权威来源。二、翻译文件结构与 i18n 运行架构2.1 命名空间NamespaceJSON 文件所有翻译文件都是 JSON位于airflow-core/src/airflow/ui/public/i18n/locales/locale-name/每个语言目录包含一组与英文 localeen/镜像的命名空间 JSON 文件当前共 10 个admin.json、assets.json、browse.json、common.json、components.json、 dag.json、dags.json、dashboard.json、hitl.json、tasks.jsonSKILL 文档中这两个文件清单被包裹在!-- START namespace-files ... END namespace-files --注释之间说明该列表由工具自动同步更新新增命名空间文件后无需手动修改文档。以 en/common.json 为例可以看到嵌套 key、复数 key 与跨命名空间引用的典型形态{ admin: { Connections: Connections, Pools: Pools }, asset_one: Asset, asset_other: Assets, assetEvent_one: $t(common:asset_one) Event, assetEvent_other: $t(common:asset_one) Events, dag_one: Dag, dag_other: Dags }2.2 运行时如何加载翻译config.tsUI 前端基于i18next react-i18next i18next-http-backend i18next-browser-languagedetector构建。config.ts#L32-L54 中的supportedLanguages数组定义了 UI 语言切换器可展示的全部语言code 该语言自称的namedefaultLanguage固定为en。初始化逻辑config.ts#L116-L161有几个值得注意的设计语言检测顺序为[localStorage, navigator, htmlTag]即以用户手动选择localStorage 缓存优先其次浏览器语言最后html标签回退语言fallbackLng为en——任何缺失 key 或未支持的 locale 都回落到英文原文这也是「英文 locale 是所有翻译来源」这一约定得以成立的前提加载路径为${basePath}/static/i18n/locales/{{lng}}/{{ns}}.json?vversion?v参数通过VersionService.getVersion()获取 Airflow 版本号作为缓存破坏器cache buster避免 CDN/浏览器长期缓存旧翻译包导致新增 key 缺失config.ts#L158-L161convertDetectedLanguageconfig.ts#L79-L114是一个精细的浏览器语言归一化函数它按navigator.languages的顺序逐项把en-GB归约为en、pt-BR归约为pt对中文这类带地区变体的语言利用Intl.Locale.maximize()依据 CLDR 脚本推导把zh-HK/zh-Hant映射到zh-TW、zh-SG/zh映射到zh-CN从而避免zh-CN/zh-TW被粗暴剥离成不支持的zh。对翻译者的含义你新增的语言code必须与supportedLanguages中的 code 严格一致否则浏览器即使检测到该语言也不会加载对应的 JSON。三、新增一种语言翻译3.1 创建 locale 目录mkdir -p airflow-core/src/airflow/ui/public/i18n/locales/locale/3.2 在supportedLanguages中注册语言更新 airflow-core/src/airflow/ui/src/i18n/config.ts把语言加入supportedLanguages数组并保持数组现有的字母序{ code: locale, name: native name },name使用语言的自称写法例如{ code: ja, name: 日本語 }。3.3 配置复数后缀PLURAL_SUFFIXES更新 dev/breeze/src/airflow_breeze/commands/ui_commands.py在PLURAL_SUFFIXES字典中添加该语言的复数后缀ui_commands.py#L75-L97locale: [suffixes],后缀种类取决于语言的 i18next 复数规则差异非常大。从源码中现有的配置可以直接读到真实案例语言后缀说明ar阿拉伯语_zero,_one,_two,_few,_many,_other6 种复数形式pl波兰语_one,_few,_many,_other4 种形式es/fr西/法语_one,_many,_other3 种形式he希伯来语_one,_two,_other3 种形式it/pt意/葡语_zero,_one,_many,_other含_zeroja/ko/th/zh-CN/zh-TW仅_other无复数区分多数语言[\_one, \_other]源码中以MOST_COMMON_PLURAL_SUFFIXES常量复用若不确定目标语言需要哪些后缀SKILL 文档建议查阅 i18next 官方的复数规则演示工具jsfiddle demo确认。源码印证PLURAL_SUFFIXES不仅用于生成模板也是完整性校验的核心输入。expand_plural_keys 会把英文 locale 中每个复数基 key如dagRun_one按目标语言的后缀表展开成「必需 key 集合」若某语言在PLURAL_SUFFIXES中查不到后缀命令会直接报错退出并提示去 i18next 规则工具查询。此外该函数还会读取英文值中的{{count}}占位符与英文是否定义了多个复数形式来决定是否展开避免把语言特定的复数 key 误判为 unused——这正是 3.3 节配置必须准确的原因。3.4 配置 PR 自动打标.github/boring-cyborg.yml在 .github/boring-cyborg.yml 的labelPRBasedOnFilePath段落下按字母序添加translation:locale: - airflow-core/src/airflow/ui/public/i18n/locales/locale/*当前文件中已存在translation:default对应locales/en/*以及 ar 到 zh-TW 的完整语言打标规则boring-cyborg.yml#L413-L477。这样配置后涉及某个语言翻译文件的 Pull Request 会自动被贴上translation:locale标签便于维护者分发给对应的语言社区。3.5 用 Breeze 生成翻译脚手架三处配置就绪后执行breeze ui check-translation-completeness --language locale --add-missing该命令会把英文 locale 下每个命名空间文件的全部 key 复制到新语言目录每个值都填充为TODO: translate:前缀的英文原文桩stub{ allRuns: TODO: translate: All Runs, blockingDeps: { dependency: TODO: translate: Dependency, reason: TODO: translate: Reason } }源码印证add_missing_translations 的写入行为保证了几个工程细节——缺失 key 一律写成TODO: translate: 英文原文复数基 key 会按该语言后缀表一次性补齐所有形式写入前用natural_sort_key模拟 eslint-plugin-jsonc 的natural: true自然排序如2 10、忽略大小写主排序对字典递归排序保证 JSON key 顺序与前端 lint 规则一致文件以ensure_asciiFalse, indent2输出并补换行非 ASCII 字符中文、日文等原样落盘。四、翻译规则全局以下规则全局适用若目标语言存在 locale 专属指南见第六节且规定不同以语言指南为准。4.1 默认保留英文的术语术语保留原因Airflow产品名Dag/DagsAirflow 约定永远写作Dag绝不写作DAGXCom/XComsAirflow 跨任务通信机制名Provider/ProvidersAirflow 扩展包名REST API标准技术术语JSON标准技术格式名ID通用缩写PIDUnix 进程标识符UTC时间标准Schema数据库术语语言指南可针对存在成熟本地惯例的个别条目做覆盖例如中文指南要求「Dag 执行」这类中英混排时空格规则。4.2 变量与占位符翻译字符串使用 i18next 的{{variable}}插值格式。规则永不翻译、永不删除{{…}}内部的变量名占位符可以为符合目标语言语序而调整位置变量名的大小写必须原样保留如{{dagDisplayName}}不能写成{{dagDisplayname}}。4.3 复数形式Airflow 使用 i18next 复数后缀_one、_other以及按需的_zero、_two、_few、_many。你需要为该语言要求的所有后缀提供翻译——具体是哪几个由语言指南指定若尚无语言指南则查询 i18next 复数规则工具且至少要提供_one与_other。源码印证完整性校验通过 expand_plural_keys 把「英文 key 集合 语言后缀表 英文值是否含{{count}}」换算成该语言的必需 key 集合因此多交一个该语言不需要的后缀 key 会被判为 unused、少交一个则判为 missing。4.4 热键热键值如hotkey: e是字面按键绑定不应翻译除非语言指南另有规定。五、更新已有翻译当目标语言目录已存在需要补漏、修订或清理陈旧 key 时先读语言指南见第六节建立术语表与格式约定通读该语言现有 JSON学习既有术语。与既有翻译保持一致至关重要——某个词如果已经被翻译过必须复用那个确切的译法检查完成度现状breeze ui check-translation-completeness --language locale若有missing缺失key用桩补齐breeze ui check-translation-completeness --language locale --add-missing若有unused冗余key——即非必需 key英文 locale 中不存在或是该语言不需要的一种复数后缀形式——删除之breeze ui check-translation-completeness --language locale --remove-unused源码印证remove_unused_translations 会递归删除未要求 key并顺带删除递归后变空的字典避免留下空对象残骸随后同样执行自然排序并格式化重写。最后按语言指南翻译所有TODO: translate:条目连同前缀一起替换为目标语言译文然后进入第七节验证。六、Locale 专属指南翻译开始前应阅读目标语言对应的指南文件其中包含该语言的术语表glossary、语气规则与格式约定与全局规则冲突时以语言指南为准。SKILL 文档给出的指南索引以下路径已转换为仓库根目录相对路径Locale语言指南文件ar阿拉伯语locales/ar.mdca加泰罗尼亚语locales/ca.mdde德语locales/de.mdel希腊语locales/el.mdes西班牙语locales/es.mdfr法语locales/fr.mdhe希伯来语locales/he.mdhi印地语locales/hi.mdhu匈牙利语locales/hu.mdit意大利语locales/it.mdja日语locales/ja.mdko韩语locales/ko.mdnl荷兰语locales/nl.mdpl波兰语locales/pl.mdpt葡萄牙语locales/pt.mdth泰语locales/th.mdtr土耳其语locales/tr.mdzh-CN简体中文locales/zh-CN.mdzh-TW繁体中文locales/zh-TW.md若目标语言的指南文件尚不存在则只遵循 SKILL 文档中的全局规则。以 zh-CN.md 为例语言指南的典型内容深度包括复数规则简体中文不区分单复数_one与_other使用相同译文如dagRun_one: Dag 执行与dagRun_other: Dag 执行——注意这与PLURAL_SUFFIXES中zh-CN: [_other]的配置共同决定了校验行为空格规则中文与相邻英文、数字、符号之间插入半角空格正确示例Dag 执行、最近 12 小时、{{count}} 个连接错误示例Dag执行、最近12小时标点规则中文语境用全角标点。英文术语、JSON、代码内部用半角标点。七、验证翻译完成后依次执行两项检查。7.1 完整性校验breeze ui check-translation-completeness --language locale输出表应显示0 missing、0 TODOs、0 unused、100% Coverage。源码印证进度表由 print_translation_progress 生成逐文件统计「英文基础 key 数 / 复数展开 key 数 / 必需总数 / 已翻译数 / 缺失数 / 覆盖率 / TODO 数 / 冗余数」。其中「已翻译」的判定是 is_todo_value值以TODO: translate开头即计为未翻译TODO 计入 magenta 列而非 translated 列行颜色语义为——有 missing 红色、仅 TODO/unused 黄色、全部干净加粗绿色。若所有语言都不干净命令还会额外打印一张「Total Coverage per Language」汇总表与中位数覆盖率覆盖率 ≥95% 绿色、90% 黄色、其余红色。7.2 运行 pre-commit 钩子prek run --from-ref main --hook-stage pre-commit用于自动修复格式、许可证头、lint 等问题JSON 文件即依赖此环节做排序与格式化兜底。八、完整工作流速查新增语言以locale代指的端到端步骤mkdir -p airflow-core/src/airflow/ui/public/i18n/locales/locale/config.ts 的supportedLanguages追加{ code, name }字母序ui_commands.py 的PLURAL_SUFFIXES追加该语言后缀表boring-cyborg.yml 的labelPRBasedOnFilePath追加translation:locale规则breeze ui check-translation-completeness --language locale --add-missing生成TODO: translate:脚手架阅读语言指南第六节索引逐条翻译含 4.1–4.4 全局规则breeze ui check-translation-completeness --language locale确认 0 missing / 0 TODOs / 0 unused / 100%prek run --from-ref main --hook-stage pre-commit更新已有语言则跳过 1–5直接从「读指南 → 读现有译文保证术语一致 → 检查完成度 →--add-missing/--remove-unused→ 翻译 → 验证」开始。九、适用前提与限制本文所有命令基于当前仓库中 dev/breeze 与 airflow-core UI 源码 的实际实现breeze ui check-translation-completeness支持--language/-l、--add-missing、--remove-unused、--verbose、--dry-run选项ui_commands.py#L611-L637且对英文 locale 本身禁止做完整性检查命令会直接报错退出从 config.ts 的supportedLanguages看代码中还注册了ru俄语其复数后缀为[_one, _few, _other]但 SKILL 文档的指南索引表中暂无对应语言指南文件——从文档结构看该语言目前仅遵循全局规则namespaces常量config.ts#L57-L66与 locales 目录中的 JSON 文件清单存在细微差异例如tasks.json存在于 locales 目录而不在该常量列表中实际以en/目录下的文件为准——这正是「英文 locale 是所有翻译的主要来源」这一约定的落地方式。【免费下载链接】airflowApache Airflow - A platform to programmatically author, schedule, and monitor workflows项目地址: https://gitcode.com/GitHub_Trending/ai/airflow创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考