WordPressのテーマを国際化(i18n)しておくと、日本語以外の環境でも、翻訳ファイルを差し替えるだけで表示を切り替えられます。基本は、コード中の文字列をgettext関数で囲み、テキストドメインを読み込み、.po/.moファイルを用意する流れです。ここでは、その手順と、つまずきやすい点をまとめます。
gettext関数で文字列を翻訳対応にする
テーマに直接書いた文字列は、そのままでは翻訳できません。gettext関数で囲んで「翻訳可能な文字列」にします。このとき原文は英語で書くのが慣例です。日本語の原文に対してja.poを作っても翻訳の意味がなく、他の言語にも展開しにくくなるためです。日本語表示は、英語の原文をja.poで日本語に訳して実現します。
<?php
// 翻訳して出力する(HTMLエスケープ付き)
esc_html_e('Read more', 'mytheme');
// 翻訳した文字列を返す(属性値ならesc_attr__)
$label = esc_html__('Show comments', 'mytheme');
// 文脈を加える(同じ英単語でも意味が違う場合)
echo esc_html_x('Post', 'noun', 'mytheme');
// プレースホルダーを使う場合は translators コメントを付ける
/* translators: %s: ユーザー名 */
printf(esc_html__('Welcome, %s', 'mytheme'), esc_html($username));
// 単数・複数
printf(
esc_html(_n('%d comment', '%d comments', $count, 'mytheme')),
$count
);
出力は、_e()や__()のままではなく、esc_html_e()、esc_html__()、esc_attr__()などのエスケープ付きを使います。翻訳ファイルの内容がそのままHTMLとして出力されるのを防ぐためです。
主な関数の使い分けは次のとおりです。
__():翻訳した文字列を返す_e():翻訳した文字列をそのまま出力する(エスケープなし)esc_html__()/esc_html_e():HTMLエスケープして返す/出力するesc_attr__():属性値用にエスケープして返す_x():文脈(context)を加えて、同じ英単語の別の意味を区別する_n():単数形・複数形を切り替える
プレースホルダー(%sなど)を使う場合は、直前に/* translators: … */のコメントを書いておくと、翻訳者が何が入るかを把握できます。プレースホルダーが複数あるときは%1$s、%2$sのように番号を付けます。
テキストドメインを決めて読み込む
すべてのgettext関数には、テキストドメインを渡します。ドメインは、テーマのstyle.cssのヘッダーにあるText Domainと同じ文字列にします。通常はテーマのフォルダ名と同じにします。
/* Theme Name: My Theme Text Domain: mytheme Domain Path: /languages */
翻訳ファイルを自分のテーマに置く場合は、after_setup_themeで読み込みます。
<?php
add_action('after_setup_theme', function () {
load_theme_textdomain('mytheme', get_template_directory() . '/languages');
});
WordPress 6.7以降は、翻訳の読み込みが早すぎる(after_setup_themeより前)と警告が出ます。after_setup_themeか、それ以降のフックで読み込んでください。
子テーマの場合
load_theme_textdomain()の第2引数にget_template_directory()を使うと、親テーマのフォルダを指します。子テーマ側に翻訳ファイルを置くときは、load_child_theme_textdomain()とget_stylesheet_directory()を使います。子テーマの基本は子テーマでfunctions.phpを正しく拡張する方法、コードの分け方はfunctions.phpを分割して管理する方法で解説しています。
<?php
// 子テーマ側のlanguagesフォルダを読み込む場合
add_action('after_setup_theme', function () {
load_child_theme_textdomain('mytheme-child', get_stylesheet_directory() . '/languages');
});
.potと.po/.moファイルを作る
翻訳ファイルは、役割の違う三つの形式があります。
- .pot:コードから抽出した原文の一覧(翻訳の雛形)
- .po:人が編集する翻訳ファイル(テキスト形式)
- .mo:.poをコンパイルしたバイナリ。WordPressが実際に読み込む
作り方は、GUIのPoeditを使う方法と、WP-CLIを使う方法があります。Poeditでは、新規カタログを作成して、ソースコードをスキャンし、翻訳を入力して保存します。保存すると、.poと.moが同時に出力されます。WP-CLIでは次のように作成します。
# .pot(翻訳の雛形)を作る wp i18n make-pot . languages/mytheme.pot --exclude=node_modules # .po から .mo を作る wp i18n make-mo languages/
WordPress 6.5以降は、.moに加えて、高速な.l10n.php形式の翻訳ファイルも読み込まれます。
翻訳ファイルの名前と置き場所
テーマのlanguagesフォルダに置く場合、ファイル名はロケールだけにします。日本語ならja.poとja.moです。
mytheme/ ├─ style.css ├─ functions.php └─ languages/ ├─ mytheme.pot ├─ ja.po └─ ja.mo
この命名規則は、テーマ内に置く場合のものです。WordPress本体の言語ディレクトリ(WP_LANG_DIR)側に置く翻訳ファイルはテキストドメイン-ロケール.moの形式になります。この違いは、WordPress本体のコードでも分岐しています。サイトの言語設定が日本語なら、ja.moが自動的に適用されます。
翻訳対応のポイント
- テーマ内の表示文字列は、すべてgettext関数で囲む
- 原文は英語で書き、翻訳は.poで行う
- テキストドメインは
style.cssのText Domainと一致させる - 出力時は
esc_html__()などのエスケープ付き関数を使う - 文字列を連結せず、1つの文として渡す(語順が言語で変わるため)
- 同じ単語でも意味が違うときは
_x()、数に応じて変えるときは_n()を使う
よくある質問(FAQ)
wp i18n make-potで.potを作り、.poを翻訳後にwp i18n make-moで.moを作ります。テーマのlanguagesフォルダに置いてください。__()は翻訳した文字列を返し、_e()は出力します。ただしどちらもエスケープはしません。実際のテーマでは、esc_html__()やesc_html_e()のようなエスケープ付きの関数を使ってください。style.cssや関数の引数と一致していないこと、load_theme_textdomain()のパスが正しくないこと、.moのファイル名が違うことです。テーマ内のlanguagesフォルダに置く場合、.moはja.moのようにロケール名だけにします。mytheme-ja.moはWP_LANG_DIR側の命名なので、テーマ内に置いても読み込まれません。.poを編集した後は、.moの再生成も忘れずに行ってください。まとめ
テーマを翻訳対応にするには、英語の原文をエスケープ付きのgettext関数で囲み、テキストドメインを読み込み、.pot/.po/.moを用意します。テーマ内の翻訳ファイルはロケール名だけ(ja.mo)にすること、子テーマでは読み込み関数とパスが変わることに注意してください。

