2026年8月5日

2026年8月5日

WordPressのローカライズ(i18n)と多言語対応の方法|翻訳関数・テキストドメイン・翻訳ファイルの作り方

WordPressの「多言語対応」には、テーマやプラグインの画面に出る文言を翻訳できるようにする 国際化(i18n)とローカライズ(l10n) と、記事や固定ページの本文を言語ごとに用意する コンテンツの多言語化 の2種類があります。この記事では前者を中心に、翻訳関数の正しい使い方、テキストドメインの設定、POT/PO/MOなど翻訳ファイルの作り方と置き場所、JavaScriptの翻訳、よくある「翻訳が反映されない」原因までを解説し、最後に本文の多言語化の選択肢を整理します。

i18n と l10n の違い

  • 国際化(i18n):コードの中の文言を翻訳関数で包み、後から翻訳できる状態にする作業。テーマやプラグインの開発者が行います。
  • ローカライズ(l10n):i18n 済みの文言を、特定の言語(ロケール)向けに翻訳する作業。日本語のロケールは ja です。

i18n をしていないコードは、どれほど翻訳者がいても翻訳できません。逆に i18n さえしておけば、翻訳ファイルを追加するだけで、管理画面の言語設定に合わせて表示が切り替わります。WordPressはサイトの言語(設定 → 一般)と、ユーザーごとのプロフィールの言語の両方を見て、表示に使うロケールを決めます。

翻訳関数の使い分け

<?php
// 値を返す / そのまま出力する
$label = __( 'Read more', 'my-plugin' );
_e( 'Settings saved.', 'my-plugin' );

// エスケープと翻訳を同時に(HTMLに出すときはこちらが基本)
echo esc_html__( 'Read more', 'my-plugin' );
esc_html_e( 'Settings saved.', 'my-plugin' );
echo '<input placeholder="' . esc_attr__( 'Search', 'my-plugin' ) . '">';

// 同じ英語でも意味が違う場合は文脈を付ける
echo esc_html_x( 'Post', 'verb: to publish', 'my-plugin' );

// 単数・複数
$count = 3;
printf(
	/* translators: %d: number of comments */
	esc_html( _n( '%d comment', '%d comments', $count, 'my-plugin' ) ),
	(int) $count
);

// 変数を含む文は、文全体を翻訳対象にしてプレースホルダーを使う
$name = wp_get_current_user()->display_name;
printf(
	/* translators: %s: user display name */
	esc_html__( 'Welcome back, %s.', 'my-plugin' ),
	esc_html( $name )
);

押さえておきたい決まりがいくつかあります。

  • 文字列とテキストドメインはリテラルで書く:__( $text, 'my-plugin' ) のように変数を渡すと、翻訳文字列を抽出するツールが拾えません。テキストドメインも定数や変数にせず、文字列で書きます。
  • 文を分割しない:「__( 'Welcome' ) . $name . __( 'back' )」のように分けると、語順の違う言語で正しく訳せません。sprintf() / printf() とプレースホルダーを使い、プレースホルダーが2つ以上あるなら %1$s・%2$s のように番号を付けます。
  • 翻訳者向けコメント:/* translators: ... */ を直前に書くと、翻訳ツールにそのまま表示され、%s に何が入るかが伝わります。
  • **複数形は _n()**:日本語には単複の区別がありませんが、言語によっては複数の形があります。if ( 1 === $count ) で分岐するのではなく _n() に任せます。
  • エスケープ付きを基本に:翻訳ファイルの中身も外部から入る文字列です。HTMLに出す場面では esc_html__() などのエスケープ付き関数を使います。

数値や日付は、number_format_i18n() や wp_date() を使うと、ロケールに合わせた桁区切りや日付表記になります。

テキストドメインを設定する

テキストドメインは「この文言はどのプラグイン(テーマ)のものか」を示す識別子です。WordPress.org で配布するプラグインやテーマでは、スラッグ(フォルダ名)と同じにする決まりです。自作のものも同じにしておくと迷いません。

