ブログに戻る
A git diff view showing a locale file with three changed keys highlighted, and only those three keys being sent to the translation API below.

すべてを再翻訳する必要はありません:CIでのデルタ翻訳の仕組み

By Robert M

すべてを再翻訳する必要はありません:CIにおけるデルタ翻訳の仕組み

自動翻訳をCIパイプラインに組み込むと、自然に次の疑問が浮かびます:誰かが変更をプッシュするたびに、ロケールファイル全体を再翻訳するのでしょうか?

デルタモードなしでは、はい。ソースロケールファイルに触れるすべてのプッシュは、変更の有無にかかわらず、すべてのキー、すべての文字列をAPIに送信します。小規模な初期プロジェクトでは問題ありませんが、10〜20言語にわたる数百の翻訳キーを持つ成熟したプロジェクトでは、前回の実行以降変更されていない文字列にトークンを消費し、同一の出力を得るだけになってしまいます。

デルタ翻訳はこれを解決します。ファイル全体を送信する代わりに、Actionは現在のソースファイルと保存されたベースラインを比較し、追加または変更されたキーのみを特定してAPIに送信します。変更のないキーの出力は既存の翻訳ファイルから取得されます。トークン使用量は実際の作業量に合わせて減少します。


ベースラインの仕組み

デルタモードが初めて実行されるとき、または完全なリフレッシュを強制したとき、Actionはソースファイル全体を翻訳し、その平坦化されたJSON表現をベースラインファイルとしてリポジトリに保存します。以降の実行では、そのベースラインを読み込み、現在のソースファイルと差分を取り、変更されたキーのみを含むペイロードを作成します。

JSONロケールファイルの場合、ベースラインはメッセージディレクトリ内の .polylingo-baseline.json に保存されます。YAMLロケールファイルの場合はロケールディレクトリ内の .polylingo-yaml-baseline.json に、Laravel PHP langファイルの場合はlangディレクトリ内の .polylingo-laravel-php-baseline.json に保存されます。

ベースラインは翻訳ファイルと共にコミットされるため、リポジトリと一緒に移動します。リポジトリをクローンする開発者は、パイプラインが使用しているのと同じベースラインを取得します。


変更とみなされるもの

差分はソースファイルの平坦化されたキー表現に対して行われます。ネストされた構造は比較前にドット表記のキーに平坦化されます:

{
  "nav.home": "ホーム",
  "nav.about": "私たちについて",
  "hero.title": "私たちのプラットフォームへようこそ",
  "hero.cta": "始める"
}

デルタペイロードに含まれるキーは以下の場合です:

  • 現在のソースファイルに存在し、ベースラインに存在しない(新しいキー)
  • 両方に存在するが値が変更された(変更されたキー) ベースラインに存在し、現在のソースファイルに存在しないキー(削除されたキー)は翻訳出力ファイルから自動的に削除されます。両方で同一のキーは完全にスキップされ、既存の翻訳はそのまま残されます。

実際の例

Next.jsプロジェクトに200の翻訳キーが messages/en.json にあり、すでに12言語に翻訳されているとします。開発者がヒーローセクションの文言を更新し、機能発表用に2つの新しいキーを追加しました。200中4つのキーが変更されました。

デルタモードなしでは、パイプラインは毎回12言語分の200キーすべてを送信します。デルタモードでは4キーのみ送信します。その実行のトークン使用量は完全翻訳の約2%です。送信量が少なく待ち時間も短いため、パイプラインも高速です。

1か月の定期的な開発で、この節約は大きく積み重なります。ほとんどのプッシュは数文字列にしか触れません。完全な再翻訳は新しい言語を追加したときやベースラインを明示的にリセットしたときのみ発生します。


PolyLingoの3つのGitHub Actions

デルタモードは3つのPolyLingo翻訳Actionsすべてで利用可能です。それぞれ特定のコンテンツタイプとプロジェクト構造向けに作られています。

translateAction — JSONとMarkdown

オリジナルのAction。next-intlやi18nextスタイルのフラットなJSONロケールファイルを扱い、大きなファイル向けに非同期ジョブAPIを使ったMarkdownドキュメント処理もオプションで対応します。

- uses: UsePolyLingo/translate-action@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    source_file: messages/en.json
    locales: fr,de,es,ja,zh
    delta: true
    commit: true
    commit_message: "chore(i18n): sync translations"

デルタベースライン: messages/.polylingo-baseline.json

github.com/UsePolyLingo/translateActionMarketplaceで見る


translate-action-yaml — YAMLロケールファイル

ネストされたYAMLロケールファイルを使うプロジェクト向け:Rails i18n、Vue i18n、その他YAML形式を使うフレームワーク。ActionはRailsのルートロケールキーの慣習を自動処理します — en.ymlen: ルートキーを持ち、各出力ファイルは正しいターゲットロケールキー(fr:de:など)を持ちます。

