-1

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

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

4

1 回答 1

0

理论与指导:

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

  2. 接下来是检测请求|需要|选择哪种语言frontend| backend| api. 这可以通过多种方式完成:标头、cookie、会话、获取、发布甚至通过主机名。

  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为请求设置标头。

const headers = {
    'Accept': '*/*',
    'Content-Type': 'multipart/form-data;',
    'X-Requested-With': 'XMLHttpRequest',
    'Access-Control-Allow-Credentials': 'true',
    'Access-Control-Allow-Origin': '*',
    'language': 'en'
}
于 2021-03-10T10:59:16.913 回答