GitLab CI 内で Lingo.dev を実行すると、ソース文字列を追加・変更したすべてのマージリクエストに、翻訳がすでに埋まった状態で結果が返ってきます。パイプラインは lingo push を実行し、ローカライゼーションエンジンは新規または変更されたキーだけを翻訳。その結果を MR ブランチへ直接コミットします。翻訳は MR の差分に表示され、人がマージする前にレビューされます。未確認の変更がそのままデフォルトブランチに入ることはありません。
動作するサンプル
完全に動くセットアップ例は gitlab.com/lingo.dev/gitlab-cicd-example にあります。
前提条件#
Lingo.dev の organization とエンジン、そして service API key が必要です(Dashboard → API Keys → create、type は service)。
Lingo.dev 用に設定されたプロジェクト。以下のコマンドを一度実行して生成します。
bashnpx @lingo.dev/cli@latest init # scaffolds .lingo/config.json npx @lingo.dev/cli@latest link # connects the project to your org + engine.lingo/config.jsonでは、ソース/ターゲットのロケールとソース glob を定義します。json{ "sourceLocale": "en", "targetLocales": ["es", "fr", "de", "zh"], "files": [{ "pattern": "locales/en.json" }], "orgId": "org_...", "engineId": "eng_..." }コミット済みのベースラインも必要です。初回はまず全体を翻訳してコミットし、CI が差分比較に使う lockfile を用意してください。
bashnpx @lingo.dev/cli@latest push --backfill-missing --wait git add locales .lingo && git commit -m "chore(i18n): baseline translations"
アクセストークン#
Settings → CI/CD → Variables で、masked の CI/CD 変数を 2 つ追加します。
LINGO_API_KEY— Lingo.dev の service key(lingo_sk_...)。CLI が自動で読み取り、認証に使います。GITLAB_PUSH_TOKEN—write_repositoryスコープ付きの Project Access Token(ロールは Developer)。これにより、CI が翻訳を MR ブランチへコミットして戻せます。
Settings → Access tokens で Project Access Token を作成します。CI_JOB_TOKEN ではコミットを push できないため、コミットを書き戻すステップには専用トークンが必要です。Project access tokens の利用には有料の GitLab プランが必要です。
パイプライン#
この .gitlab-ci.yml をコミットしてください。デフォルトブランチ向けのマージリクエストで実行され、翻訳を MR のソースブランチへ push して戻します。
stages:
- localize
localize:
stage: localize
image: node:22-alpine
rules:
# Only on merge requests that target the default branch.
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH'
before_script:
- apk add --no-cache git
script:
# Pin the CLI version — never @latest; bump deliberately after testing.
# --wait blocks until the engine finishes and writes files: since 1.6.0
# `push` is async by default (it submits the run and exits), so CI must
# wait to have something to commit.
- npx -y @lingo.dev/cli@1.6.0 push --wait
- |
if [ -z "$(git status --porcelain)" ]; then
echo "Translations already up to date — nothing to commit."
exit 0
fi
git config user.name "lingo-bot"
git config user.email "bot@lingo.dev"
git add locales .lingo/lock.json
# [skip ci] keeps the bot's own commit from re-triggering this pipeline.
git commit -m "chore(i18n): sync translations [skip ci]"
git push "https://oauth2:${GITLAB_PUSH_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" "HEAD:${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}"試してみる#
git checkout -b feat/new-strings
# add or change a key in locales/en.json
git commit -am "feat: add strings" && git push -u origin feat/new-strings
# open an MR feat/new-strings -> main (UI, or: glab mr create --fill --target-branch main)MR パイプラインは lingo push --wait を実行し、locales/{...}.json と更新済みの .lingo/lock.json を MR ブランチへコミットします。すると翻訳が差分に表示されます。レビュー担当者が必要に応じて値を調整し、その後マージします。
手動編集が維持される仕組み#
lingo push は手動編集を キー単位 で保持します。
- ターゲット文字列を編集しても(対応する英語ソースが変わらない限り)、その文字列は保持されます。ほかのすべてのキーは引き続き翻訳されます。
- 編集済みキーに対応する英語ソースが変わると、そのキーには新しい翻訳が生成されます(意味が変わったためです)。
- 新しいソースキーが追加されると、手動編集を含むファイルであっても翻訳されて追加されます。
そのため、MR でレビュー担当者が加えた修正は以降のパイプライン実行でも維持され、新規・変更されたキーは自動で流れ込みます。
push モード#
lingo push— 増分モード。CI のデフォルトです。新規/変更キーだけを翻訳し、それ以外はすべて保持します。CI では--waitを追加してください。これにより、出力が書き込まれるまで待機します(1.6.0+ ではデフォルトで非同期です)。lingo push --backfill-missing— 初回 push / 新規ロケールのブートストラップ用。まだ存在しないターゲットファイルを埋めます。継続的な変更には向きません。lingo push --force --yes— すべてをゼロから再翻訳します(手動編集は上書きされます)。使用頻度は低めです。
カスタマイズ#
- MR ではなくデフォルトブランチへ自動コミットする:
$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCHをトリガーにして、$CI_DEFAULT_BRANCHへ push して戻します。よりシンプルですが、AI の出力がレビューなしでデフォルトブランチに入ります。 - 特定の文字列を固定する:
.lingo/config.jsonでpreservedKeys/lockedKeysを使うと、ソースが変わっても選んだキーを固定できます。 - セルフホスト版 GitLab: そのまま動作します。gitlab.com では、新規アカウントは共有 runner が CI ジョブを実行する前に本人確認を完了する必要があります。
