WordPress JSON翻訳: ブロックエディターのJavaScriptを翻訳する

プラグインを翻訳しました。PHPの文字列は管理設定、フロントエンドのテンプレート、メール通知など、すべてローカライズされて完璧に表示されます。しかし、ブロックエディターを開くと、カスタムGutenbergブロック内のすべてのラベルが頑固に、そして嘲笑うかのように英語のままです。「Add Item」ボタン、インスペクターパネルの見出し、プレースホルダーテキスト。.moファイルは読み込まれています。では、なぜこれらの文字列は翻訳されないのでしょうか?
WordPress 5.0とGutenbergの登場以来、JavaScriptの文字列は.moファイルからは一切取得されないためです。それらは、スクリプトごとに完全に別個のWordPress JSON翻訳ファイルを必要とします。そして、もしあなたがそれを生成しない限り、.poファイルがどれほど完璧であっても、ブロックエディターは英語のままです。これは、現代のWordPress開発において最も一般的で混乱を招くローカライズのギャップの1つです。このガイドでは、それがなぜ起こるのか、JSON翻訳システムがどのように機能するのか、誰もが戸惑うMD5ハッシュのファイル名、そしてそれを修正するための完全なツールチェーンについて正確に説明します。
なぜブロックエディターの文字列は英語のままなのか
簡潔に言うと、WordPressではPHPとJavaScriptが完全に異なる2つの翻訳配信システムを使用しており、.moファイルはPHPのものにしか供給されないためです。
2つの翻訳システム、1つのプラグイン
WordPressがload_plugin_textdomain()を実行すると、コンパイルされた.moファイルがPHPのメモリに読み込まれます。PHPコード内のすべての__()、_e()、_x()呼び出しは、そこから翻訳を探します。これは、PHPがサーバーサイドでレンダリングされるため機能します。.moデータは同じプロセス内にあります。
JavaScriptは異なります。ブロックコードはブラウザで実行され、PHPが完了してから時間が経っています。サーバーサイドの.moファイルにアクセスすることはできません。代わりに、GettextのJS版である@wordpress/i18nパッケージ(__()、_x()、sprintf()をスクリプトに公開します)は、必要な特定のスクリプトにアタッチされたJSONペイロードとして翻訳が配信されることを期待します。
未翻訳のJS文字列に何が起こるか
したがって、次のような文字列を持つブロックは:
import { __ } from '@wordpress/i18n';
registerBlockType( 'myplugin/feature-box', {
title: __( 'Feature Box', 'myplugin' ),
edit: () => {
return <Button>{ __( 'Add Item', 'myplugin' ) }</Button>;
},
} );
「Feature Box」や「Add Item」を.moファイルに見つけることは決してありません。ブラウザは.moファイルを読み込まないからです。これらの文字列は、この正確なスクリプトハンドルに紐付けられたJSONとして到着する必要があります。これを設定していない場合、JSの__()呼び出しは単に元の英語を返します。コンソールにエラーも表示されず、サイレントに実行されます。
wp_set_script_translations()でJSON翻訳を接続する
スクリプトとそのJSON翻訳をつなぐ橋渡しとなるのは、wp_set_script_translations()という単一のPHP関数です。「WordPressがどのJSONファイルがどのスクリプトに属するかをどのように知るのか」という問いへの答えは、スクリプトを登録し、そのテキストドメインとJSONが存在するフォルダーを宣言することによって、あなたがWordPressに教える、ということです。
スクリプトとその翻訳フォルダーを登録する
add_action( 'init', function () {
wp_register_script(
'myplugin-editor',
plugins_url( 'build/index.js', __FILE__ ),
array( 'wp-blocks', 'wp-i18n', 'wp-element' ),
'1.0.0'
);
// Tell WordPress where this script's JSON translations live
wp_set_script_translations(
'myplugin-editor', // the registered script handle
'myplugin', // text domain
plugin_dir_path( __FILE__ ) . 'languages'
);
} );
エディターがmyplugin-editorを読み込むと、WordPressはlanguages/フォルダー内でこのスクリプトと現在のユーザーのロケールに一致するJSONファイルを探すことを認識します。もし見つかれば、スクリプトが実行される前に翻訳を挿入し、JSの__()呼び出しは正しく解決されます。渡すハンドルは登録されたスクリプトと完全に一致している必要があります。ハンドルが一致しない、または欠落していることが、翻訳がサイレントに失敗する2番目に一般的な理由です。
誰も予想しないMD5ハッシュのファイル名
これがほとんどの人がつまずく詳細です。WordPressが探すJSONファイルは、myplugin-fr_FR.jsonのようなきれいな名前ではありません。スクリプトのソースパスのMD5ハッシュで名付けられています。
ファイル名パターンの解読
myplugin-fr_FR-a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6.json
パターンは{textdomain}-{locale}-{md5}.jsonで、ハッシュは登録されたスクリプトファイルへの相対パス(例:build/index.js)のMD5です。WordPressは、適切なスクリプトに対して適切なJSONを見つけるために、実行時にこのハッシュを計算します。手動でファイル名を変更すると、WordPressは見つけることができず、システムが壊れていると誓うでしょうが、実際には別のファイル名を探しているだけです。
ハッシュは自分で計算しません。WP-CLI i18nコマンドがそれを行ってくれます。これが、手作業でこれらのファイルを作成するのではなく、ツールを使用しなければならない正確な理由です。ただし、ハッシュが存在することを理解することは、JSONファイルがlanguages/に存在しても無視される場合に、何時間も節約することになります。それはほとんど常に、スクリプトパスの変更によるファイル名のハッシュの不一致です。
完全なワークフロー:make-potからmake-jsonへ
良いニュースは、翻訳をすでに使用している.poファイルに保持できることです。JSONは最後に生成される派生アーティファクトです。「JS文字列を別々に管理する必要がありますか」という問いへの答えはノーです。それらはPHP文字列と同じ.pot/.poに存在し、1つの追加コマンドでJS文字列がJSONに分割されます。
4つのコマンドパイプライン
完全なパイプラインは次のとおりです。
# 1. Extract ALL translatable strings (PHP and JS) into one template
wp i18n make-pot . languages/myplugin.pot
# 2. Translate languages/myplugin-fr_FR.po as usual (Poedit, AI, etc.)
# 3. Compile the .mo for PHP strings (server-side, as always)
wp i18n make-mo languages/
# 4. Generate the MD5-hashed JSON files for JS strings
wp i18n make-json languages/ --no-purge
ステップ1のmake-potは、.phpファイルと.js/.jsxソースの両方をスキャンするのに十分スマートなので、ロケールごとに1つの.poですべてを保持します。ステップ4のmake-jsonは、翻訳された各.poを読み込み、JavaScriptファイルから来たエントリを見つけて、スクリプトごとに正しくハッシュされたJSONを書き出します。--no-purgeフラグはJS文字列も.poに残すため、後のmake-moでそれらを失うことがありません。このフラグがないと、make-jsonはJSエントリを.poから削除し、コマンドを間違った順序で実行した人々を驚かせます。
生成されたJSONファイルは、Jed形式の翻訳セットのように見えます。
{
"translation-revision-date": "2026-06-12 10:00+0000",
"generator": "WP-CLI/2.x",
"domain": "messages",
"locale_data": {
"messages": {
"": { "domain": "messages", "lang": "fr_FR" },
"Feature Box": [ "Bloc fonctionnalité" ],
"Add Item": [ "Ajouter un élément" ]
}
}
}
WordPressはlocale_dataを読み込み、スクリプトが実行される前に@wordpress/i18nに渡します。これで、ブラウザで__( 'Add Item', 'myplugin' )がAjouter un élémentを返し、ブロックエディターがついにローカライズされます。
i18next JSONとの違い
どちらのシステムもJSONを使用し、どちらもJavaScriptを対象としているため、その表面的な類似性が実際の混乱を引き起こします。それらは交換可能ではありません。WordPressブロックエディターのJSONは、Gettextから派生したMD5ハッシュのスクリプトごとのペイロードであり、@wordpress/i18nによって消費されます。i18next JSONは、react-i18nextまたはnext-intlによって消費されるフラットまたはネストされたキーと値のファイルであり、独自の{{interpolation}}構文と複数形のキーの慣例を持っています。
WordPress以外でプレーンなReactまたはNext.jsで作業している場合は、i18nextのアプローチが必要です。これについては、ReactおよびNext.jsでi18next JSONを翻訳するで説明しています。WordPress内では、上記のmake-jsonワークフローが必要です。これらを混同する(たとえば、フラットなi18nextスタイルのJSONを手動で記述し、wp_set_script_translations()がそれをロードすることを期待する)と、WordPressがハッシュされたJed形式を探しており、任意のキーと値のペアを探しているわけではないため、単に機能しません。
1つのソース、必要なすべての形式
これらすべてにおいて脆弱なのは、途中にある翻訳ステップです。.poファイルは.mo(PHP)とJSON(JavaScript)の両方に供給されるため、1つの翻訳ミス(破損した%s、壊れた<strong>タグ、変更された複数形)が両方の出力に同時に悪影響を及ぼします。また、JS文字列はブラウザで非同期に読み込まれるため、構造上のエラーは、優雅なフォールバックではなく、空白のラベルやハードクラッシュとして現れることがよくあります。
1回のアップロードで、PHPとJavaScriptをカバー
ここで、Gettext構造を理解する翻訳パイプラインの価値が発揮されます。SimplePoTranslateは、1つのソース.poまたは.potを受け取り、1回のアップロードから複数の形式(.po、.mo、.json、.php、および.xliff)でクリーンな翻訳済み出力を生成します。これにより、PHPとJavaScriptのレイヤー用に別々のツールをつなぎ合わせる必要がありません。そのSyntax Lockingは、%s、%1$s、{count}、およびインラインHTMLを所定の位置に保持します。これは、壊れたプレースホルダーがエディターパネル全体をダウンさせる可能性があるブロックエディターの文字列にとって特に重要です。この「1つのファイルから5つの形式を出力する」モデルについては、1つのファイルから5つの形式を出力するで詳しく説明しています。
WordPressが期待するハッシュファイルを生成するためには、引き続きmake-jsonを実行します。このステップはWordPress固有のものであり、ビルドに残ります。しかし、翻訳自体、つまりJS文字列を破損させる可能性が最も高い部分は、検索と置換スクリプトではなく、コンテキストを認識するエンジンによって処理されます。
結論
ブロックエディターが英語のままになる理由は、バグではなく構造的なものです。WordPress JSON翻訳は、ブラウザがサーバーサイドのGettextデータを読み取れないという理由で特別に構築された、.moファイルとは別の配信システムです。JavaScriptの文字列がwp i18n make-jsonによって生成され、wp_set_script_translations()によって接続されたスクリプトごとのMD5ハッシュJSONを必要とすることを理解すれば、修正は機械的なものです。文字列を1つの.poに保持し、PHP用に.moをコンパイルし、JS用にmake-jsonを実行します。
翻訳ステップを正しく行えば、両方の出力がそれに従います。間違えれば、午後の間空白のエディターパネルのデバッグに時間を費やすことになります。
1つのクリーンなソースからWordPressのJSONおよびPHP文字列を翻訳する準備はできましたか?SimplePoTranslateを無料で試す — クレジットカードは不要です。無料ティアでは、プレースホルダー保護のSyntax Lockingを備えた実際の
.poおよび.potファイルを翻訳するため、ブロックエディターの文字列は正しく出荷されます。