使用 angular 和 yii2 实现多语言应用程序的最佳方法是什么

What is the best approach to implement multi language app using angular and yii2

我正在使用 yii2 restful api 作为后端,angular 作为前端。

我想问一下实现多语言功能的最佳方法,该功能可以在同一个地方(db table、文件)管理前端和后端。

理论和指南:

  1. 要在 Yii2 应用程序中实现|启用 multi-language 功能,您应该使用 i18n 组件 https://www.yiiframework.com/doc/guide/2.0/en/tutorial-i18n.

  2. 接下来是检测frontend|backend|api请求|要求|选择了哪种语言。这可以通过多种方式完成:headers、cookies、session、get、post 甚至通过主机名。

  3. 在处理请求之前,您需要通过某种优先级检测所选语言,语言配置存储在哪里并将其设置为应用程序。

代码:

app/common/config/main.php

return [
// ...
'language' => 'en', // base language
// ...
'components' => [
//...
    'i18n' => [
        'translations' => [
            '*' => [
                'class' => 'yii\i18n\PhpMessageSource',
                'basePath' => '@common/messages',
                'sourceLanguage' => 'en',
            ],
        ],
    ],    
// ...
],
// ...

// handle request and detect language    
'as beforeRequest' => [
    'class' => app\common\behaviours\LanguageHandler::class,
],

app/common/behaviours/LanguageHandler.php

namespace common\behaviours;

use common\models\User;
use Yii;
use yii\base\Behavior;
use yii\base\Event;
use yii\helpers\Url;
use yii\web\Application;
use yii\web\Cookie;

/**
 * Class LanguageHandler
 * @package common\behaviours
 */
class LanguageHandler extends Behavior
{
    const LANG_KEY = 'language';
    public $domainOnly = false;

    /**
     * @return array
     */
    public function events()
    {
        return [
            Application::EVENT_BEFORE_REQUEST => 'handleBeginRequest',
        ];
    }

    /**
     * Handle app selected language
     *
     * Priority of detecting language
     * 1) Detect from host name
     * 2) Detect from post
     * 3) Detect from headers
     * 4) Detect from cookies
     * 5) Detect from user config
     * 6) Use default app language
     *
     * @param Event $event
     */
    public function handleBeginRequest(Event $event)
    {
        $hostName = $request->getHostName();
        $request = Yii::$app->getRequest();
        $language = $request->post(self::LANG_KEY, null);
        $query = $request->getQueryParams();
        $cookies = $request->getCookies();
        $headers = $request->getHeaders();

        /**
         * Try first by domain and hostname
         */
        if ($this->domainOnly) {
            /**
             * Try first by domain and hostname
             */
            if (substr($hostName, -3) == '.ru') {
                $language = 'ru';
            } else {
                $language = 'en';
            }
        } else {
            if (substr($hostName, -3) == '.ru') {
                $language = 'ru';
            }
        }

        /**
         * Use detected language or try to get language from query params
         */
        $language = $language ?? ($query[self::LANG_KEY] ?? null);

        /**
         *  Use detected language or try to get language from request headers
         */
        $language = $language ?? (
            $headers->has(self::LANG_KEY)
                ? (
                    array_key_exists($headers->get(self::LANG_KEY), Yii::$app->params['languages'])
                        ? $headers->get(self::LANG_KEY)
                        : null
                )
                : null
            );

        /**
         *  Use detected language or try to get language from cookies headers
         */
        $language = $language ?? (
            $cookies->has(self::LANG_KEY)
                ? (
                    array_key_exists($cookies->getValue(self::LANG_KEY), Yii::$app->params['languages'])
                        ? $cookies->getValue(self::LANG_KEY)
                        : null
                )
                : null
            );

        /**
         *  Use detected language or try to get language from user profile
         */
        if (empty($language) && !Yii::$app->user->isGuest) {
            /** @var User $user */
            $user = Yii::$app->user->identity;
            if ($user instanceof User && isset($user->language) && !empty($user->language)) {
                $language = $user->language;
            }
        }

        /**
         * If no language use default
         */
        $language = $language ?? Yii::$app->language;

        // Add a cookie for next requests
        $languageCookie = new Cookie([
            'name' => self::LANG_KEY,
            'value' => $language,
            'expire' => time() + 86400 * 365,
        ]);
        Yii::$app->getResponse()->getCookies()->add($languageCookie);

        // store selected language to application 
        Yii::$app->language = $language;
    }
}

现在您可以使用它来实现您的目标,还可以建立检测语言的优先级。

Angular 开始,您可以为请求设置 language header。

const headers = {
    'Accept': '*/*',
    'Content-Type': 'multipart/form-data;',
    'X-Requested-With': 'XMLHttpRequest',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Allow-Origin': '*',
    'language': 'en'
}