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

问题描述

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

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

解决方法

理论和指南:

  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'
}