多言語

多言語は symfony/translation コンポーネントを使用しています。

インストール

composer require symfony/translation

言語パッケージの作成

webmanはデフォルトで言語パッケージをresource/translationsディレクトリに置きます(存在しない場合は自分で作成してください)。ディレクトリを変更する場合は、config/translation.phpで設定してください。
各言語はその中の1つのサブフォルダーに対応しており、言語定義はデフォルトでmessages.phpに記入されます。以下はその例です:

resource/
└── translations
    ├── en
    │   └── messages.php
    └── zh_CN
        └── messages.php

すべての言語ファイルは配列を返します、例えば:

// resource/translations/en/messages.php

return [
    'hello' => 'Hello webman',
];

設定

config/translation.php

return [
    // デフォルト言語
    'locale' => 'zh_CN',
    // フォールバック言語、現在の言語で翻訳が見つからない場合はフォールバック言語の翻訳を試みる
    'fallback_locale' => ['zh_CN', 'en'],
    // 言語ファイルの保存先フォルダ
    'path' => base_path() . '/resource/translations',
];

翻訳

翻訳はtrans()メソッドを使用します。

言語ファイルresource/translations/zh_CN/messages.phpを以下のように作成してください:

return [
    'hello' => '你好 世界!',
];

ファイルapp/controller/UserController.phpを作成します:

<?php
namespace app\controller;

use support\Request;

class UserController
{
    public function get(Request $request)
    {
        $hello = trans('hello'); // 你好 世界!
        return response($hello);
    }
}

http://127.0.0.1:8787/user/getにアクセスすると "你好 世界!" が返されます。

デフォルト言語の変更

言語を切り替えるにはlocale()メソッドを使用します。

新たに言語ファイルresource/translations/en/messages.phpを以下のように作成します:

return [
    'hello' => 'hello world!',
];
<?php
namespace app\controller;

use support\Request;

class UserController
{
    public function get(Request $request)
    {
        // 言語を切り替え
        locale('en');
        $hello = trans('hello'); // hello world!
        return response($hello);
    }
}

http://127.0.0.1:8787/user/getにアクセスすると "hello world!" が返されます。

また、trans()関数の第4引数を使用することで一時的に言語を切り替えることもできます。例えば、上記の例と次の例は等価です:

<?php
namespace app\controller;

use support\Request;

class UserController
{
    public function get(Request $request)
    {
        // 第4引数で言語を切り替え
        $hello = trans('hello', [], null, 'en'); // hello world!
        return response($hello);
    }
}

各リクエストごとに言語を明示的に設定

translationはシングルトンであり、すべてのリクエストがこのインスタンスを共有します。もしあるリクエストでlocale()を使ってデフォルト言語を設定した場合、それはこのプロセスの後続のすべてのリクエストに影響を及ぼします。したがって、各リクエストごとに言語を明示的に設定する必要があります。例えば以下のミドルウェアを使用することができます。

ファイルapp/middleware/Lang.phpを作成します(ディレクトリが存在しない場合は自分で作成してください):

<?php
namespace app\middleware;

use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;

class Lang implements MiddlewareInterface
{
    public function process(Request $request, callable $handler) : Response
    {
        locale(session('lang', 'zh_CN'));
        return $handler($request);
    }
}

config/middleware.phpにグローバルミドルウェアを追加します:

return [
    // グローバルミドルウェア
    '' => [
        // ... ここでは他のミドルウェアを省略
        app\middleware\Lang::class,
    ]
];

プレースホルダの使用

時には、メッセージに翻訳する必要のある変数が含まれることがあります。例えば:

trans('hello ' . $name);

このような場合、プレースホルダを使用して処理します。

resource/translations/zh_CN/messages.phpを以下のように変更します:

return [
    'hello' => '你好 %name%!',
];

翻訳する時は、第二引数を使ってプレースホルダに対応する値を渡します:

trans('hello', ['%name%' => 'webman']); // 你好 webman!

複数形の処理

一部の言語では、物の数によって異なる文形式が必要です。たとえば、There is %count% appleという文では、%count%が1のときは正しく、1より大きいときは間違っています。

このような場合はパイプ(|)を使用して複数形の形式を列挙します。

言語ファイルresource/translations/en/messages.phpapple_countを追加します:

return [
    // ...
    'apple_count' => 'There is one apple|There are %count% apples',
];
trans('apple_count', ['%count%' => 10]); // There are 10 apples

特定の数字範囲を指定して、より複雑な複数形ルールを作成することもできます:

return [
    // ...
    'apple_count' => '{0} There are no apples|{1} There is one apple|]1,19] There are %count% apples|[20,Inf[ There are many apples'
];
trans('apple_count', ['%count%' => 20]); // There are many apples

言語ファイルの指定

言語ファイルのデフォルト名はmessages.phpですが、実際には他の名前の言語ファイルを作成することもできます。

言語ファイルresource/translations/zh_CN/admin.phpを以下のように作成します:

return [
    'hello_admin' => '你好 管理员!',
];

trans()の第三引数を使用して言語ファイルを指定できます(.php拡張子は省略します)。

trans('hello', [], 'admin', 'zh_CN'); // 你好 管理员!

さらなる情報

symfony/translationマニュアルを参照してください。