Multilingual

Multilingual uses the symfony/translation component.

Installation

composer require symfony/translation

Establishing Language Packs

Webman defaults to placing language packs in the resource/translations directory (please create it if it does not exist). To change the directory, please set it in config/translation.php.
Each language corresponds to a subfolder within it, and language definitions are defaulted to be placed in messages.php. An example is as follows:

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

All language files return an array, for example:

// resource/translations/en/messages.php

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

Configuration

config/translation.php

return [
    // Default language
    'locale' => 'zh_CN',
    // Fallback language, which attempts to use translations from this language when the current language cannot find a translation
    'fallback_locale' => ['zh_CN', 'en'],
    // Folder where language files are stored
    'path' => base_path() . '/resource/translations',
];

Translation

Translations use the trans() method.

Create the language file resource/translations/zh_CN/messages.php as follows:

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

Create the file app/controller/UserController.php

<?php
namespace app\controller;

use support\Request;

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

Visiting http://127.0.0.1:8787/user/get will return "你好 世界!"

Changing Default Language

Switch languages using the locale() method.

Create a new language file resource/translations/en/messages.php as follows:

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

use support\Request;

class UserController
{
    public function get(Request $request)
    {
        // Switch language
        locale('en');
        $hello = trans('hello'); // hello world!
        return response($hello);
    }
}

Visiting http://127.0.0.1:8787/user/get will return "hello world!"

You can also use the fourth parameter of the trans() function to temporarily switch languages, for example, this case and the one above are equivalent:

<?php
namespace app\controller;

use support\Request;

class UserController
{
    public function get(Request $request)
    {
        // Fourth parameter switches language
        $hello = trans('hello', [], null, 'en'); // hello world!
        return response($hello);
    }
}

Setting Language for Each Request Explicitly

Translation is a singleton, which means all requests share this instance. If a request uses locale() to set the default language, it will affect all subsequent requests in this process. Therefore, we should explicitly set the language for each request. For example, using the following middleware.

Create the file app/middleware/Lang.php (please create the directory if it doesn't exist) as follows:

<?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);
    }
}

In config/middleware.php, add the global middleware as follows:

return [
    // Global middleware
    '' => [
        // ... Other middleware omitted here
        app\middleware\Lang::class,
    ]
];

Using Placeholders

Sometimes, a message contains variables that need to be translated, for example:

trans('hello ' . $name);

In such cases, we handle it using placeholders.

Change resource/translations/zh_CN/messages.php as follows:

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

When translating, pass the values corresponding to the placeholders through the second parameter:

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

Handling Plurals

Some languages present different sentence structures based on the quantity of items, for example, There is %count% apple. The sentence is correct when %count% is 1, and incorrect when greater than 1.

In such cases, we use a pipe (|) to list out plural forms.

Add apple_count to the language file resource/translations/en/messages.php as follows:

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

We can even specify numeric ranges and create more complex plural rules:

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

Specifying Language Files

The default name for language files is messages.php, but you can actually create language files with other names.

Create the language file resource/translations/zh_CN/admin.php as follows:

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

Use the third parameter of trans() to specify the language file (omit the .php suffix):

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

More Information

Refer to the symfony/translation documentation