PolyLingo APIはJSONをネイティブに扱うため、ActionはネストされたYAMLをドット表記のJSONに平坦化して送信し、翻訳後にネスト構造を再構築して有効なYAML出力を書きます。v1の注意点として、ドットを含むキーはドット表記の平坦化と衝突するためサポートされません。

- uses: UsePolyLingo/translate-action-yaml@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    locales_dir: config/locales
    source_file: config/locales/en.yml
    locales: fr,de,es,ja
    delta: true
    commit: true

デルタベースライン: config/locales/.polylingo-yaml-baseline.json

github.com/UsePolyLingo/translate-action-yamlMarketplaceで見る


translate-action-laravel — Laravel langファイル

Laravelプロジェクト向けで、JSON翻訳ファイル(lang/en.json、Laravel 9+スタイルのネスト・フラット両対応)またはPHP配列langファイル(lang/en/*.php)を使用。Actionは php_format: auto でプロジェクトのフォーマットを自動検出し、まず lang/en.json を探し、なければPHP配列ファイルにフォールバックします。

PHPファイルの場合、PHP CLIを呼び出してソースファイルを読み込み、翻訳出力をJavaScript内で有効なPHP配列構文にシリアライズします。追加の依存関係は不要です。GitHubホストの ubuntu-latest ランナーはデフォルトでPHP 8.xを含むため追加設定は不要。PHP 7.4以上が必要です。

v1の注意点として、ドットを含むキーはドット表記の平坦化戦略のためPHPモードではサポートされません。

- uses: UsePolyLingo/translate-action-laravel@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    lang_dir: lang
    source_locale: en
    locales: fr,de,es,pt,nl
    php_format: auto
    delta: true
    open_pr: true

デルタベースライン: フォーマットに応じて lang/.polylingo-laravel-json-baseline.json または lang/.polylingo-laravel-php-baseline.json

github.com/UsePolyLingo/translate-action-laravelMarketplaceで見る


PRモード vs コミットモード

3つのActionすべてが2つの出力モードをサポートします。

コミットモード (commit: true) は翻訳ファイルを書き込み、現在のブランチに直接コミットします。設定が簡単で、翻訳をレビュー不要の自動化プロセスとして扱うチームに適しています。

PRモード (open_pr: true) は新しいブランチ(polylingo/yaml-<sha>polylingo/laravel-<sha>など)を作成し、翻訳ファイルを書き込み、ベースブランチに対してプルリクエストを開きます。翻訳内容のマージ前に人間のレビューを行いたいチームや、翻訳品質がユーザー体験に直接影響するプロジェクトに適しています。

両方設定されている場合はPRモードが優先されます。

PRモードにはワークフローの権限で pull-requests: write が必要です:

permissions:
  contents: write
  pull-requests: write

完全リフレッシュの強制

デルタモードは保存されたベースラインと比較します。ベースラインに関係なくすべてを再翻訳したい場合は delta: false を設定してください。これによりベースラインも現在のソースファイルに合わせて更新され、以降のデルタ実行は新しい状態から始まります。

完全リフレッシュは、新しいターゲット言語を追加したとき、新しいモデルバージョンで翻訳品質の改善を取り込みたいとき、または何らかの理由でベースラインが実際の状態からずれてしまったときに有用です。

- uses: UsePolyLingo/translate-action-yaml@v1
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    locales_dir: config/locales
    locales: fr,de,es,ja,zh,ko,ar
    delta: false  # 完全リフレッシュ、ベースライン更新
    commit: true

下流ステップへの出力

3つのActionはすべて同じ出力を公開しているため、後続のワークフローステップで使用できます:

- uses: UsePolyLingo/translate-action@v1
  id: translate
  with:
    api_key: ${{ secrets.POLYLINGO_API_KEY }}
    source_file: messages/en.json
    locales: fr,de,es
    delta: true
    commit: true

- name: 翻訳統計のログ出力
  run: |
    echo "翻訳されたロケール: ${{ steps.translate.outputs.locales_translated }}"
    echo "変更されたファイル数: ${{ steps.translate.outputs.files_changed }}"
    echo "使用トークン数: ${{ steps.translate.outputs.tokens_used }}"

各実行はGitHub Actionsのステップサマリーに要約テーブルも書き込み、ログを掘り下げなくてもトークン使用量や翻訳結果を確認できます。


はじめに

3つのActionはすべてGitHub Marketplaceで利用可能です。PolyLingo APIキーが必要で、usepolylingo.com で無料で入手できます。無料プランは月50,000トークンを含みます。デルタモードを有効にすると、ほとんどのプロジェクトは通常の開発プッシュでその範囲内に収まります。

APIキーをリポジトリのシークレット(POLYLINGO_API_KEY)として追加し、該当するActionをワークフローに組み込みます。最初の実行は完全翻訳を行いベースラインを設定します。その後の実行は変更された部分のみを翻訳します。