|
文档
预约演示平台
平台MCPCLIAPI工作流
指南
更新日志

本地化

  • 概览
  • 翻译 API
  • Web 应用本地化
  • 移动应用本地化
  • iOS 与 String Catalogs
  • Android 与 strings.xml
  • 邮件本地化
  • 静态内容(如 .md、.json)
  • Next.js + Markdoc
  • Rails + i18n

工作流

  • 通过 MCP 配置引擎
  • Jira 智能分诊
  • CI/CD

使用 i18n API 实现 Ruby on Rails 本地化

Lingo.dev CLI 可通过已配置的 config/locales本地化引擎 翻译 Rails 的 YAML 文件。Rails 原生内置 i18n API——应用中所有可翻译文本都存放在按 locale 划分的 YAML 文件里。Lingo.dev 能无缝接入你现有的流程,无需额外引入运行时依赖。

这篇指南会带你从头到尾完成 Rails 应用本地化:配置 CLI、按 locale 组织 YAML 文件、在请求时切换 locale,以及在 CI 中自动化翻译。

演示仓库

克隆或 fork lingodotdev/ruby-on-rails-localization-example,边看边上手。这是一个可直接运行的 Rails 应用,包含 config/locales YAML 文件、已提交的 .lingo/config.json,并且翻译结果也已就绪,因此你可以一边看配置,一边对照它生成的输出。

Rails 本地化如何运作#

Rails 会从 config/locales/ 下的 YAML 文件中读取翻译。每个文件都以 locale code 作为根键,内部则包含嵌套键,对应你在代码里通过 I18n.t 使用的查找路径。

层级存放内容示例文件
UI 文案按钮、标签、flash 消息config/locales/en.yml
邮件文案ActionMailer 的主题和正文config/locales/mailers.en.yml
模型错误校验消息和属性名config/locales/activerecord.en.yml

每个 Rails YAML 文件的第一个键,都是 locale 代码本身——en:、es:、fr:。Rails 是根据这个根键而不是文件名来索引翻译的:它会加载 config/locales/ 下的所有文件,并将每个文件的内容存到它所声明的根键之下。所以,一个 es.yml 就算根仍然是 en:,也不会被忽略——它会被合并进 en 命名空间。结果就是西班牙语完全没有翻译,而英文翻译则会被悄悄覆盖。

因此,翻译这种格式时,改写的是这个键本身,而不只是值。yaml-root-key 格式正是为此而生:它会遍历根键下的整棵树,只翻译字符串值,并把目标文件写成以目标 locale 为根。嵌套键、%{name} 插值 token,以及 CLDR 复数类别(zero/one/two/few/many/other)都属于结构内容,因此会原样保留——注释和 YAML anchors 也一样。

前提条件#

1

创建本地化引擎

每次运行 CLI 时,内容都会发送到 本地化引擎——这项配置决定使用哪个 LLM 模型,以及应用哪些 glossary、品牌语调和 规则。请前往 Lingo.dev dashboard 创建配置,并生成 API key。

2

确认 Ruby 和 Rails 版本

本指南适用于 Rails 7.2 及以上版本,而它要求 Ruby 3.1 及以上。先检查你的版本:

bash
ruby -v
rails -v
3

确认 Node.js 版本

CLI 需要 Node.js 22 或更高版本:

bash
node -v
4

设置 Rails i18n

