Skip to main content

このページで達成すること

パッケージのメッセージを多言語で配布し、利用アプリケーションが必要な文言だけを変更できるようにします。翻訳キー・プレースホルダーを公開APIとして扱い、パッケージ更新時にカスタマイズを維持する方法まで整理します。 ローカライゼーションがアプリケーションでの基本操作を、Laravelパッケージ開発が登録と公開の基本を扱います。このページはLaravel 13の ServiceProvider、FileLoader、Translator の実装に踏み込みます。
loadTranslationsFrom() は読み込み先の登録、publishes() はファイルのコピー先の登録です。翻訳を使うために、利用者が必ず vendor:publish を実行する必要はありません。

PHP翻訳を名前空間付きで配布する

パッケージ専用のキーを持ちたい場合は、PHP配列形式と名前空間を使います。以下は Acme\Courier というパッケージの例です。
lang/ja/messages.php に日本語のデフォルト値を用意します。
lang/en/messages.php にフォールバック用の英語も用意します。
サービスプロバイダーの boot() で読み込みと任意の公開を登録します。
使用側は名前空間・ファイル名・配列キーを指定します。言語コードはLaravelの設定に合わせて ja を使います。このドキュメントサイトのURLに使う jp とは別です。
名前空間の courier は loadTranslationsFrom() の第2引数です。Composerのパッケージ名から自動で決まるわけではありません。

PHP翻訳はファイルを丸ごと置き換えない

利用アプリケーションでは、標準の言語ディレクトリなら lang/vendor/courier/ja/messages.php に変更するキーだけを書けます。言語ディレクトリを変更している場合も、$this->app->langPath('vendor/courier') の配下を使います。
この例では queued だけが変わり、failed はパッケージの日本語翻訳を使います。

FileLoaderの読み込み順序

ServiceProvider::loadTranslationsFrom() はTranslatorの解決後に名前空間を登録します。実際のファイル取得は翻訳が要求されたときに行われます。 FileLoader::loadNamespaced() は、登録されたパッケージの言語ファイルを読み込み、その配列を loadNamespaceOverrides() に渡します。そこでローダーの各言語パスにある vendor/{namespace}/{locale}/{group}.php を読み、array_replace_recursive() で置換します。 標準の TranslationServiceProvider はフレームワークの言語パスとアプリケーションの言語パスを、この順序でローダーに渡します。追加パスを登録する拡張がある場合も、後から読み込む上書き配列が同じキーを優先します。
名前空間が登録されていない場合、FileLoader::loadNamespaced() は空の配列を返します。lang/vendor/courier にファイルを置くだけでは、サービスプロバイダーの登録漏れを補えません。また、同じ名前空間を別パッケージが登録すると登録先が置き換わるため、衝突しない名前を選びます。

JSON翻訳はパッケージ専用の名前空間を持たない

文章をキーにするJSON翻訳は、次のようにディレクトリを登録します。これは先ほどのPHP翻訳とは別の選択肢です。
パッケージの lang/ja.json の例です。
loadJsonTranslationsFrom() には名前空間の引数がありません。登録されたJSON翻訳は、他のパッケージやアプリケーションと同じキー空間を共有します。

JSONの上書き先はアプリケーションのja.json

FileLoader::loadJsonPaths() は、登録されたJSONパスを先に、その後に通常の言語パスを読み、array_merge() します。標準構成ではアプリケーションの lang/ja.json の同じ文字列キーがパッケージの値を上書きします。
  • パッケージ間で同じ文字列キーを使うと、後から読み込むJSONの値が優先されます。プロバイダーの順序に頼る設計は避けます。
  • lang/vendor/courier/ja.json は、標準のJSONローダーの上書き先ではありません。PHP用の公開設定をそのままJSONに流用しても、この場所は自動で読まれません。
  • アプリケーションの lang/ja.json へパッケージのJSONを publishes() しても、ファイル内容はマージされません。既存翻訳を壊さないよう、必要なキーだけを利用者が追加する手順を案内します。
Translator::get() は、まず要求した言語のJSONを確認し、見つからなければPHP形式のキーとして探索します。PHP翻訳と同じようにフォールバック言語のJSONまで順番に探す処理ではありません。JSONを英語の文章キーにする場合は、翻訳がないと原文のキーが表示される標準動作と区別してください。
PHP翻訳の名前空間は他パッケージのPHPキーを分離します。ただし、Translator::get() はJSONの完全一致キーを先に調べるため、JSONに courier::messages.delivery.queued のようなキーを定義するとPHP側より優先されます。通常は文章キーとPHP形式のキーを混在させない方針にします。

公開済み翻訳を壊さずに更新する

PHP翻訳を一括公開したい利用者には、対象を絞ったコマンドを案内できます。
ただし、すべてのデフォルト値をコピーすると、そのコピーも以後は上書き値です。パッケージ側で誤字を修正しても、同じキーが公開済みファイルに残っていれば新しい値は見えません。一方、コピーにない新しいキーはパッケージ側から補われます。
少数の文言だけを変更する場合は、全ファイルを公開せず、上書きファイルに必要なキーだけを置く方が更新を取り込みやすくなります。これはPHP翻訳の部分上書きを利用する運用です。
長期保守では、次の順序で更新を設計します。
  1. キーと名前空間を維持する — キーの削除・移動は、利用者の __() 呼び出しと上書き先に影響します。新しいキーを追加し、旧キーを残す移行期間を検討します。
  2. プレースホルダーを維持する — :name を :recipient に変えると、呼び出し側の置換配列も変更が必要です。翻訳ファイルだけの修正と考えないようにします。
  3. 公開済みファイルを差分確認する — 利用者の上書きと新しいデフォルトを比較します。不要になった上書きキーを削除すると、パッケージの値に戻せます。
  4. 無条件の再公開を避ける — --force による再公開は利用者のカスタマイズを上書きします。JSONをアプリケーションのファイルへコピーする設計では、他の翻訳まで失う可能性があります。
  5. 常駐プロセスで確認する — Translator::load() は名前空間・グループ・言語ごとの配列をインスタンス内に保持します。既に読み込み済みのTranslatorが残るプロセスでは、ファイル変更だけで再読込されるとは限りません。運用に応じてワーカー等を再起動します。
公開操作の対象選択や上書きオプションはパッケージの公開アセットと更新で、バージョン更新時の互換性判断はパッケージのバージョン互換性管理で補足しています。

利用アプリケーションで確認する項目

サービスプロバイダーを登録した検証用アプリケーションで、次の組み合わせを確認します。パッケージ内のテスト環境構築はパッケージのテストを参照してください。 読み込み後に上書きファイルを作るテストでは、Translatorの既存の読み込み結果が影響しないようにします。ファイルを先に用意してから取得するか、ケースごとに新しいアプリケーションインスタンスを使って確認します。

参照した一次情報

公式ドキュメントは最新のデフォルトブランチ 13.x、内部実装は参照時点の最新リリース v13.35.0 を確認しています。
最終更新日 2026年10月8日