TMS 平台对比:Crowdin / Phrase / Lokalise
核心问题:Translation Management System(TMS)平台能帮你做什么?三大平台各有什么优势?如何接入 GitHub CI/CD?
真实场景
你的产品支持 8 种语言,有 5 名外部翻译人员(来自不同国家),每周约有 200 个新 key 需要翻译。手动管理翻译包已经无法应对:你需要 TMS 平台来自动同步、分配任务、跟踪进度、管理术语表。
为什么需要 TMS
| 问题 | 没有 TMS | 有 TMS |
|---|---|---|
| 新翻译分发 | 手动打包 → 邮件发送 | 自动同步(GitHub PR 触发) |
| 翻译进度 | 手动统计 Excel | 实时仪表板 |
| 术语表 | 手动维护 Word 文档 | 翻译界面实时高亮 |
| 翻译记忆 | 无法复用历史翻译 | 自动复用相似翻译 |
| 协作 | 邮件来回 | 在线评论、实时协作 |
| 机器翻译 | 手动调用 API | 一键 MT,人工后审 |
| 代码回流 | 手动复制粘贴 | 自动 PR 合并 |
三大 TMS 平台对比
| 特性 | Crowdin | Phrase(原 Phrase Strings) | Lokalise |
|---|---|---|---|
| 定价模式 | 按用户 + 字符串 | 按用户 | 按项目 + 字符串 |
| 免费计划 | ✅(开源项目免费) | 限制性免费试用 | 14 天试用 |
| GitHub 集成 | ✅ 原生应用 | ✅ | ✅ |
| GitLab/Bitbucket | ✅ | ✅ | ✅ |
| 支持的文件格式 | 60+ | 40+ | 40+ |
| 机器翻译集成 | ✅ DeepL/Google/Microsoft | ✅ | ✅ |
| 翻译记忆 | ✅ | ✅ | ✅ |
| 术语表 | ✅ | ✅ | ✅ |
| QA 检查 | ✅ | ✅ | ✅ |
| API | ✅ REST + CLI | ✅ REST + CLI | ✅ REST + CLI |
| 中文界面 | ✅ | ❌ | ❌ |
| 适合场景 | 开源/中小企业 | 中大型企业 | 中大型企业 |
Crowdin 接入(最流行的选择)
Step 1:配置 crowdin.yml
# crowdin.yml(放在项目根目录)
project_id: "123456"
api_token_env: CROWDIN_API_TOKEN # 从环境变量读取
files:
# 上传:本地翻译文件 → Crowdin
- source: /src/locales/zh-CN/*.json
translation: /src/locales/%locale%/%original_filename%
# locale 映射(Crowdin locale → 你的文件名)
languages_mapping:
locale:
zh-CN: zh-CN
en-US: en-US
ja-JP: ja-JP
ko-KR: ko-KR
ar-SA: ar-SA
de-DE: de-DE
# 翻译文件中 key 的格式
type: json
# 不要导出未翻译的 key
export_patterns:
ignore: ["/^$/"] # 空字符串不导出
# 额外设置
commit_message: "feat(i18n): update translations from Crowdin [skip ci]"
pull_request_title: "🌍 New translations from Crowdin"
Step 2:GitHub Actions 自动同步
# .github/workflows/crowdin.yml
name: Crowdin Sync
on:
# 推送到 main 时上传新的源文件
push:
branches: [main]
paths:
- 'src/locales/zh-CN/**'
# 定期下载翻译(每天一次)
schedule:
- cron: '0 9 * * *' # UTC 09:00 = 北京时间 17:00
workflow_dispatch: # 手动触发
jobs:
synchronize-with-crowdin:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Upload source files to Crowdin
uses: crowdin/github-action@v2
with:
upload_sources: true
upload_translations: false
crowdin_branch_name: main
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }}
download-translations:
runs-on: ubuntu-latest
needs: []
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
steps:
- uses: actions/checkout@v4
- name: Download translations from Crowdin
uses: crowdin/github-action@v2
with:
upload_sources: false
upload_translations: false
download_translations: true
# 自动创建 PR 合并翻译
create_pull_request: true
pull_request_base_branch_name: main
pull_request_labels: "translations,automated"
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_API_TOKEN }}
Step 3:Crowdin CLI 手动操作
# 安装 Crowdin CLI
npm install -g @crowdin/cli
# 上传源文件
crowdin upload sources
# 下载翻译文件
crowdin download
# 查看翻译进度
crowdin status translation
# 输出:
# en-US: 95% (1187/1250 strings)
# ja-JP: 88% (1100/1250 strings)
# ko-KR: 64% (800/1250 strings)
# 预翻译(使用 TM + MT 自动填充)
crowdin pre-translate \
--method tm \
--auto-approve-option perfectly-match \
--language-ids en-US,ja-JP
Lokalise 接入
Lokalise GitHub App 配置
# .lokalise.yml
project_id: "abc123def456"
file_format: json
# 监听的 branch
branch: main
# 文件映射
upload:
files:
- src/locales/zh-CN/%file_name%.json
download:
destination: src/locales/%lang_iso%/%file_name%.json
lang_map:
zh_CN: zh-CN
en_US: en-US
ja_JP: ja-JP
# Lokalise CLI
npm install -g @lokalise/node-api
# 上传
lokalise2 file upload \
--token $LOKALISE_API_TOKEN \
--project-id $LOKALISE_PROJECT_ID \
--file src/locales/zh-CN/common.json \
--lang-iso zh_CN \
--keys-to-values \
--include-path true
# 下载
lokalise2 file download \
--token $LOKALISE_API_TOKEN \
--project-id $LOKALISE_PROJECT_ID \
--format json \
--dest ./src/locales \
--unzip-to .
完整 CI/CD 翻译工作流
sequenceDiagram
participant Dev as 开发者
participant GitHub as GitHub
participant Actions as GitHub Actions
participant Crowdin as Crowdin
participant Trans as 翻译人员
Dev->>GitHub: push 代码(含新 key)
GitHub->>Actions: 触发 workflow
Actions->>Crowdin: 上传新源文件(zh-CN)
Crowdin->>Trans: 通知新字符串待翻译
Trans->>Crowdin: 完成翻译(在线编辑器)
Note over Crowdin: 每天定时任务
Actions->>Crowdin: 下载已完成翻译
Crowdin-->>Actions: 返回翻译文件
Actions->>GitHub: 创建 PR(翻译更新)
Dev->>GitHub: Review 并合并 PR
GitHub->>Actions: 触发部署
翻译记忆和术语表 API
// 通过 API 管理术语表
import crowdinApi from '@crowdin/crowdin-api-client';
const { glossariesApi } = crowdinApi({
token: process.env.CROWDIN_API_TOKEN!,
});
// 批量添加术语
async function updateGlossary(terms: Array<{ source: string; translation: string; locale: string }>) {
const projectId = Number(process.env.CROWDIN_PROJECT_ID);
const glossaries = await glossariesApi.listGlossaries({});
const glossaryId = glossaries.data[0]?.data?.id;
if (!glossaryId) throw new Error('No glossary found');
// 批量添加术语
await glossariesApi.importGlossaryFile(glossaryId, {
storageId: /* upload glossary file */,
});
}
// 从本地术语表同步到 Crowdin
const localGlossary = JSON.parse(fs.readFileSync('glossary/zh-CN-en-US.json', 'utf-8'));
const terms = Object.entries(localGlossary).map(([source, translation]) => ({
source,
translation: translation as string,
locale: 'en-US',
}));
await updateGlossary(terms);
TMS 平台选型建议
| 团队规模 | 预算 | 推荐平台 | 理由 |
|---|---|---|---|
| < 5 人,开源项目 | 免费 | Crowdin | 开源免费,中文界面 |
| 5-20 人,初创公司 | 低 | Crowdin Team | 性价比高 |
| 20-100 人,成长期 | 中 | Lokalise | 功能全面,API 完善 |
| > 100 人,企业 | 高 | Phrase | 企业级功能,合规支持 |
| 重视 DeepL 质量 | 中 | 任何(配 DeepL API) | 三家都支持 DeepL |
常见问题
Q:翻译文件格式不是平台原生支持的怎么办?
A:三大平台都支持 60+ 格式,ICU JSON 和 i18next JSON 都在支持列表中。如果格式确实不支持,可以在上传前用脚本转换。
Q:TMS 平台的翻译员能看到我的产品代码吗?
A:不能。TMS 平台只同步翻译字符串和源文件,不暴露代码库。但翻译字符串本身可能包含产品信息,需要根据 NDA 要求管理翻译员权限。
Q:多个环境(dev/staging/prod)如何处理?
A:通常使用分支策略:main 对应 prod,develop 对应 staging。Crowdin 和 Lokalise 都支持多分支同步。
进入第 07 章:翻译工作流建立好了,接下来处理最容易被忽视的挑战——阿拉伯语、希伯来语等从右到左语言的 RTL 布局和文化适配。