エンジニアリング//9 読了時間

GitHubで翻訳を自動同期する方法:CI/CDローカライゼーション完全ガイド

Eray Gündoğmuş
共有

ほとんどのチームは、煩雑な手動ループで翻訳を管理しています:文字列をエクスポートし、翻訳者に送り、待ち、ファイルを受け取り、リポジトリにコピーし、マージコンフリクトを解決して、また繰り返す。頻繁にリリースしたり、複数の言語をサポートしたりする場合、このプロセスはすぐに破綻します。

より良い方法があります。GitHubリポジトリを翻訳管理システムに直接接続することで、コード内の新しい文字列の検出から完成した翻訳のプルリクエストとしての配信まで、サイクル全体を自動化できます。

このガイドでは、better-i18nを使用してGitHubとの自動翻訳同期を設定する方法を説明します。Webhookのメカニズム、PRベースの配信ワークフロー、マルチリポジトリ設定、Doctor CIヘルスチェックワークフローについて解説します。

なぜ翻訳同期を自動化するのか?

セットアップに入る前に、手動翻訳ワークフローのコストを理解することが重要です:

  • コンテキストスイッチング — 開発者がコードと翻訳ファイルの間を行き来する
  • 古い翻訳 — 手動エクスポートは翻訳者が古いソース文字列で作業することを意味する
  • マージコンフリクト — 複数の人が触れるとJSONの翻訳ファイルはコンフリクトの温床になる
  • カバレッジ不足 — 新機能が翻訳なしでリリースされたかどうかを自動的に確認する方法がない
  • 遅い配信 — 翻訳が継続的に流れる代わりにキューで待機する

GitHubと翻訳プラットフォーム間の同期を自動化することで、これらのボトルネックが解消されます。リポジトリへのすべてのプッシュがキー検出をトリガーします。完成したすべての翻訳がプルリクエストとして返ってきます。CIチェックが本番環境に到達する前に翻訳の欠落をキャッチします。

アーキテクチャの概要

同期システムには2つの方向があります:

インバウンド(コードからクラウドへ): 開発者がコードをプッシュすると、GitHubはbetter-i18nにWebhookを送信します。プラットフォームは翻訳ファイルを読み込み、新しいまたは変更されたキーを検出し、クラウドダッシュボードを更新します。翻訳者はすぐに新しい文字列を確認できます。

アウトバウンド(クラウドからコードへ): 翻訳が完成すると、better-i18nは更新されたJSONファイルを含むプルリクエストをリポジトリに作成します。チームは標準的なコードレビューワークフローを通じてレビューとマージを行います。

両方向ともHMAC-SHA256署名検証で保護されています。認証されていないペイロードは処理されません。

ステップ1:GitHub Appをインストールする

GitHubアカウントをbetter-i18nに接続することから始めます:

  1. dash.better-i18n.comにアクセスし、プロジェクト設定を開く
  2. Connect GitHubをクリックしてbetter-i18n GitHub Appをインストールする
  3. アプリがアクセスできるリポジトリを選択する — 特定のリポジトリまたは組織全体へのアクセスを許可できます
  4. 要求された権限を承認する

better-i18nは最小限の権限を要求します:

権限目的
Repository Contents翻訳ファイルの読み取り/書き込み(設定されたパターンに一致するファイルのみ)
Pull Requests翻訳更新のPRを作成
WebhooksSync をトリガーするプッシュイベントを受信

アプリはソースコード、環境変数、シークレット、または翻訳ファイルパターン外のファイルには決してアクセスしません。

ステップ2:リポジトリを追加する

GitHub Appがインストールされたら、同期したいリポジトリを追加します。ダッシュボードまたはプログラムから行うことができます:

github.addRepository({
  project: "your-org/your-project",
  repositoryId: 123456789,
  branch: "main",
  filePattern: "locales/{locale}/{namespace}.json"
})

