news 2026/9/14 18:12:39

OpenProject 配置目录国际化规范:i18n-tasks 工作流与 Crowdin 翻译管理实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
OpenProject 配置目录国际化规范:i18n-tasks 工作流与 Crowdin 翻译管理实战

OpenProject 配置目录国际化规范:i18n-tasks 工作流与 Crowdin 翻译管理实战

【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject

导读

OpenProject 作为覆盖项目管理、敏捷看板与组合管理的开源软件,其界面文本支持数十种语言,而这背后是一套严格的“配置目录国际化(i18n)规范”。本文以仓库config/目录下的 AGENTS.md 约定为骨架,系统讲解 OpenProject 的翻译键约束、en.yml源文件编辑方式、Crowdin 社区翻译协作流程,以及i18n-tasks四个核心 CLI 命令的用法与底层原理,并结合仓库源码说明前端 JS 翻译、复数化兜底等关键实现,帮助开发者在参与 OpenProject 开发或自建多语言功能时快速上手。

一、总体约定:UI 字符串必须走翻译键

config/AGENTS.md首先确立了一条铁律:

UI strings must use translation keys (never hard-coded)

界面字符串一律使用翻译键(translation key),严禁硬编码。这条约束在仓库中随处可见:视图层通过t('...')/I18n.t(...)取键,例如 app/components/admin/backups/reset_token_dialog_component.html.erb 中的按钮文案,组件层则在 Ruby 中调用I18n.t。如此设计的目标是让“文本”与“逻辑”彻底解耦:任何新增的 UI 文案都必须在英文源文件中登记一个键,再由各语言文件提供对应翻译,从而保证语言切换、复数规则、无障碍标签等能力的一致性。

在组件开发层面,OpenProject 对 ViewComponent 的惰性查找(lazy lookup)做了专门适配。app/components/translations_override.rb 注释解释了原因:由于项目未使用 ViewComponent 自带的 sidecar 翻译文件,VC 4.0 的#translate会转发到I18n.translate,而项目依赖 ActionView 的覆盖实现来支持组件内的惰性键解析,因此该模块显式include ActionView::Helpers::TranslationHelper。这意味着组件内的t('.some_key')相对键能够按“组件路径 + 方法名”正确解析(参见 config/i18n-tasks.yml 中关于relative_rootsrelative_exclude_method_name_paths的配置)。

二、英文源文件:可以直接修改的en.yml

文档规定,源翻译存放在**/config/locales/en.yml中,可以直接修改。这里的**通配符覆盖两层含义:

  1. 核心仓库:config/locales/en.yml 是主英文翻译文件,包含约 6000 余条键,覆盖 accessibility、activerecord、work_package、project 等全部命名空间;
  2. 各功能模块:OpenProject 以模块化方式组织代码,29 个模块各自维护独立的config/locales/en.yml,例如 modules/storages/config/locales/en.yml(文件存储模块)、modules/meeting/config/locales/en.yml 等。这也是 config/i18n-tasks.yml 中data.read读取来源的一部分。

因此新增或修改英文文案时,先定位该功能所属的模块目录,再编辑对应en.yml;根目录的config/locales/en.yml则承载核心应用文案。

三、其他语言:统一交给 Crowdin 管理

与英文源文件不同,其他语言的翻译统一由 Crowdin 管理,开发者不应手工编辑config/locales/crowdin/下的 165 个语言文件(涵盖 af、ar、az、de、fr、ja、zh 等)。仓库 crowdin.yml 定义了与 Crowdin 平台的同步配置,这一工作流带来的收益是:翻译由社区译者分布式完成,且版本回退、词条一致性检查都在平台侧完成。

仓库中与 Crowdin 配套的脚本位于 script/i18n/:

  • generate_seeders_i18n_source_file:把种子数据(seeds)中的默认内容(如颜色名、默认状态名)抽成可翻译的源文件,文件头明确标注“This file has been generated … Please do not edit directly”,见 config/locales/crowdin/de.seeders.yml;
  • rewrite_crowdin_yml_files/fix_crowdin_pt_language_root_key:处理 Crowdin 下载产物中的键根节点等格式问题;
  • generate_languages_translations:基于 CLDR 数据(代码中CLDR_VERSION = 44)生成本地化语言元数据;
  • test_seed_all_locales:批量校验所有语言环境下种子数据的可加载性。

此外,config/locales/generated/存放生成产物(en.ymlde.yml等按语言聚合的文件),config/locales/js-en.yml 则是前端 JS 用的英文翻译源。整体目录分工可归纳为:

目录/文件角色编辑方式
**/config/locales/en.yml英文源翻译(含各模块)开发者直接修改
config/locales/crowdin/*.yml各语言社区翻译仅通过 Crowdin 平台
config/locales/generated/*.yml生成/聚合产物脚本生成,勿手改
config/locales/js-*.yml前端 JS 翻译源按需更新英文源

四、i18n-tasks 四件套:检查、清理与归一化

文档给出了开发者在提交翻译改动前必须运行的四个命令,全部基于i18n-tasks这个 Ruby gem(依赖声明见 Gemfile,版本约束为~> 1.1.0require: false按需加载):

bundle exec i18n-tasks missing # Show missing translation keys bundle exec i18n-tasks unused # Show unused translation keys bundle exec i18n-tasks normalize # Fix/normalize translation files bundle exec i18n-tasks check-consistent-interpolations # Check interpolation consistency

1.missing:找出缺失的翻译键

扫描代码中所有翻译调用,对照各语言文件找出缺失的键。工具的搜索范围与规则在 config/i18n-tasks.yml 中定义:

  • search.paths:默认搜索app/,当前配置额外加入了modules/storages/app/(模块内代码同样纳入检查);
  • exclude:排除app/assets/imagesapp/assets/fontsapp/assets/videosapp/assets/builds等非代码资源目录;
  • strict模式(默认 true)下,t("categories.#{category}.title")这类动态拼接会被识别为“猜测用法”,从而避免误报。

2.unused:找出未使用的翻译键

用于发现已被代码移除、但仍残留在语言文件中的键。为避免误报,config/i18n-tasks.yml 配置了ignore_unused白名单,例如:

ignore_unused: - 'activerecord.{models,attributes,errors}.*' - 'permission_*' - '{devise,kaminari,will_paginate}.*' - '*.permission_header_explanation' - 'storages.upsell.*' - 'services.*' - 'storages.health.checks.*'

这些键要么由 Rails 框架按约定动态查找(如activerecord.attributes.*对应User.human_attribute_name(:email)),要么由权限/服务等反射式机制使用,静态扫描无法定位,因此需要显式豁免。

3.normalize:归一化翻译文件

对 YAML 文件做排序、键结构调整,保证多语言文件结构一致,避免合入 Crowdin 后产生大量无意义 diff。归一化遵循 config/i18n-tasks.yml 的data.write路由规则,例如 storages 模块的键会被强制写入modules/storages/config/locales/%{locale}.yml,其余键走config/locales/%{locale}.yml的 catch-all 规则;YAML 写入时设置line_width: -1(不自动换行,见第 43-46 行)。normalize -p变体可强制按规则搬移键。

4.check-consistent-interpolations:校验插值一致性

检查同一个键在不同语言中的插值占位符(如%{name}%{descendants})是否一致。若英文写作%{name}: %{description}(见 config/locales/en.yml 中accessibility.macro.aria_label_with_name),而某语言漏掉%{description},运行时就会出现KeyError或渲染异常,该命令在 CI/提交前拦截这类问题。如确有例外可配置ignore_inconsistent_interpolations

提示:i18n-tasks 本身也在 config/i18n-tasks.yml 中通过PatternMapper注册了自定义扫描器,用来识别项目特有的link_translate("some.key", ...)辅助方法调用——这类调用因未走标准t()/I18n.t()而无法被默认扫描器捕获。这意味着项目内所有翻译入口都纳入了同一套静态检查体系。

五、运行时兜底:复数化与回退机制

翻译键的正确性不仅依赖静态检查,还依赖运行时的健壮性设计。config/initializers/i18n.rb 展示了两个关键增强:

  1. 复数化兜底:加载lib/open_project/translations/pluralization_backend.rb定义的PluralizationBackend,并includeI18n::Backend::Simple。该模块(pluralization_backend.rb)覆写pluralize方法:当俄语、匈牙利语、波兰语等东欧语言缺少:many复数键触发I18n::InvalidPluralizationData异常时,安全回退到:other键;若无:other则返回 nil,表现为“缺失翻译”而不是直接抛异常——避免单个语言文件缺陷拖垮整个请求;
  2. 默认语言回退include I18n::Backend::Fallbacks为未翻译的字符串回退到默认语言(base_locale: en)。注释特别指出,管理员配置的邮件头/邮件尾(Setting#localized_emails_header/Setting#localized_emails_footer)可能未提供所有语言版本,必须依赖该回退机制。

六、前端 JS 翻译:从 YAML 到 JSON 的自动化管线

OpenProject 的 Angular 前端同样使用翻译键,其英文源为 config/locales/js-en.yml,而输出映射规则定义在 config/i18n.yml(注意:该文件只控制前端 i18n-js 的翻译):

embed_fallback_translations: enabled: true translations: - file: "frontend/src/locales/:locale.json" patterns: - '*.js.*' - '*.number.*' - '*.time.*' - '*.date.*'

即只有js.*number.*time.*date.*四类命名空间的键会被打包进前端产物 frontend/src/locales/,并以<locale>.json形式输出,且启用回退翻译嵌入。config/initializers/i18n-js.rb 进一步说明:开发模式下应用启动后会调用I18nJS.listen,持续监听根目录config/locales及所有模块的**/config/locales目录,翻译文件一有改动即自动重建 JS 翻译,实现热更新式的前端多语言开发体验(frontend/src/locales/README.md 也说明该目录存放开发/生产环境生成的翻译,并指向项目翻译贡献指南)。

