Lingo.dev CLI 会通过已配置的 本地化引擎 翻译 Android strings.xml字符串资源()。借助 android 格式,CLI 能原生识别 <resources>、<string>、<string-array> 和 <plurals> 元素,既保留 XML 结构,也能为每个目标语言环境生成正确的复数类别。
这篇指南会带你完整走一遍 Android 应用本地化流程:配置 CLI、本地翻译,以及在 CI 中实现自动化,让翻译在每次 push 后都能随版本一起交付。
示例仓库
克隆或 fork lingodotdev/android-app-localization-example,即可跟着一起操作。这个仓库包含一个可直接运行的 Android 项目,内含字符串资源、Lingo.dev CLI 配置,以及已提交到各个目标语言环境的翻译。
Android 本地化如何工作#
Android 采用 资源目录约定,为每个语言环境使用独立的 values-[locale]/ 目录。系统会在运行时根据设备语言设置加载对应的 strings.xml。
app/src/main/res/
values/ # Default (source) strings
strings.xml
values-es/ # Spanish
strings.xml
values-fr/ # French
strings.xml
values-ja/ # Japanese
strings.xml一个典型的 strings.xml 通常包含三类元素:
<resources>
<!-- Simple strings -->
<string name="app_name">My App</string>
<string name="welcome_message">Welcome back!</string>
<!-- String arrays -->
<string-array name="planets">
<item>Mercury</item>
<item>Venus</item>
<item>Earth</item>
</string-array>
<!-- Plurals -->
<plurals name="items_count">
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
</plurals>
</resources>CLI 会解析这三类元素,通过 localization engine 翻译其中内容,并将各语言环境对应的文件写入正确的 values-[locale]/ 目录。
准备工作#
创建 localization engine
每次运行 CLI 时,内容都会经过一个本地化引擎——该配置决定使用哪个 LLM 模型,以及应用哪个术语表、品牌语调和规则。在Lingo.dev dashboard中创建一个。
确认 Node.js 版本
CLI 要求 Node.js 22 或更高版本:
node -v安装 CLI
全局安装 CLI,这样就可以直接使用 lingo 命令:
npm install -g @lingo.dev/cli准备 Android 项目
你的项目需要在 strings.xml 中有一个默认的 app/src/main/res/values/。新建项目时,Android Studio 会自动生成这个文件。关于资源目录的设置方式,可参考 Android 的 本地化指南。
配置 CLI#
在项目根目录运行 lingo init,创建 .lingo/config.json,写入源语言环境、目标语言环境和文件匹配模式;然后再运行 lingo link,关联你的组织和引擎。最终效果如下:
{
"orgId": "org_...",
"engineId": "eng_...",
"sourceLocale": "en",
"targetLocales": ["es", "fr", "de", "ja"],
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
}
]
}该模式指向默认资源目录,也就是未限定的 values/——正是 Android 期望存放源字符串的位置。这里不会出现语言环境代码,也不需要出现。
为什么要显式设置 `format`
CLI 会根据文件扩展名自动识别大多数格式,但 .xml 有歧义,因此 Android 资源文件需要在 files 条目中显式指定 "format": "android"。
多个资源文件
如果你的项目将字符串拆分在多个文件中(例如 strings.xml 和 arrays.xml),请为每个文件分别添加一个 files 条目:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android"
},
{
"pattern": "app/src/main/res/values/arrays.xml",
"format": "android"
}
]
}将 .lingo/config.json 提交到仓库中。
语言环境目录与限定符#
Android 会将默认语言放在未限定的 values/ 目录中,因此源路径本身不包含语言环境代码。CLI 也遵循这一规则:它会将不带限定符的 values/ 视为源语言环境,并为其他每种语言环境追加对应的目标限定符。
| 语言环境 | 资源目录 |
|---|---|
en(源) | values/ |
es | values-es/ |
pt-BR | values-pt-rBR/ |
zh-Hans | values-b+zh+Hans/ |
这里需要特别理解区域和书写系统语言环境,因为资源限定符并不是原始的 BCP 47 标签。Android 支持两种写法:传统的语言-地区形式(values-pt-rBR/),以及带 b+ 前缀的 BCP 47 形式(values-b+pt+BR/,适用于 API 24 及以上)。如果目录命名为 values-pt-BR/,Android 会直接忽略——字符串虽然存在,但永远不会被加载。
设置 "format": "android" 后,CLI 会自动为你生成正确的写法:能用传统形式表达的语言环境就使用传统形式;涉及书写系统、三字母语言代码和数字区域时,则使用 b+。
从旧配置升级
较早版本的 CLI 要求在源路径中包含语言环境,本指南过去也曾建议使用 values-en -> values 符号链接来衔接这两种约定。从 @lingo.dev/cli 1.12.0 开始,这已经不再需要——将模式指向 values/strings.xml,然后删除该符号链接即可。
本地翻译#
运行 CLI。首次运行时——或者每次新增目标语言环境时——请使用 --backfill-missing,这样现有的所有字符串都会被翻译:
lingo push --backfill-missingCLI 会读取源 strings.xml,基于 运行状态 找出尚未翻译的条目,通过你的本地化引擎翻译这些增量内容,并将结果写入目标 values-[locale]/ 目录。打开任意目标文件,就能看到翻译后的字符串。
后续再运行时,lingo push 只会翻译发生变更的内容:
lingo push如果你只想让某次运行作用于特定文件,可以传入一个 glob。模式会基于源路径进行匹配,因此应按源文件限定范围,而不是目标文件:
lingo push "app/src/main/res/values/strings.xml"如果要把在其他地方生成的翻译(例如由 CI 生成)拉取到当前工作树中,运行 lingo pull 即可。
复数处理#
Android 使用 <plurals> 元素,并配合 CLDR quantity strings(zero、one、two、few、many、other)来处理复数形式。不同语言所需的复数类别不同——英语需要两类(one 和 other),俄语需要四类,阿拉伯语需要六类。
CLI 会在翻译时保留 <plurals> 结构,并为每个目标语言环境生成正确的 quantity 条目。比如一个只包含两个类别的源条目:
<plurals name="messages_count">
<item quantity="one">%d new message</item>
<item quantity="other">%d new messages</item>
</plurals>就能为每种目标语言生成正确的类别。localization engine 知道每个语言环境适用哪些 CLDR plural rules,并且只会生成该语言真正需要的类别。
键锁定#
有些字符串值在所有语言中都应保持完全一致——例如品牌名称、API 端点或格式模式。这时可以使用 key locking,直接复制这些值而不进行翻译:
{
"files": [
{
"pattern": "app/src/main/res/values/strings.xml",
"format": "android",
"lockedKeys": ["app_name", "api_base_url"]
}
]
}被锁定的键会从源文件直接复制到所有目标文件,不会进入翻译流程。
在 CI 中实现自动化#
想要持续保持翻译最新,推荐使用 Lingo.dev GitHub App。它在服务端运行,读取你已提交的 .lingo/config.json 和 engineId,并自动创建翻译更新——无需 runner、无需存储 secret,也不用你自己管理 lockfile。安装后将它连接到你的仓库,就能在每次 push 时自动完成翻译。
如果你更希望在自己的流水线里运行 CLI,可以添加一个工作流,安装 CLI 并执行 lingo push:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install -g @lingo.dev/cli
- run: lingo push --backfill-missing
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}在 GitHub 仓库的 Settings > Secrets and variables > Actions 中,将你的 API key 保存为 LINGO_API_KEY,然后在后续步骤中提交更新后的目标文件(或创建一个 pull request)。
部署前先校验#
你也可以把 lingo check 作为部署门禁,确保未翻译的字符串不会进入生产环境。如果仍有条目需要翻译,这个命令会以非零状态码退出:
lingo check可以在构建前把它作为单独的 CI 步骤加入:
- name: Verify translations
run: lingo check
env:
LINGO_API_KEY: ${{ secrets.LINGO_API_KEY }}