プラグインの場合はメインファイルのヘッダー、テーマの場合は style.css のヘッダーに書きます。

<?php
/**
 * Plugin Name: My Plugin
 * Text Domain: my-plugin
 * Domain Path: /languages
 */

WordPress.org で配布されているプラグインやテーマは、翻訳プラットフォーム(translate.wordpress.org)で作られた翻訳が wp-content/languages/ に自動で配信され、WordPressが必要なときに読み込みます。この場合、load_plugin_textdomain() を呼ばなくても翻訳が使えます。

自作のテーマやプラグインで、翻訳ファイルを自分のフォルダに同梱する場合は、読み込み処理を書きます。

<?php
// プラグイン
add_action( 'init', function () {
	load_plugin_textdomain( 'my-plugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
} );

// テーマ(functions.php)
add_action( 'after_setup_theme', function () {
	load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );
} );

注意したいのは、翻訳関数を呼ぶタイミングです。WordPress 6.7 からは、init より前に翻訳関数が呼ばれると「_load_textdomain_just_in_time が誤って呼ばれた」という趣旨の通知が出るようになりました。プラグインのファイル直下やクラスのコンストラクターで __() を実行していると、この通知の原因になります。文言の取得は init 以降に実行される処理の中で行ってください。

翻訳ファイルの種類と作り方

翻訳ファイルは次の流れで作ります。

  1. POT(テンプレート):コードから翻訳対象の文字列を抜き出したもの
  2. PO:POT をもとに、言語ごとの訳を書き込んだテキストファイル
  3. MO / .l10n.php:PO をWordPressが読む形式に変換したもの。WordPress 6.5 から、読み込みが速い PHP 形式(.l10n.php)も使えるようになりました

WP-CLI の wp i18n コマンドを使うと、POT の作成から変換までをコマンドで行えます。

# プラグインのフォルダで実行:POT を作る
wp i18n make-pot . languages/my-plugin.pot

# PO を訳した後、MO を作る
wp i18n make-mo languages

# PHP 形式の翻訳ファイルを作る(WP-CLI のバージョンによっては未対応)
wp i18n make-php languages

# JavaScript 用の JSON を作る
wp i18n make-json languages --no-purge

PO の翻訳作業には、Poedit のような翻訳エディターや、管理画面から翻訳できる Loco Translate プラグインが使われます。Loco Translate で作った翻訳は保存先を選べるので、プラグインの更新で消えない場所(wp-content/languages/ 配下など)を選びます。

ファイル名と置き場所には決まりがあります。

  • wp-content/languages/plugins/my-plugin-ja.mo:プラグインの翻訳(テキストドメイン-ロケール)
  • wp-content/languages/themes/my-theme-ja.mo:テーマの翻訳
  • プラグインのフォルダ内:languages/my-plugin-ja.mo(テキストドメイン-ロケール)
  • テーマのフォルダ内:languages/ja.mo(ロケールのみ)

テーマとプラグインで同梱時のファイル名の付け方が違う点は、間違えやすいところです。wp-content/languages/ 配下と自分のフォルダの両方に同じテキストドメインの翻訳を置くと、どちらが使われるかの扱いは WordPress のバージョンによって変わってきた経緯があります。どちらか一方に置くようにすると、反映されない原因を追いやすくなります。

JavaScript の文言を翻訳する

ブロックエディター用のスクリプトなど、JS の文言は @wordpress/i18n パッケージの関数で包みます。

import { __, sprintf } from '@wordpress/i18n';

const message = sprintf(
	/* translators: %s: file name */
	__( 'Uploaded %s', 'my-plugin' ),
	fileName
);

PHP 側では、スクリプトの依存関係に wp-i18n を含めて登録し、wp_set_script_translations() で翻訳の読み込みを指示します。