七、提交前检查清单

结合上述约定,一个完整的“新增 UI 文案”开发流程应为:

  1. 在对应模块或根目录的config/locales/en.yml中添加英文键(如some_feature.title: "...");
  2. 运行bundle exec i18n-tasks missing确认代码中引用的键已全部登记;
  3. 运行bundle exec i18n-tasks normalize归一化文件结构;
  4. 运行bundle exec i18n-tasks check-consistent-interpolations校验插值一致性;
  5. 运行bundle exec i18n-tasks unused清理废弃键;
  6. 将新英文键通过 crowdin.yml 同步到 Crowdin 平台,等待社区译者补充各语言翻译;
  7. 前端若需要显示该文案,确认键位于js.*等白名单命名空间,开发模式下由监听进程自动产出frontend/src/locales/:locale.json

结语

OpenProject 的国际化并非零散地“在代码里写字符串”,而是一套从“禁止硬编码”的编码规范、en.yml源文件与 Crowdin 协作分工、i18n-tasks静态检查,到复数化与回退兜底、前端 JSON 自动生成的完整工程体系。理解 config/AGENTS.md 这份简短约定背后的实现细节,能帮助贡献者以最低成本、最高质量地向这一多语言开源项目提交翻译相关改动。

【免费下载链接】openprojectOpenProject is the leading open source project management software for product, project and portfolio management. A powerful Jira alternative with agile planning, issue tracking, roadmaps, Gantt charts, time tracking, collaboration features, and more. Available on premises or in the cloud. ⭐ Star us on GitHub项目地址: https://gitcode.com/GitHub_Trending/op/openproject

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 18:11:25

LIMS系统如何解决实验室数据管理难题

1. 实验室数据管理的现状与挑战 实验室数据管理长期以来面临着从传统手工记录向数字化系统转型的迫切需求。记得三年前我参与某化工企业实验室调研时&#xff0c;看到实验员们还在使用纸质记录本&#xff0c;各种颜色的便利贴贴满操作台&#xff0c;重要数据分散在Excel表格、纸…

作者头像 李华
网站建设 2026/9/14 18:10:39

内景 楼梯艺术画廊场景模型

本项目为前几天收费帮学妹做的一个项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 楼梯艺术画廊场景模型 地址&#xff1a;本地PC端运行&#xff08;或WebGL端部署链接…

作者头像 李华
网站建设 2026/9/14 18:10:37

提示词工程实战:10个降低大语言模型猜测成本的技巧与模板

不用把它想得太玄。我在日常项目里折腾提示词也有几年了&#xff0c;刚入门的时候一度以为这是门“语言艺术”&#xff0c;靠文采和花哨的措辞取胜。后来被真实业务连续教育了几次才明白&#xff0c;提示词工程本质是需求分析&#xff0c;是把模糊的意图翻译成模型能稳定执行的…

作者头像 李华
网站建设 2026/9/14 18:09:02

Linux内核设备树与电源管理核心技术解析

1. Linux内核源代码深度解析概述 作为一名在嵌入式领域摸爬滚打多年的工程师&#xff0c;我深知理解Linux内核源代码的重要性。内核就像一座精密的钟表&#xff0c;而设备树和电源管理则是其中两个最关键的齿轮组。设备树&#xff08;Device Tree&#xff09;作为硬件描述的标准…

作者头像 李华
网站建设 2026/9/14 18:08:36

移动储能系统在配电网韧性提升中的优化策略

1. 项目背景与核心价值 在电力系统领域&#xff0c;配电网作为连接输电网与终端用户的关键环节&#xff0c;其可靠性直接关系到供电质量。近年来&#xff0c;随着极端天气事件频发和分布式能源大量接入&#xff0c;传统配电网面临前所未有的挑战。移动储能系统&#xff08;Mobi…

作者头像 李华
网站建设 2026/9/14 18:08:27

部署 keep:开源告警管理平台从本地体验到生产落地的完整路径

部署 keep&#xff1a;开源告警管理平台从本地体验到生产落地的完整路径 【免费下载链接】keep The open-source AIOps and alert management platform 项目地址: https://gitcode.com/GitHub_Trending/kee/keep keep 告警管理平台把多来源的告警统一接进来&#xff0c;…

作者头像 李华