filePatternパラメータはbetter-i18nに翻訳ファイルの場所を伝えます。一般的なパターンは:

  • locales/{locale}/{namespace}.json — ネームスペースファイルを含むロケールフォルダ
  • src/i18n/{locale}.json — ロケールごとの単一ファイル
  • packages/*/locales/{locale}.json — パッケージごとの翻訳を持つMonorepo

マルチリポジトリサポート

単一のリポジトリに限定されません。better-i18nはいくつかのマルチリポジトリ設定をサポートしています:

  • Monorepo: 翻訳プロジェクトを共有する複数のアプリを持つ単一リポジトリ
  • マイクロフロントエンド: 共有翻訳セットに貢献する複数のリポジトリ
  • プラットフォーム + モバイル: 同じ翻訳ソースから同期するWebとモバイルのリポジトリ

各リポジトリは独自のファイルパターンとブランチ設定を持つことができます。翻訳はすべての接続されたリポジトリと中央クラウドプロジェクト間を流れます。

ステップ3:Webhookメカニズムを理解する

リポジトリが接続されると、GitHubはbetter-i18nにWebhookイベントを送信します。各イベントの動作は次のとおりです:

プッシュイベント

pushイベントは主要なSync トリガーです。接続されたブランチにコードをプッシュすると:

  1. GitHubはプッシュペイロードをbetter-i18nに送信します
  2. ペイロードの署名がHMAC-SHA256を使用して検証されます
  3. better-i18nは変更されたファイルが設定されたファイルパターンに一致するかを確認します
  4. 翻訳ファイルが変更された場合、Syncジョブが開始されます
  5. 新しいキーがクラウドプロジェクトに追加され、変更された翻訳が更新されます
  6. Syncステータスが追跡され、ダッシュボードに表示されます

設定されたブランチへのプッシュのみがSyncをトリガーします。明示的に設定していない限り、フィーチャーブランチへのプッシュはSyncをトリガーしません。

インストールライフサイクルイベント

イベント何が起こるか
installation.deleted統合が自動的にアンインストールされ、すべてのWebhookサブスクリプションがクリーンアップされます
installation.suspendSyncが一時停止 — インストールが再開されるまでWebhookは処理されません
installation.unsuspendSyncが再開 — Webhookが通常通り再処理されます

これらのイベントにより、統合がGitHub Appインストール状態と同期され続けることが保証されます。組織管理者がアプリを一時停止した場合、better-i18nは失敗したWebhook配信を蓄積する代わりに、すぐに処理を停止します。

ステップ4:PRベースの翻訳ワークフローを設定する

アウトバウンドフロー — 翻訳をリポジトリに戻す配信 — は直接プッシュではなくプルリクエストを使用します。これは意図的なデザインの選択です:

なぜプルリクエストなのか?

  • コードレビューは翻訳にも適用されます。 レビュアーは翻訳が本番環境に到達する前に、コンテキストの問題、プレースホルダーエラー、またはフォーマットの問題を発見できます。
  • CIが翻訳変更に対して実行されます。 テストスイート、リンター、ビルドプロセスが新しい翻訳が何も壊さないことを検証します。
  • gitでの完全な監査トレイル。 すべての翻訳変更は、何が変更されたかを正確に示す明確なdiffを持つコミットです。
  • 簡単なロールバック。 他の変更を元に戻すのと同じ方法で翻訳PRを元に戻します。

仕組み

  1. 翻訳者またはAIエージェントがbetter-i18nダッシュボードで翻訳を更新する
  2. 翻訳のバッチが準備できたら、パブリッシュをトリガーする
  3. better-i18nがリポジトリにブランチを作成する(例:better-i18n/translations-2026-03-13
  4. 更新された翻訳JSONファイルがそのブランチにコミットされる
  5. 設定されたベースブランチに対してプルリクエストがオープンされる
  6. チームがdiffをレビューし、満足したらマージする

PRには翻訳ファイルのみが含まれます — 他のファイルは触れられません。diffはどのキーがどの言語で変更されたかを明確に示します。

翻訳をパブリッシュする

複数のチャンネルを通じてパブリッシュをトリガーできます:

  • ダッシュボード: プロジェクト設定の「Publish to GitHub」ボタンをクリックする
  • REST API: パブリッシュエンドポイントをプログラムから呼び出す
  • MCPツール: AIエージェントワークフローからpublishTranslationsを使用する

ステップ5:Doctor CIワークフローを有効にする

Doctorワークフローは、すべてのコミットで翻訳の健全性を監視するGitHub Actionsワークフローです。翻訳のためのESLintと考えてください。

ワークフローを生成する

tRPC APIを使用してワークフローファイルを生成します:

github.createDoctorWorkflow({
  project: "your-org/your-project",
  repositoryId: 123456789
})

これによりリポジトリに.github/workflows/i18n-doctor.ymlファイルが作成されます。

Doctorが確認すること

翻訳の欠落 — ソース言語には存在するが、1つ以上のターゲット言語に存在しないキー。Doctorは言語ごとの正確な数を報告します。

未使用のキー — 翻訳ファイルで定義されているが、コードベースで一度も参照されていないキー。これらは翻訳バンドルを肥大化させ、翻訳者を混乱させます。

フォーマットの一貫性 — 全言語にわたるICUメッセージ構文の検証。英語では{count}だがスペイン語では{nombre}のような不一致なプレースホルダーや壊れた複数形ルールなどのエラーをキャッチします。

カバレッジレポート — 進捗を一目で追跡できるよう言語ごとの完了率。

Doctorの出力例

i18n Doctor Report
==================

Coverage:
  en: 100% (source)
  tr: 94.2% (missing 23 keys)
  de: 87.1% (missing 51 keys)
  ja: 78.3% (missing 86 keys)

Unused keys: 12
Format errors: 0

Result: WARNING — 3 languages below 95% threshold

DoctorはGitHubのチェックシステムと統合されます。翻訳の欠落やフォーマットエラーを導入するプルリクエストには警告ステータスが表示され、レビュアーに翻訳の影響への即時の可視性を提供します。

DoctorとCLIを組み合わせる

最も徹底的なカバレッジのために、CIパイプラインでDoctorとbetter-i18n CLIを組み合わせます:

name: i18n Health Check
on: [push, pull_request]

jobs:
  i18n:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"

      # 翻訳すべきハードコードされた文字列をスキャン
      - name: Scan for untranslated strings
        run: npx @better-i18n/cli scan --ci

      # ローカルキーをクラウドプロジェクトと比較
      - name: Sync coverage report
        run: npx @better-i18n/cli sync --format json

      # Doctorは生成されたワークフローを通じて自動的に実行される

scan --ciコマンドは未翻訳の文字列が見つかった場合にゼロ以外のコードで終了し、PRをブロックします。sync --format jsonコマンドは機械可読なカバレッジレポートを出力します。

ステップ6:pre-commitフックを設定する

コードがコミットされる前に — さらに早く翻訳の問題をキャッチします — pre-commitフックを使用して:

# Huskyを使用して
npx husky init
echo "npx @better-i18n/cli scan --staged --ci" > .husky/pre-commit

--stagedフラグはCLIに現在のgitステージングエリアのファイルのみをスキャンするよう指示し、大規模なコードベースでもフックを高速に保ちます。

より細かい制御のために、lint-stagedを使用します:

{
  "lint-staged": {
    "*.{tsx,jsx}": ["better-i18n scan --ci"]
  }
}

Sync追跡とObservability

すべてのSync操作 — インバウンドまたはアウトバウンド — は完全なステータスとログを持つジョブとして追跡されます。MCPツールまたはREST APIを通じてSync履歴を照会できます:

表示されるSyncタイプ:

  • initial_import — リポジトリが接続された際の最初のSync。既存のすべての翻訳ファイルをインポートします。
  • source_sync — GitHubプッシュイベントによってトリガーされます。変更された翻訳ファイルをクラウドに同期します。
  • cdn_upload — ランタイム消費のためにCDNに翻訳をDeployします。
  • batch_publish — 翻訳をプルリクエストとしてGitHubに戻して公開します。

各ジョブにはタイムスタンプ、ステータス(保留中、実行中、完了、失敗)、デバッグ用の詳細ログが含まれます。

すべてをまとめる

セットアップ後の完全な自動翻訳ワークフローは次のとおりです:

  1. 開発者がユーザー向けの文字列を含む新機能を追加する
  2. コンポーネントでuseTranslations('namespace')またはgetTranslations('namespace')を使用する
  3. pre-commitフックがscan --stagedを実行し、未翻訳の文字列について警告する
  4. 開発者がGitHubにプッシュする
  5. プッシュWebhookがインバウンドSyncをトリガーする — 新しいキーがbetter-i18nダッシュボードに表示される
  6. Doctor CIがPRで実行され、翻訳カバレッジを報告する
  7. 翻訳者(またはMCP経由のAIエージェント)が新しいキーを翻訳する
  8. 翻訳がパブリッシュされる — 更新されたJSONファイルを含むPRがリポジトリに作成される
  9. チームが翻訳PRをレビューしてマージする
  10. CDN DeployがランタイムでSyncに翻訳をすぐに利用可能にする

サイクル全体が手動ファイルコピー、エクスポート/インポートステップ、またはマージコンフリクト解消なしで実行されます。翻訳はコードベースとクラウド間を継続的に流れます。

一般的な設定

複数のアプリを持つMonorepo

your-monorepo/
├── apps/
│   ├── web/
│   │   └── locales/{locale}/{namespace}.json
│   └── admin/
│       └── locales/{locale}/{namespace}.json

両方のアプリをカバーするファイルパターンでリポジトリを一度接続します:apps/*/locales/{locale}/{namespace}.json