<?php
add_action( 'enqueue_block_editor_assets', function () {
	wp_enqueue_script(
		'my-plugin-editor',
		plugins_url( 'build/editor.js', __FILE__ ),
		array( 'wp-i18n', 'wp-blocks', 'wp-element' ),
		'1.0.0',
		true
	);
	wp_set_script_translations( 'my-plugin-editor', 'my-plugin', plugin_dir_path( __FILE__ ) . 'languages' );
} );

JS 用の翻訳は JSON ファイルで、ファイル名には「テキストドメイン-ロケール-スクリプトのパスのMD5ハッシュ」が使われます。wp i18n make-json で PO から生成すると、名前は自動で付きます。ビルドの出力先を変えるとハッシュが変わり、翻訳が読み込まれなくなるので、JS の場所を変えたら JSON を作り直します。

翻訳が反映されないときの確認順

可能性が高い順に挙げます。

  1. 表示に使われている言語:サイトの言語だけでなく、ログイン中のユーザーのプロフィールの言語が英語になっていないか確認します。
  2. テキストドメインの不一致:コード内の第2引数、ヘッダーの Text Domain、翻訳ファイル名の三者が同じか確認します。1文字の違いでも読み込まれません。
  3. ファイル名と場所:上の命名規則どおりか、テーマ同梱なのに my-theme-ja.mo にしていないかを確認します。
  4. PO を変えたのに MO / .l10n.php を作り直していない:WordPressは PO を直接読みません。両方の形式がある場合は PHP 形式が優先されるため、古い .l10n.php が残っていると変更が反映されません。
  5. 翻訳関数の呼び出しが早すぎる:上で触れた 6.7 以降の通知が debug.log に出ていないかを、ステージング環境で WP_DEBUG_LOG を有効にして確認します。
  6. キャッシュ:オブジェクトキャッシュやページキャッシュが古い表示を返していないかを確認します。

記事本文を多言語化する選択肢

ここまでの方法は「テーマやプラグインの文言」の翻訳で、記事や固定ページの本文は対象外です。本文を言語ごとに用意するには、別の仕組みが必要です。代表的な方法は次のとおりです(2026年10月現在)。機能の範囲や無料版・有料版の区分は変わることがあるため、導入前に各公式サイトで確認してください。

  • WPML:有料のプラグイン。翻訳管理やWooCommerceとの連携など機能が幅広い
  • Polylang:無料版があるプラグイン。投稿ごとに言語を割り当て、翻訳同士をひも付ける
  • TranslatePress:フロントエンドの画面上で訳文を入力する方式のプラグイン
  • マルチサイト+MultilingualPress など:言語ごとに別サイトを持ち、相互にひも付ける

どの方法でも、URLの設計(サブディレクトリ・サブドメインなど)と、検索エンジンに言語ごとの対応ページを伝える hreflang の設定が関わります。導入後に方式を変えるのは手間が大きいので、本番サイトのバックアップを取り、ステージング環境で URL と表示を確認してから決めるのがおすすめです。

まとめ

  • 多言語対応には、コードの文言を訳せるようにする i18n/l10n と、本文を言語ごとに用意する多言語化の2種類がある
  • 文言は __()・esc_html__()・_x()・_n() で包み、文字列とテキストドメインはリテラルで書く。文は分割せずプレースホルダーと翻訳者向けコメントを使う
  • テキストドメインはスラッグと同じにし、ヘッダーと翻訳ファイル名をそろえる。翻訳関数は init 以降に呼ぶ
  • POT → PO → MO / .l10n.php の流れで作り、WP-CLI の wp i18n で抽出と変換ができる
  • JS は @wordpress/i18n と wp_set_script_translations()、JSON 翻訳ファイルで対応する
  • 本文の多言語化は WPML・Polylang・TranslatePress などから、URL設計と hreflang まで含めて選ぶ

お気軽にご相談ください

お見積りへ お問い合わせへ
▲