glebm/i18n-tasks

GitHub: glebm/i18n-tasks

一个基于静态分析的 Ruby i18n 翻译管理工具,用于检测、补全和清理项目中的多语言翻译键。

Stars: 2158 | Forks: 284

# i18n-tasks [![Build Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/634dec4ef6161621.svg)][ci] [![Coverage Status](https://api.codeclimate.com/v1/badges/5d173e90ada8df07cedc/test_coverage)][coverage] [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/glebm/i18n-tasks?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Stand With Ukraine](https://static.pigsec.cn/wp-content/uploads/repos/2026/05/770fc8666d161627.svg)](https://stand-with-ukraine.pp.ua/) i18n-tasks 可帮助你查找和管理缺失及未使用的翻译。 该 gem 会对代码中的键(key)用法进行静态分析(例如 `I18n.t('some.key')`),以便: - 报告缺失或未使用的键。 - 预填充缺失的键,可选择使用 Google Translate 或 DeepL(Pro 或 Free)进行翻译。 - 删除未使用的键。 从而解决 [i18n gem][i18n-gem] 设计中的两个主要问题: - 缺失的键只会在运行时报错。 - 不再使用的键可能会不断累积并带来额外开销,而你却毫不知情。 ## 目录 - [快速开始](#quick-start) - [命令](#commands) - [健康检查](#check-health) - [查找用法](#find-usages) - [添加缺失的键](#add-missing-keys) - [翻译缺失的键](#translate-missing-keys) - [移除未使用的键](#remove-unused-keys) - [修剪](#prune) - [规范化](#normalize) - [移动 / 重命名 / 合并键](#move--rename--merge-keys) - [删除键](#delete-keys) - [组合任务](#compose-tasks) - [配置](#configuration) - [语言环境](#locales) - [存储和语言环境文件](#storage--locale-files) - [Pattern 路由](#pattern-router) - [Conservative 路由](#conservative-router) - [Isolating 路由](#isolating-router) - [键模式语法](#key-pattern-syntax) - [自定义适配器](#custom-adapters) - [Rails 凭证](#rails-credentials) - [用法搜索](#usage-search) - [基于 Prism 的扫描器](#prism-based-scanner) - [微调](#fine-tuning) - [环境变量与 dotenv](#environment-variables--dotenv) - [翻译后端](#translation-backends) - [Google Translate](#google-translate) - [DeepL](#deepl) - [Yandex](#yandex) - [OpenAI](#openai) - [watsonx](#watsonx) - [功能与限制](#features--limitations) - [相对键](#relative-keys) - [复数键](#plural-keys) - [引用键](#reference-keys) - [动态键](#dynamic-keys) - [I18n.localize](#i18nlocalize) - [`t()` 关键字参数](#t-keyword-arguments) - [意外的规范化](#unexpected-normalization) - [高级](#advanced) - [交互式控制台](#interactive-console) - [CSV 导入 / 导出](#csv-import--export) - [添加自定义任务](#add-custom-tasks) - [开发](#development) ## 快速开始 i18n-tasks 可用于任何使用 ruby [i18n gem][i18n-gem](Rails 的默认配置)的项目中。 1. 添加到你的 `Gemfile` 中: gem 'i18n-tasks', '~> 1.1.2', group: :development 2. 复制默认的[配置文件](#configuration): $ cp $(bundle exec i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/ 3. 运行你的第一次健康检查: $ bundle exec i18n-tasks health 就是这样。请查看[命令](#commands)以获取所有任务的完整列表,或者查看[配置](#configuration)来针对你的项目调整设置。 **可选:** 复制一个在每次 CI 运行时检查缺失/未使用翻译的测试: ``` # RSpec $ cp $(bundle exec i18n-tasks gem-path)/templates/rspec/i18n_spec.rb spec/ # Minitest $ cp $(bundle exec i18n-tasks gem-path)/templates/minitest/i18n_test.rb test/ ``` ## 命令 运行 `bundle exec i18n-tasks` 获取所有任务的列表及简短描述。 ### 健康检查 `bundle exec i18n-tasks health` 会检查是否有任何键缺失或未被使用, 各语言环境中的插值变量是否一致, 以及所有的语言环境文件是否已规范化(自动格式化): ``` $ bundle exec i18n-tasks health ``` ### 查找用法 使用 `bundle exec i18n-tasks find` 查看键的使用位置: ``` $ bundle exec i18n-tasks find common.help $ bundle exec i18n-tasks find 'auth.*' $ bundle exec i18n-tasks find '{number,currency}.format.*' ``` ### 添加缺失的键 使用占位符添加缺失的键(基础值或人性化后的键名): ``` $ bundle exec i18n-tasks add-missing ``` 此命令及其他任务支持传递参数: ``` $ bundle exec i18n-tasks add-missing -v 'TRME %{value}' fr ``` 传递 `--help` 以获取更多信息: ``` $ bundle exec i18n-tasks add-missing --help Usage: i18n-tasks add-missing [options] [locale ...] -l, --locales Comma-separated list of locale(s) to process. Default: all. Special: base. -f, --format Output format: terminal-table, yaml, json, keys, inspect. Default: terminal-table. -v, --value Value. Interpolates: %{value}, %{human_key}, %{value_or_human_key}, %{key}. Default: %{value_or_human_key}. -h, --help Display this help message. ``` ### 翻译缺失的键 使用你选择的后端服务翻译缺失的键。 ``` $ bundle exec i18n-tasks translate-missing # 接受 backend、from 和 locales 选项 $ bundle exec i18n-tasks translate-missing --from=base es fr --backend=google ``` 可用的后端有: - `google` – [Google Translate](#google-translate) - `deepl` – [DeepL](#deepl) - `yandex` – [Yandex](#yandex) - `openai` – [OpenAI](#openai) - `watsonx` – [watsonx](#watsonx) ### 移除未使用的键 ``` $ bundle exec i18n-tasks unused $ bundle exec i18n-tasks remove-unused ``` 如果你将 `search.strict` 设置为 false,或者在命令行中传递 `--no-strict`, 这些任务可以推断[动态键](#dynamic-keys),例如 `t("category.\#{category.name}")`。 如果你在使用 remove-unused 时希望保持原语言文件的排序,请传递 `-k` 或 `--keep-order`。 ### 修剪不在基础语言环境中的键 移除非基础语言环境中不存在于基础语言环境中的键: ``` $ i18n-tasks prune ``` 传递 `-k` 或 `--keep-order` 以保留语言环境文件中的原始键排序。 ### 规范化 对键进行排序: ``` $ bundle exec i18n-tasks normalize ``` 对键进行排序,并根据 [`config.write`](#storage--locale-files) 的定义将它们移动到相应的文件中: ``` $ bundle exec i18n-tasks normalize -p ``` ### 移动 / 重命名 / 合并键 `bundle exec i18n-tasks mv ` 是一个多功能的任务,用于移动或删除匹配给定模式的键。 所有匹配 [``](#key-pattern-syntax) 的节点(叶节点或子树)将被合并并移动到 ``。 重命名一个节点(叶节点或子树): ``` $ bundle exec i18n-tasks mv user account ``` 移动一个节点: ``` $ bundle exec i18n-tasks mv user_alerts user.alerts ``` 将子节点上移一层: ``` $ bundle exec i18n-tasks mv 'alerts.{:}' '\1' ``` 合并移动多个节点: ``` $ bundle exec i18n-tasks mv '{user,profile}' account ``` 将(非叶)节点合并到其父节点: ``` $ bundle exec i18n-tasks mv '{pages}.{a,b}' '\1' ``` ### 删除键 使用 `rm` 任务删除键: ``` $ bundle exec i18n-tasks rm 'user.{old_profile,old_title}' another_key ``` ### 组合任务 `i18n-tasks` 还提供了用于读取、写入和操作语言环境数据的可组合任务。示例如下。 使用 `missing`、`tree-set-value` 和 `data-merge` 实现的 `add-missing`: ``` $ bundle exec i18n-tasks missing -f yaml fr | bundle exec i18n-tasks tree-set-value 'TRME %{value}' | bundle exec i18n-tasks data-merge ``` 使用 `unused` 和 `data-remove` 实现的 `remove-unused`(不含确认步骤): ``` $ bundle exec i18n-tasks unused -f yaml | bundle exec i18n-tasks data-remove ``` 移除 `fr` 中不存在于 `en` 的所有键。不更改 `en`: ``` $ bundle exec i18n-tasks missing -t diff -f yaml en | bundle exec i18n-tasks tree-mv en fr | bundle exec i18n-tasks data-remove ``` 使用 `bundle exec i18n-tasks --help` 查看完整的任务列表。 ## 配置 配置将从 `config/i18n-tasks.yml` 或 `config/i18n-tasks.yml.erb` 中读取。 使用 `bundle exec i18n-tasks config` 检查配置。 使用以下命令安装[默认配置文件][config]: ``` $ cp $(bundle exec i18n-tasks gem-path)/templates/config/i18n-tasks.yml config/ ``` 默认设置与 Rails 兼容。 ### 语言环境 默认情况下,`base_locale` 被设置为 `en`,而 `locales` 是从数据文件的路径推断出来的。 你可以在[配置][config]中覆盖这些设置。 ### 存储和语言环境文件 默认的数据适配器支持 YAML 和 JSON 文件。 i18n-tasks 可以管理多个翻译文件,并从其他 gem 中读取翻译。 有关更多信息,请参见[配置][config]中的 `data` 选项。 注意:默认情况下,只会读取 `%{locale}.yml` 文件,而不是 `namespace.%{locale}.yml`。请务必检查配置。 对于写入语言环境文件,i18n-tasks 提供了三种路由。 #### Pattern 路由 Pattern 路由基于键模式列表来组织键,如下例所示: ``` data: router: pattern_router # a list of {key pattern => file} routes, matched top to bottom write: # write models.* and views.* keys to the respective files - ["{models,views}.*", 'config/locales/\1.%{locale}.yml'] # or, write every top-level key namespace to its own file - ["{:}.*", 'config/locales/\1.%{locale}.yml'] # default, sugar for ['*', path] - "config/locales/%{locale}.yml" ``` #### Conservative 路由 Conservative 路由将键保留在它们被找到的地方,或者从基础语言环境推断路径。 如果该键是全新的,Conservative 路由将退回到 Pattern 路由的行为。 Conservative 路由是**默认**路由。 ``` data: router: conservative_router write: - ["devise.*", "config/locales/devise.%{locale}.yml"] - "config/locales/%{locale}.yml" ``` 如果你想让 i18n-tasks 使用 `data.write` 重新组织现有的键,可以像上面那样将路由设置为 `pattern_router`,或者运行 `bundle exec i18n-tasks normalize -p`(强制在此次运行中使用 pattern 路由)。 #### Isolating 路由 Isolating 路由假定每个 YAML 文件都是独立的,并且可以包含相似的键。 因此,翻译会被写入到每个源文件对应的备用目标文件中 (只有 `%{locale}` 部分会被更改以匹配目标语言环境)。因此,无需指定任何 `write` 配置(实际上,它会被完全忽略)。 例如,在使用 [ViewComponent sidecars](https://viewcomponent.org/guide/translations.html) 时,这会非常有用 (ViewComponent 为每个 sidecar YAML 文件分配了一个隐式作用域,但 `i18n-tasks` 并不知道该逻辑,从而导致冲突): - `app/components/movies_component.en.yml`: en: title: Movies - `app/components/games_component.en.yml` en: title: Games 不过,此路由有一个限制:它不支持从代码用法中检测缺失的键 (因为它不了解隐式作用域的逻辑)。 #### 键模式语法 i18n-tasks 在各处使用一种类似于文件 glob 模式的特殊语法来匹配翻译键: | 语法 | 描述 | | :--------: | :------------------------------------------------------- | | `*` | 匹配所有内容 | | `:` | 匹配单个键 | | `*:` | 匹配单个键的一部分 | | `{a, b.c}` | 匹配集合中的任意项,可使用 `:` 和 `*`,匹配内容会被捕获 | 用法示例: ``` $ bundle exec i18n-tasks mv "{:}.contents.{*}_body" "\1.attributes.\2.body" car.contents.name_body ⮕ car.attributes.name.body car.contents.description_body ⮕ car.attributes.description.body truck.contents.name_body ⮕ truck.attributes.name.body truck.contents.description_body ⮕ truck.attributes.description.body ``` #### 自定义适配器 如果你将数据存储在文件系统以外的地方(例如数据库或 mongodb),你可以实现一个自定义适配器。 如果你已经实现了一个自定义适配器,请在 [wiki][wiki] 上分享它。 #### Rails 凭证 如果你使用 Rails 凭证并希望加载例如翻译后端的凭证,请将你的 `i18n-tasks.yml` 转换为 `i18n-tasks.yml.erb` 并添加一行 `require "./config/application"` 来加载 Rails。 ``` # config/i18n-tasks.yml.erb <% require "./config/application" %> # ... translation: backend: google google_translate_api_key: <%= Rails.application.credentials.google_translate_api_key %> ``` ### 用法搜索 i18n-tasks 对 `.rb` 和 `.html.erb` 文件使用 AST 扫描器,对其他所有文件使用正则表达式扫描器。 添加新的扫描器非常容易:请参考[此示例](https://github.com/glebm/i18n-tasks/wiki/A-custom-scanner-example)。 有关所有可用的配置选项,请参见[配置文件][config]中的 `search` 部分。 注意:默认情况下,仅会搜索 `app/` 目录。 #### 基于 Prism 的扫描器 有一个基于 [Prism](https://github.com/ruby/prism) 的扫描器,可以在两种不同的模式下使用。 - `rails` 模式解析 Rails 代码,并处理控制器、before_actions、模型翻译等上下文。 - `ruby` 模式仅解析 Ruby 代码,其工作方式类似于现有的 whitequark/parser 实现。 - 该解析器同时用于 ruby 和 ERB 文件。 ##### `rails` 模式 它处理以下情况: - 在 `before_actions` 中调用的翻译 - 在嵌套方法中调用的翻译 - `Model.human_attribute_name` 调用 - `Model.model_name.human` 调用 通过将以下内容添加到你的 `config/i18n-tasks.yml` 中来启用它: ``` search: prism: "rails" ``` ##### `ruby` 模式 它会查找 Ruby 代码中所有的 `I18n.t`、`I18n.translate`、`t` 和 `translate` 调用。通过添加以下内容来启用它: ``` search: prism: "ruby" ``` 未来的目标是使用此扫描器替代基于 whitequark/parser 的扫描器。 ##### 帮助我们进行测试 请安装最新版本的 gem 并运行 `bundle exec i18n-t check-prism`,它将使用基于 whitequark/parser 的扫描器解析所有内容,然后使用 Prism 扫描器解析所有内容,并尝试比较结果。 请针对任何解析器崩溃、遗漏翻译或误报提交 issue。 ### 微调 通过魔法注释提示(默认以 `(#|/) i18n-tasks-use` 开头的行)为静态分析添加提示: ``` # i18n-tasks-use t('activerecord.models.user') # 让 i18n-tasks 知道该 key 已被使用 User.model_name.human ``` 你还可以通过 `ignore*` 设置显式忽略出现在语言环境文件中的键。 如果你有生成翻译键的辅助方法,例如返回 `t '.page_title'` 的 `page_title` 方法, 或者返回 `t "spree.#{key}"` 的 `Spree.t(key)` 方法,请使用内置的 `PatternMapper` 来映射它们。 对于更复杂的情况,你可以实现一个[自定义扫描器][custom-scanner-docs]。 有关更多信息,请参阅[配置文件][config]。 ### 环境变量与 dotenv i18n-tasks 支持使用 [dotenv](https://github.com/bkeepers/dotenv) gem 从 `.env` 文件中加载环境变量。 这对于存储翻译 API 密钥和其他敏感配置特别有用。 如果你的 Gemfile 中包含 `dotenv`,i18n-tasks 将在执行命令之前自动从 `.env` 文件加载环境变量。这意味着你可以将 API 密钥存储在 `.env` 文件中: ``` # .env GOOGLE_TRANSLATE_API_KEY=your_google_api_key DEEPL_AUTH_KEY=your_deepl_api_key OPENAI_API_KEY=your_openai_api_key ``` dotenv 集成是无缝的——无需额外配置。如果 `dotenv` 不可用, i18n-tasks 将继续正常使用系统环境变量。 ## 翻译后端 ### Google Translate `i18n-tasks translate-missing` 需要 Google Translate API 密钥,请在 [Google API Console](https://code.google.com/apis/console) 获取。 此密钥的位置取决于你的 Google API 控制台: - 旧版控制台:API Access -> Simple API Access -> Key for server apps。 - 新版控制台:Nav Menu -> APIs & Services -> Credentials -> Create Credentials -> API Keys -> Restrict Key -> Cloud Translation API 在这两种情况下,如果密钥不存在,你可能需要创建它。 将密钥放入 `GOOGLE_TRANSLATE_API_KEY` 环境变量或配置文件中。 ``` # config/i18n-tasks.yml translation: backend: google google_translate_api_key: ``` 或通过环境变量: ``` GOOGLE_TRANSLATE_API_KEY= ``` ### DeepL `i18n-tasks translate-missing` 需要 DeepL API 密钥。DeepL 提供 Pro 计划和[免费计划](https://www.deepl.com/en/pro#api)(限制为每月 500,000 个字符)。在 [DeepL](https://www.deepl.com/en/pro#api) 获取你的 API 密钥。如果你仅在内部使用简单的语言环境,则可以指定语言环境别名。 ``` # config/i18n-tasks.yml translation: backend: deepl deepl_api_key: deepl_host: deepl_version: deepl_glossary_ids: - uuid deepl_options: formality: prefer_less deepl_locale_aliases: en: en-us pt: pt-br ``` 或通过环境变量: ``` DEEPL_AUTH_KEY= DEEPL_HOST= DEEPL_VERSION= ``` ### Yandex `i18n-tasks translate-missing` 需要 Yandex API 密钥,请在 [Yandex](https://tech.yandex.com/translate) 获取。 ``` # config/i18n-tasks.yml translation: backend: yandex yandex_api_key: ``` 或通过环境变量: ``` YANDEX_API_KEY= ``` ### OpenAI `i18n-tasks translate-missing` 需要 OpenAI API 密钥,请在 [OpenAI](https://openai.com/) 获取。 ``` # config/i18n-tasks.yml translation: backend: openai openai_api_key: openai_model: ``` 或通过环境变量: ``` OPENAI_API_KEY= OPENAI_MODEL= ``` ### watsonx `i18n-tasks translate-missing` 需要 watsonx 项目和 API 密钥,请在 [IBM watsonx](https://www.ibm.com/watsonx/) 获取。 ``` # config/i18n-tasks.yml translation: backend: watsonx watsonx_api_key: watsonx_project_id: watsonx_model: ``` 或通过环境变量: ``` WATSONX_API_KEY= WATSONX_PROJECT_ID= WATSONX_MODEL= ``` ## 功能与限制 `i18n-tasks` 对 `.rb` 和 `.html.erb` 文件使用 AST 扫描器,对其他文件(如 `.haml`)使用基于正则表达式的扫描器。 ### 相对键 `i18n-tasks` 支持相对键,例如 `t '.title'`。 ✔ 支持相对于它们使用时所在文件路径的键(参见[用法搜索](#usage-search))。 ✔ 支持 Rails 控制器中相对于 `controller.action_name` 的键。使用的是最接近的 `def` 名称。 ### 复数键 ✔ 复数键(如 `key.{one,many,other,...}`)被完全支持。 ### 引用键 ✔ 引用键(值为 `:symbol` 的键)被完全支持。这些键在 `add/translate-missing` 中按原样复制,并且可以在 `find` 中通过引用或值进行查找。 ### 动态键 默认情况下,无法识别动态键,例如 `t "cats.#{cat}.name"`。 我们鼓励你使用 [i18n-tasks-use 提示](#fine-tuning) 来标记它们。 或者,你可以在配置中将 `search.strict` 设置为 `false` 来启用动态键推断。在这种情况下, 键的所有动态部分将被视为已使用,例如,`cats.tenderlove.name` 将不会被报告为未使用。 请注意,每次字符串插值只有键的一个部分被视为通配符;即在此示例中, `cats.tenderlove.special.name` _会_ 被报告为未使用。 ### I18n.localize 不支持 `I18n.localize`,请使用 [i18n-tasks-use 提示](#fine-tuning)。 这是因为 `I18n.localize` 生成的键取决于传入的对象类型,因此无法静态推断。 ### `t()` 关键字参数 ✔ `scope` 关键字参数被 AST 扫描器完全支持,同时也被 Regexp 扫描器支持,但仅当它是第一个参数时。 ✔ `default` 参数可用于预填充语言环境文件(仅限 AST 扫描器)。 ### 意外的规范化 `i18n-tasks` 底层使用了一个名为 `Psych` 的 YAML 解析器和发射器。`Psych` 有自己关于何时为多行字符串使用 `|`、`>` 或 `""` 的启发式方法。这可能会产生一些意想不到的后果,例如在规范化时: ``` a: | Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur b: | Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur ``` 我们得到的结果是: ``` a: | Lorem ipsum dolor sit amet, consectetur Lorem ipsum dolor sit amet, consectetur b: "Lorem ipsum dolor sit amet, consectetur \nLorem ipsum dolor sit amet, consectetur\n" ``` `a` 和 `b` 之间唯一的区别是 `b` 的每行多了一个尾部空格。 这是 `i18n-tasks` 使用 `Psych` 带来的一个不幸副作用。 ## 高级 ### 交互式控制台 `bundle exec i18n-tasks irb` 在 i18n-tasks 上下文中启动一个 IRB 会话。输入 `guide` 获取更多信息。 ### CSV 导入 / 导出 参见 [i18n-tasks wiki: CSV import and export tasks](https://github.com/glebm/i18n-tasks/wiki/Custom-CSV-import-and-export-tasks)。 ### 添加自定义任务 该 gem 附带的任务定义在 [lib/i18n/tasks/command/commands](lib/i18n/tasks/command/commands) 中。 自定义任务可以轻松添加,请参阅 [wiki](https://github.com/glebm/i18n-tasks/wiki#custom-tasks) 上的示例。 ## 开发 - 使用 `bundle install` 安装依赖 - 使用 `bundle exec rspec` 运行测试 - 通过运行 `overcommit --install` 安装 [Overcommit](https://github.com/sds/overcommit) ### 跳过 Overcommit hooks - `SKIP=RuboCop git commit` - `OVERCOMMIT_DISABLE=1 git commit`
标签:AST解析, DeepL, Gem包, Google Translate, Homebrew安装, i18n, Petitpotam, Prism, Ruby, Ruby on Rails, 代码健康度, 内存转储, 国际化, 威胁情报, 开发者工具, 批量扫描, 文本处理, 未使用代码检测, 本地化, 知识库, 翻译管理, 自动化payload嵌入, 自动化翻译, 错误基检测, 键值管理, 静态代码分析