Laravel多言語対応でファイル数が多くなった時に管理がカオスになった話


この記事について

あらすじ

自分が携わった開発案件で多言語(3つの言語)対応する機会がありました。
その際に命名規則やルールをちゃんと決めていなかった事により、各ファイルの内容に統一感がなくなり、管理が煩雑になってしまった。
その中で最終的に行きついたやり方をご紹介します。
※最終的にはあまり効率的なやり方には落とし込めませんでした...。

やりたい事

  • 3つの言語に対応する。
  • スプレッドシートで翻訳ファイルを管理する。
  • 翻訳ファイル・翻訳キーの命名規則をしっかり決めたい。
  • 翻訳作業はビジネスサイドの方が行い、スプレッドシートを正とする。
    • スプレッドシートイメージ(sample)

課題

  • 各ファイルの役割が不明確。
  • 各翻訳ファイル、翻訳キーの命名規則を決めるのが難しい。
    • この辺り、割とまとめている記事が少ない印象。

やってみた事

  • Try1 エンティティ単位と画面要素単位で分けてみる。
    • なるべく、共通化、再利用できる形を意識して分けてみる。
  • Try2 画面ページ単位で完全に分けてみる。

多言語対応の導入方法

1. resources/langディレクトリ配下に各言語用の翻訳ファイルを作成します。

2. resources/lang/{lamg}/auth.phpを編集してみる。

ex. resources/lang/en/auth.php (英語ファイル)

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used during authentication for various
    | messages that we need to display to the user. You are free to modify
    | these language lines according to your application's requirements.
    |
    */

    'failed' => 'These credentials do not match our records.',
    'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',

];


ex. resources/lang/ja/auth.php (日本語ファイル)

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used during authentication for various
    | messages that we need to display to the user. You are free to modify
    | these language lines according to your application's requirements.
    |
    */

    'failed' => '認証情報が記録と一致しません。',
    'throttle' => 'ログイン試行が規定回数を超えました。:seconds秒後に再開できます。',

];

3. bladeファイルに埋め込む

こんな感じで、出力したい画面に先ほどのキー名を埋め込みます。

    <p>{{ trans('auth.throttle') }}</p>

4. configファイルにロケール情報を持つ

<?php

return [
    'locale' => [
        'ja' => 1,
        'en' => 2,
    ],
    'locale_display' => [
        1 => '日本語',
        2 => '英語',
    ],
];

5. 言語切り替え判別用のミドルウェアを作成する

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Support\Facades\Auth;

class Locale
{
    public function handle($request, Closure $next)
    {
        // 言語設定
        $locale = array_get(Auth::user(), 'locale');
        if ($locale) {
            $variablesLocale = config("variables.locale");
            $localeAl = array_search($locale, $variablesLocale);
           \App::setLocale($localeAl);
        } else {
            $httpAcceptLanguages = explode(',', array_get($_SERVER, 'HTTP_ACCEPT_LANGUAGE'));
            $httpAcceptLanguage = array_shift($httpAcceptLanguages);
            switch ($httpAcceptLanguage ) {
                case 'ja':
                    \App::setLocale('ja');
                    break;
                default:
                    \App::setLocale('en');
                    break;
            }
        }
        return $next($request);
    }
}

ざっとはこんな感じです。

Try1 エンティティ単位と画面要素単位で分けてみる。

では、上記の導入を終えた後になんとなくでエンティティ単位と画面要素単位でファイルを分けて
管理していました。けれど、ここで問題が起きてきました。分割ルールとしては、下記です。

分割ルール

  • エンティティ単位:DBのエンティティ単位ごとに分割する。該当するファイルにはエンティティのプロパティを記載する。
  • 画面要素単位:メニュー、タイトル、見出し、フォーム(ボタンの名前)、メッセージなどの単位で分割する。

上記のようになるべく、部品ごとで共通化できるように分けたのですが、上記のエンティティ単位で分けようとした時に画面にはあるけど、エンティティのプロパティにないという項目が出てきて、結局、それっぽいファイルに当て込むという事が発生しました。あと、静的ファイルの場合にそもそもエンティティと一致しない...!というのがありました。
また、スプレッドシートを正として管理していたので、シートの内容を無理に共通化させようとすると、逆にシステム側での管理が煩雑になってしまいました。その他にも後から開発に入った人にファイル分割の粒度を説明するのも難しく、よくないと感じました...。
そこで、下記の分割ルールに変更しました。

Try2 画面ページ単位で完全に分けてみる。

  • スプレッドシートのシート番号とファイル名を同じにする。
  • キーの名前はなるべく、日本語の直訳に近い英語名にする。
  • キー名もスプレッドシートでしっかり管理し、一致させる。
    ※グローバルメニューなど、明らかに共通化した方が良いものは共通の翻訳ファイルにまとめる。

まとめ

  • Try2の分け方が良さそうだった。
  • 翻訳をビジネスサイドの人がやる場合は、無理に汎用的に共通化させようとするとファイルの管理がカオスになってしまったので、多少、重複する翻訳キーが出てきても、ページなどのわかりやすい粒度でまとめるのが無難なのかと思いました。
    ※もちろん、自分も手探り状態なので、もっと効率の良い分割方法があれば、ご意見頂けると幸いです!

参考記事