Claude Codeでpoファイルを翻訳 — プレースホルダを壊さず埋める手順
gettextの.poファイルの未翻訳をClaude Codeで埋め、%sや{name}、複数形を壊していないかをmsgfmtで検証する手順です。CLAUDE.mdの規約とfuzzの扱いも示します。
.po ファイルの未翻訳をClaude Codeに埋めさせるときの要点は、訳す作業と検証を分けることです。訳文を書くのはClaude Code、%s や {name} が壊れていないかを判定するのは msgfmt に任せます。この分担にしておくと、訳の質は読んで確かめ、機械的な破損はコマンドの終了コードで確かめられます。
この記事では、日本語(ja)の .po を例に、未翻訳の抽出、規約の渡し方、翻訳後の検証、fuzzy の扱いを順に示します。検証コマンドの出力は、手元のGNU gettext-tools 1.0の msgfmt で実際に流したものです。
.poファイルのどこをClaude Codeに触らせるか
GNU gettextの手引きは、POファイルを「翻訳者とプログラマーが作り、更新し、使うためのテキストファイル」と位置づけています。編集できるテキストなので、Claude Codeが直接読み書きできます。
1つの項目(エントリ)は、おおよそ次の形です。
#: src/main.c:20
#, c-format
msgid "%d file removed"
msgid_plural "%d files removed"
msgstr[0] ""Claude Codeに書かせてよいのは msgstr の中身だけです。それ以外は次の理由で触らせません。
msgidとmsgid_pluralは原文です。変えると次にmsgmergeをかけたとき、訳が原文と対応しなくなります#,行のフラグは、xgettextが付けるものです。c-formatのような*-formatフラグを人が足す想定はなく、手で変えても新しいテンプレートの生成で戻りますmsgctxtは、同じ原文を文脈で訳し分けるための鍵です。書き換えると、プログラム側のpgettextの呼び出しと合わなくなります
つまり、プロンプトの時点で「msgstr 以外は変更しない」と言い切っておくのが安全です。
未翻訳だけを抜き出して渡す
ファイル全体を読ませると、翻訳済みの項目まで訳し直されがちです。msgattrib --untranslated は、未翻訳の項目だけを残して出力します。
msgattrib --untranslated ja.po手元の検証用ファイルで流すと、ヘッダーエントリと、未翻訳の Open(msgctxt "menu" 付き)だけが出ました。翻訳済みの3件は含まれません。
Claude Codeには、この出力を見せたうえで ja.po 本体を編集させます。未翻訳の数は、あとで msgfmt --statistics と突き合わせます。
規約をCLAUDE.mdに書いておく
プレースホルダの扱いを毎回プロンプトに書くのは手間なので、プロジェクトの CLAUDE.md に置きます。公式の概要ページによれば、CLAUDE.md はプロジェクトのルートに置くMarkdownで、Claude Codeがセッションの開始時に読み込みます。
例えば、次のような内容です。
# .po 翻訳の規約
- 編集してよいのは msgstr だけ。msgid / msgid_plural / msgctxt / #, 行は変えない
- %s %d %1$s などの printf 書式は、msgid と同じ種類・同じ個数を残す
- {name} のような波括弧の名前は、綴りを含めて msgid と一致させる
- 語順を変えるときは %1$s のように番号付きにする
- 複数形は、ヘッダーの Plural-Forms が示す数だけ msgstr[N] を書く(ja は msgstr[0] のみ)
- 訳に迷う項目は #, fuzzy を付けて残す。確信がないまま埋めない
- 編集後に msgfmt -c --statistics -o /dev/null ja.po を実行し、エラー 0 を確認する最後の1行は、検証をClaude Codeに自分で回させるためのものです。エラーが出れば、出力を読んで自分で直す反復が成立します。
翻訳後にmsgfmtで壊れを検出する
検証の中心は msgfmt -c です。手引きによると -c(--check)は --check-format、--check-header、--check-domain をまとめて実行します。書式の検査は、エントリに c-format などのフラグが付いている場合に行われます。
msgfmt -c --statistics -o /dev/null ja.po-o /dev/null は、検査だけして .mo を作らないための指定です。
壊れた訳を入れたときの出力
次の2か所をわざと壊した .po で試しました。
Cannot open file %s: %sを、書式指定子が1個しかない訳にしたHello, {name}!の訳で、{name}を{namae}と綴り違いにした
実際の出力は次のとおりです(ヘッダーの警告は省略)。
bad.po:13: number of format specifications in 'msgid' and 'msgstr' does not match
bad.po:27: a format specification for argument 'namae', as in 'msgstr', doesn't exist in 'msgid'
msgfmt: found 2 fatal errors終了コードは1でした。個数の不一致も、python-brace-format の綴り違いも検出されています。python-brace-format は {name} 形式の書式を示すフラグで、手引きのsticky flagsの一覧にも載っています。
綴りを直して流すと、エラーは出ず終了コードは0に変わり、3 translated messages, 1 untranslated message. と統計が出ました。
語順を変えるときは番号付き書式にする
手引きは、書式指定子の順番が入れ替わった訳を例に挙げ、%2$d のような番号付き表記が必要だと説明しています。日本語は語順が英語と違うため、この場面はよく起きます。
Cannot open file %s: %s を次のように訳すと、検査を通りました。
msgstr "%2$s: ファイル %1$s を開けません"同じ書式を、番号なしのまま逆順に書くと、型が合わず実行時に誤動作することがある、というのが手引きの指摘です。Claude Codeには「語順を入れ替えたら番号付きにする」と規約で指示しておきます。
msgfmtが見つけられないもの
msgfmt の検査は、書式の個数・型・名前の一致が中心です。次のものは判定できません。
- 訳が意味として合っているか
- 用語集どおりの訳語か
- 敬体と常体が混ざっていないか
- フラグが付いていない項目のプレースホルダ
最後の点が見落としやすい部分です。c-format などのフラグは xgettext が推定して付けるもので、手引きも推定は完全でないと書いています。フラグのない項目に %s を含む文字列があっても、msgfmt -c はその書式を検査しません。
対策として、Claude Codeには次の確認を別途させます。
grep -n '%[0-9$]*[sdf]\|{[a-z_]*}' ja.poこれで書式らしき文字列を含む行を洗い出し、msgid 側と msgstr 側を目で突き合わせます。用語や文体は、Claudeで用語集を使って翻訳を揃える手順のように、用語集を渡して揃える方法があります。訳の質をどう確かめるかは、Claude翻訳を検証してから確定するワークフローにまとめています。
複数形はPlural-Formsヘッダーの数に従う
複数形のエントリには msgid_plural があり、訳は msgstr[0]、msgstr[1] のように番号付きで並びます。何個書くかは、ヘッダーの Plural-Forms で決まります。手引きは、このフィールドを「POファイルに複数形がある場合に必要」と説明しています。
日本語の検証用ファイルのヘッダーは次の1行でした。
"Plural-Forms: nplurals=1; plural=0;\n"nplurals=1 なので、日本語の訳は msgstr[0] だけです。英語の感覚で msgstr[1] まで書かせてしまうと、ヘッダーと合いません。他の言語に流用するときは、その言語のヘッダーの nplurals を先に確認し、Claude Codeに「この数だけ書く」と伝えます。
ヘッダーの Content-Type の charset=UTF-8 も重要です。日本語を書くならUTF-8にします。手引きも、どの言語でも使える符号化としてUTF-8を挙げています。
fuzzyは翻訳済みとして数えられない
fuzzy は、訳が正しくない可能性があるという印です。手引きによると、msgmerge が曖昧一致で項目を引き継いだときに付くほか、翻訳者が自分で付けることもできます。確認が済んだら、翻訳者が外す決まりです。
fuzzy の項目はビルド時に使われません。手元で #, fuzzy 付きの項目だけを持つファイルに --statistics をかけると、次のとおりでした。
0 translated messages, 1 fuzzy translation.msgstr に訳が入っていても、翻訳済みには数えられません。msgfmt には --use-fuzzy(-f)がありますが、手引きは「fuzzy の項目は人の翻訳者が検証していないものなので、これを使うのは通常は誤り」と注意しています。
運用としては、項目の状態ごとに次のように分けられます。
| 項目 | Claude Codeの扱い | 人間の作業 |
|---|---|---|
| 訳に自信がある | Claude Codeの扱いfuzzy を付けずに埋める | 人間の作業抜き取りで読む |
| 訳に迷う | Claude Codeの扱い#, fuzzy を付けて埋める | 人間の作業確認して fuzzy を外す |
既存の fuzzy 項目 | Claude Codeの扱い触らない、または直した旨を報告させる | 人間の作業確認して fuzzy を外す |
fuzzy を外す作業をClaude Codeに任せるかどうかは、レビューの体制で決まります。外す行為は「人間が確認した」という意味を持つので、外す権限を人に残す運用もあります。
権限を絞って検証を自動化する
検証コマンドを毎回承認するのは面倒です。読み取り中心の msgfmt と msgattrib だけを許可しておく方法があります。
{
"permissions": {
"allow": [
"Bash(msgfmt *)",
"Bash(msgattrib *)"
]
}
}ルールはコマンド名の後ろに * を置く形で書きます。msgmerge のように .po を書き換える可能性のあるコマンドは、許可に入れずに承認制のままにしておくと、意図しない上書きを防げます。
ヘッダーの警告とアクセラレーターの検査
先ほどの出力では省略しましたが、手元の検証用ファイルに msgfmt -c をかけると、書式のエラーとは別に次の警告が出ました。
warning: header field 'PO-Revision-Date' missing in header
warning: header field 'Last-Translator' missing in header
warning: header field 'Language-Team' missing in header--check-header がヘッダーエントリの項目を検査した結果です。手引きは、ヘッダーの Project-Id-Version などを埋める手順を別の節で説明しています。Claude Codeに翻訳を任せるなら、Last-Translator や PO-Revision-Date を誰が更新するかも決めておくと、警告が残りません。
メニュー項目のように & でキーボードの目印を示すアプリ向けには、--check-accelerators があります。原文の & がちょうど1個なら、訳文の & も1個でなければならない、という検査です。& を使うGUIの翻訳では、msgfmt -c --check-accelerators のように足します。
同じ原文でも文脈で訳が変わる項目
msgctxt が付いた項目は、同じ msgid が別の場所にもあります。検証用ファイルの Open は msgctxt "menu" 付きでした。手引きによると、msgctxt の文字列は翻訳者にも見え、何度も変えると翻訳のやり直しが必要になるため、変わらない文字列にすべきだとされています。
Claude Codeに渡すときは、同じ msgid の項目をまとめて見せ、msgctxt ごとに別の訳にしてよいと伝えます。「Openは『開く』で統一」のような用語表を渡すと、文脈の違う項目まで同じ訳にそろえてしまうおそれがあります。
非対話モードで回す
公式の概要ページには、claude -p にパイプで入力を渡し、スクリプトやCIから呼び出す例があります。同じ形で、未翻訳の抽出と翻訳依頼を1行にできます。
msgattrib --untranslated ja.po | claude -p "各項目のmsgstrの案を一覧にして"この形はファイルを直接書き換えず、訳の案を標準出力に出すだけです。案を人が読んでからファイルに反映するので、fuzzy を付けるか迷う項目の下見に向きます。ファイルを書き換えさせるなら、先に述べた権限設定を確認してから使います。
実行の順番
最後に、1回の作業の流れをまとめます。
.po翻訳の1サイクル
- 1
未翻訳を抜き出す
msgattrib --untranslated ja.poで件数と内容を確認します。 - 2
msgstrだけ埋めさせる
CLAUDE.mdの規約に沿って、迷う項目にはfuzzyを付けさせます。 - 3
msgfmtで検証する
msgfmt -c --statistics -o /dev/null ja.poを実行し、エラー 0を確認します。 - 4
書式らしき行を突き合わせる
フラグのない項目は
grepで洗い出して目視します。 - 5
fuzzyを人が確認する
確認した項目から
fuzzyを外し、統計のfuzzyが0になるまで繰り返します。
同じ「設定を作って検証コマンドで確かめる」型の作業は、Claude CodeでsystemdのUnitファイルを作成する手順にもあります。Docusaurusの翻訳ファイルで同じことをするなら、Claude CodeでDocusaurusサイトを作る手順が参考になります。
まとめ
.po 翻訳でClaude Codeに任せるのは msgstr の中身だけです。msgfmt -c が書式の個数・型・名前の壊れを止めますが、訳の意味やフラグのない項目は検査の外にあります。そこは grep での突き合わせと、fuzzy の人による確認で埋めます。
規約を CLAUDE.md に置き、検証コマンドを自分で回させる構成にしておけば、翻訳の更新のたびに同じ品質の確認を繰り返せます。