プラットフォームごとの別々のリポジトリ

各リポジトリを独自のファイルパターンで独立して接続します。翻訳は中央クラウドプロジェクトを通じて共有されます — 一度更新して、すべてのリポジトリにパブリッシュします。

フィーチャーブランチワークフロー

デフォルトでは、Syncは設定されたベースブランチ(通常main)へのプッシュのみでトリガーされます。フィーチャーブランチで翻訳Syncを希望するチームの場合、リポジトリ設定で複数のブランチを設定します。

まとめ

GitHubとの翻訳Syncを自動化することで、国際的な製品開発を遅らせる手動のボトルネックが解消されます。Webhookによるインバウンドの同期により、翻訳者は新鮮な文字列で作業を続けられます。PRベースのアウトバウンド配信により、翻訳の変更がコードと同じレビュープロセスを経ることが保証されます。Doctor CIは本番環境に到達する前にカバレッジのギャップをキャッチします。

セットアップには約15分かかります:GitHub Appをインストールし、リポジトリを追加し、ファイルパターンを設定し、Doctorワークフローを有効にします。その時点から、翻訳はコードベースとクラウド間を自動的に流れます。

複数のリポジトリにわたって翻訳を管理している場合、またはいくつか以上の言語のユーザーに配信している場合、この自動化は最初のスプリントで元が取れます。

Comments

Loading comments...