本指南默认你的应用已经将翻译存放在 config/locales/*.yml 中。如果你的视图或控制器里还有硬编码字符串,请先将它们提取为 t() 调用。比如,把下面这段替换成:

erb
<h1>Welcome</h1>

替换为:

erb
<h1><%= t(".welcome") %></h1>

然后把对应的键添加到 config/locales/en.yml 中。完整迁移步骤可参考 Rails 的 internationalization guide。

组织翻译文件#

Rails 会自动加载 *.yml 下所有匹配的 config/locales/ 文件。建议将源 locale 和各个目标语言文件放在同一目录中,让这个目录成为唯一可信来源:

text
config/locales/
  en.yml          # Source locale
  es.yml          # Generated by Lingo.dev
  fr.yml
  de.yml

一个典型的 en.yml 会同时包含普通字符串、嵌套命名空间、%{name} 插值和复数形式:

yaml
en:
  hello: "Hello"
  home:
    welcome: "Welcome, %{name}!"
    cta: "Get started"
  notifications:
    unread:
      zero: "No unread notifications"
      one: "1 unread notification"
      other: "%{count} unread notifications"
  errors:
    messages:
      blank: "can't be blank"

配置 CLI#

安装 CLI、完成认证,并将项目关联到你的引擎:

bash
npm install -g @lingo.dev/cli
lingo login
lingo init
lingo link

lingo init 和 lingo link 会创建 .lingo/config.json,其中包含你的 locales,以及引擎的 orgId 和 engineId。请将它与 .lingo/lock.json 一并提交,这样每台机器和每次 CI 运行都能共享同一份状态。

将一个 files[] 条目指向源 locale 文件,并显式指定格式:

json
{
  "orgId": "org_...",
  "engineId": "eng_...",
  "sourceLocale": "en",
  "targetLocales": ["es", "fr", "de"],
  "files": [{ "pattern": "config/locales/en.yml", "format": "yaml-root-key" }]
}

这里的 "format": "yaml-root-key" 是必填项,不是可选项。仅凭 .yml 路径,无法判断它的根键是 locale 还是普通配置,所以 CLI 不会自行猜测:如果省略 format,文件就会按通用 yaml 处理,只翻译值,并把根保留为 en:——也就是上面提到的那种静默失败。

目标文件会根据源路径自动推导,因此 config/locales/en.yml 会生成 config/locales/es.yml、config/locales/fr.yml 和 config/locales/de.yml。

除了 en.yml 之外,Rails 还会加载按功能拆分的文件——devise.en.yml、mailers.en.yml、activerecord.en.yml。再添加一个带 glob 的第二条目,把它们也覆盖进去:

json
{
  "files": [
    { "pattern": "config/locales/en.yml", "format": "yaml-root-key" },
    { "pattern": "config/locales/*.en.yml", "format": "yaml-root-key" }
  ]
}

这两个模式不会重叠:第一个只匹配 en.yml,第二个只匹配以 .en.yml 结尾的文件,因此像 es.yml 和 devise.es.yml 这样已翻译的文件,绝不会被当作源文件再次拾取。devise.en.yml 会生成 devise.es.yml。

为多个 locale 配置 Rails#

告诉 Rails 哪些 locale 可用,以及默认使用哪个。在 config/application.rb 中:

ruby
module YourApp
  class Application < Rails::Application
    config.i18n.available_locales = [:en, :es, :fr, :de]
    config.i18n.default_locale = :en
    config.i18n.fallbacks = [:en]
  end
end

在 ApplicationController 中根据 URL 参数或 Accept-Language 请求头选择当前请求的 locale:

ruby
class ApplicationController < ActionController::Base
  around_action :switch_locale

  private

  def switch_locale(&action)
    locale = params[:locale] || http_accept_locale || I18n.default_locale
    I18n.with_locale(locale, &action)
  end

  def http_accept_locale
    header = request.headers["Accept-Language"].to_s
    header.scan(/[a-z]{2}/).find { |l| I18n.available_locales.map(&:to_s).include?(l) }
  end

  def default_url_options
    { locale: I18n.locale }
  end
end

在视图中渲染翻译#

在 ERB 模板中使用 t 和 l 辅助方法。键名前面的点会相对于当前视图路径解析,让翻译键与使用它们的模板就近放置:

erb
<h1><%= t(".welcome", name: @user_name) %></h1>
<p><%= t("notifications.unread", count: @unread_count) %></p>
<%= link_to t(".cta"), signup_path, class: "btn-primary" %>

在布局中添加一个语言切换器:

erb
<nav>
  <% I18n.available_locales.each do |locale| %>
    <%= link_to locale.upcase, url_for(locale: locale) %>
  <% end %>
</nav>

在本地执行翻译#

bash
lingo push --wait

push 会上传源文件,通过你的本地化引擎处理后,再把翻译后的文件写回。--wait 会让命令保持阻塞,直到输出生成完成——这一点值得显式传入,因为一个即将发布的变更会调整默认行为:push 将只提交任务并立即返回,之后需要你用 lingo pull 来拉取结果。

后续运行只会翻译增量内容:push 会对源文件计算哈希,并与 .lingo/lock.json 对比,因此未变更的条目不会产生任何成本。项目首次运行时——或新增 locale 后——则需要处理整份语料:

bash
lingo push --backfill-missing

传入一个 glob,就可以把本次运行限定在部分文件上:

bash
lingo push "config/locales/**"

如果要获取在其他地方生成的输出——比如另一台机器或 CI——请运行 lingo pull。

首次运行翻译后,请重启 Rails 服务器,以便加载新的 YAML 文件:

bash
bin/rails server

访问 /es 查看西班牙语效果。

复数形式#

Rails 使用 CLDR 复数类别——zero、one、two、few、many、other。给 count: 传入 I18n.t 参数后,Rails 就会自动选择匹配的键:

ruby
t("notifications.unread", count: 0)   # => "No unread notifications"
t("notifications.unread", count: 1)   # => "1 unread notification"
t("notifications.unread", count: 12)  # => "12 unread notifications"

CLI 会在原位翻译每一种复数变体。如果目标 locale 需要比英语的 one/other 更多的类别,请在源 en.yml 中先定义好。

在 CI 中实现自动化#

Lingo.dev GitHub App 会在每次 push 和 pull request 时于服务端完成翻译——无需 runner,也不用在仓库中存放 API key。它会根据已提交的 .lingo/config.json 解析所用引擎,因此你提交的文件里必须包含 orgId 和 engineId。

如果你更希望在自己的流水线里运行 CLI——GitHub Actions、GitLab CI、Bitbucket Pipelines——请参阅 CI/CD Workflows。将 LINGO_API_KEY 作为 secret 提供,并像调用其他构建步骤一样调用 lingo push --wait。

部署前验证#

把 lingo check 作为部署前的闸门,确保未翻译内容不会进入生产环境。如果仍有任何条目需要翻译,它会以非零状态码退出,且不会写入任何内容。

bash
lingo check

将它作为独立的 CI 步骤,放在资源预编译或容器构建之前:

yaml
- name: Verify translations
  run: lingo check
- name: Precompile assets
  run: bundle exec rails assets:precompile

下一步#

静态内容本地化
Markdown、MDX、JSON、YAML 及其他静态文件格式
Web 应用本地化
覆盖常见 Web 框架的 UI 文案模式
CI/CD 工作流
GitHub Actions、GitLab CI、Bitbucket Pipelines 等模式
术语表
锁定品牌名和技术术语,避免被误译

这个页面对你有帮助吗?

Max PrilutskiyMax Prilutskiy·已更新 8 天前·3 分钟阅读