天天看點

Yii2 framework學習筆記(三) -- 語言與國際化

國際化功能一般很少用到,但作為學習,還是有必要接觸一下。

國際化最常用到的方法是\Yii::t,官方文檔如下

t() 

public static method

Translates a message to the specified language.

This is a shortcut method of yii\i18n\I18N::translate().

The translation will be conducted according to the message category and the target language will be used.

You can add parameters to a translation message that will be substituted with the corresponding value after translation. The format for this is to use curly brackets around the parameter name as you can see in the following example:

$username = 'Alexander';
echo \Yii::t('app', 'Hello, {username}!', ['username' => $username]);
           

Further formatting of message parameters is supported using the PHP intl extensions message formatter. See yii\i18n\I18N::translate() for more details.

public static string t ( $category, $message, $params = [], $language = null )
$category string The message category.
$message string The message to be translated.
$params array The parameters that will be used to replace the corresponding placeholders in the message.
$language string The language code (e.g. 

en-US

en

). If this is null, the current application language will be used.
return string The translated message.

參數有4個,但常用到的是前兩個。

第一個是組别,組别的定義放在config/main-local.php下。

Yii2預設用的是英語(en-US),現在添加中文支援(zh-CN)

在component下添加如下塊

'components' => [
        ...
    	'i18n' => [
    		'translations' => [
    			'common' => [
    				'class' => 'yii\i18n\PhpMessageSource',
    				'basePath' => '@common/messages',
    				'fileMap' => [
    					'common' => 'common.php',
    				],
    			],
    		],	
    	],
        ...
    ],           

這段代碼定義了一個名為common的組别,解析翻譯檔案用的是預設的類yii\i18n\PhpMessageSource,翻譯檔案放置在common/messages下,翻譯檔案是common.php。

根據配置,建立如下的目錄結構

Yii2 framework學習筆記(三) -- 語言與國際化

翻譯檔案以數組的方式組織的,内容如下

<?php
return [
	'Signup' => '注冊',
	'Login' => '登陸',
	'Logout' => '登出',
	'Home' => '首頁',
	'Contact' => '回報',
	'About' => '關于',
];           

然後我們在layouts檔案裡做翻譯,在/views/layouts/main.php裡修改如下:

$menuItems = [
        //['label' => 'Home', 'url' => ['/site/index']],
        //['label' => 'About', 'url' => ['/site/about']],
        //['label' => 'Contact', 'url' => ['/site/contact']],
        ['label' => \Yii::t('common', 'Home'), 'url' => ['/site/index']],
        ['label' => \Yii::t('common', 'About'), 'url' => ['/site/about']],
        ['label' => \Yii::t('common', 'Contact'), 'url' => ['/site/contact']],
    ];           

打開頁面,看看是否生效。

遺憾的是,并不能生效。。。。。

Yii2 framework學習筆記(三) -- 語言與國際化

究其原因,是因為網站的根語言還是en-US,需要配置為zh-CN。

在common/config/main-local.php裡,添加如下配置:

<?php
return [
   'language' => 'zh-CN',
   ...
];           

再檢查一下是否生效。

Yii2 framework學習筆記(三) -- 語言與國際化

可以看到翻譯已經生效。

但用Yii::t方法的主要原因是要實作多語言,如果隻是顯示一種語言,還不如做hardcode(yii2架構實際做的也是hardcode的語言顯示)

yii2沒有提供現成的切換語言的控件,需要我們自己開發一個。

實作參考http://www.yiiframework.com/wiki/294/seo-conform-multilingual-urls-language-selector-widget-i18n/,并做了适度的簡化,不做seo方面的考慮。

實作的主要思路是把使用者選擇的語言儲存到cookie中,每次使用者通路頁面前,将語言設定為cookie中的值。為什麼需要每次設定語言,原因如下

Note: If we don't set Yii::app()->language explicitly for each request, it will be equal to its default value set in the confg file. If it is not set in the config file, it will be equal to the value Yii::app()->sourceLanguage, which defaults to 'en_us'. 

大概意思就是如果不每次進行設值的話,系統将自己采用預設語言,一般是英語。

1.準備素材,國旗兩面,放到frontend/web/image/下,命名為en.png和zh.png。

Yii2 framework學習筆記(三) -- 語言與國際化

2.在/common/config/main-local.php裡配置可用的語言,供我們在控件中調用

<?php
return [
    'language' => 'zh-CN',

    'components' => [
        ...
    ],
	'params' => [
		'availableLanguages' => [
			'zh-CN' => ['img' => 'image/zh.png', 'desc' => '中文'],
			'en-US' => ['img' => 'image/en.png', 'desc' => 'English'],
		],
	],
    ...
];           

3.在/common/widgets/下建立一個php檔案,命名為LanguageSelector.php,内容如下:

<?php

namespace common\widgets;

use Yii;
use yii\helpers\Html;
use yii\helpers\Url;

class LanguageSelector
{
	public static function getMenu()
	{
		$lang = Yii::$app->language;
		$avLang = Yii::$app->params['availableLanguages'];
		$isMatch = false;
		foreach ($avLang as $key => $value) {
			if($key == $lang) {
				$tag = LanguageSelector::buildImgTag($value['img'], $value['desc']);
				$isMatch = true;
			}
		}
		if(!$isMatch) {
			$tag = LanguageSelector::buildImgTag($avLang[0]['img'], $avLang[0]['desc']);
		}
		$return = [
			'label' => $tag, 
			'items' => LanguageSelector::buildMenuItems($avLang),
		];
		
		return $return;
	}	
	
	private static function buildImgTag($src, $desc)
	{
		return '<img src="' . $src . '" alt="' . $desc . '">';
	}
	
	private static function buildMenuItems($langs)
	{
		foreach ($langs as $key => $value) {
			$link = Html::a(LanguageSelector::buildImgTag($value['img'], $value['desc']) . ' ' . $value['desc'], Url::home(), [
					'title' => LanguageSelector::buildImgTag($value['img'], $value['desc']) . ' ' . $value['desc'],
					'onclick'=>"
					     $.ajax({
					    type     :'POST',
					    cache    : false,
					    url  : '" . Url::toRoute("ajax/lang") . "',
						data: { _lang : '" . $key . "' },
					    success  : function(response) {
					        window.location.reload();
					    }
					    });return false;",
			]);
			$menuItems[] = '<li>' . $link . '</li>';
		}
		return $menuItems;
	}
}           

主要做的事情為:

  • 讀取main-local.php中的配置項,形成數組。
  • 渲染菜單。
  • 為菜單中的按鈕綁定事件,當點選時觸發ajax請求,ajax順利傳回後重新整理頁面。

4.添加處理ajax的controller。在frontend/controllers下建立AjaxController.php,添加如下代碼:

<?php

namespace frontend\controllers;

use Yii;
use yii\web\Controller;
use common\components\SelectLanguageBehavior;
use yii\web\cookie;

class AjaxController extends Controller {
	public $layout = false;
	
	public function actionLang() {
		if (isset($_POST['_lang']))
		{
			$lang = SelectLanguageBehavior::getSelectedLanguage($_POST['_lang']);
			Yii::$app->language = $lang;
			$cookie = new cookie([
					'name' => '_lang',
					'value' => $lang,
			] );
			$cookie->expire = time() + (60*60*24*365); // (1 year)
			Yii::$app->response->cookies->add($cookie);
		}
		return "success";
	}
	
}           

其中重要的是把$layouts設為false,防止ajax傳回渲染多餘的東西。

5.增加一個動作(Behaviors),用來每次使用者通路頁面時修改語言。

在common/components下(如果沒有該目錄則建立目錄),建立SelectLanguageBehavior.php,内容如下

<?php
namespace common\components;

use yii\base\Application;
use yii\base\Behavior;
use yii\web\cookie;
use Yii;
class SelectLanguageBehavior extends Behavior
{
	public function events()
	{
		return [
				Application::EVENT_BEFORE_REQUEST => 'beforeRequest',
		];
	}
	
	public function beforeRequest($event) {
		$app = Yii::$app;
	
		$lang = SelectLanguageBehavior::getSelectedLanguage(Yii::$app->request->cookies->getValue('_lang'));
		$app->language = $lang;
	}
	
	public static function getSelectedLanguage($val) {
		$langs = Yii::$app->params['availableLanguages'];
		foreach ($langs as $key=>$value) {
			if($val == $key) {
				return $val;
			}
		}
		return key($langs);
	}
}           

6.将該動作綁定到系統中。

在common/config/main-local.php中添加as beginRequest項

<?php
return [
	'language' => 'zh-CN',

    'components' => [
        ...
    ],
    ...
	'as beginRequest' => [
			'class' => 'common\components\SelectLanguageBehavior',
	],
];           

7.将該控件添加到頁面上。

在frontend/views/layouts/main.php裡,添加代碼顯示我們的控件,因為控件中帶html代碼,還要防止它做轉義處理

...
    if (Yii::$app->user->isGuest) {
        $menuItems[] = ['label' => Yii::t('common', 'Signup'), 'url' => ['/site/signup']];
        $menuItems[] = ['label' => Yii::t('common', 'Login'), 'url' => ['/site/login']];
    } else {
        $menuItems[] = [
            'label' => Yii::t('common', 'Logout') . ' (' . Yii::$app->user->identity->username . ')',
            'url' => ['/site/logout'],
            'linkOptions' => ['data-method' => 'post']
        ];
    }
	
	// add this line
        $menuItems[] = \common\widgets\LanguageSelector::getMenu();
	
	echo Nav::widget([
        'options' => [
        	'class' => 'navbar-nav navbar-right',
        	],
        'items' => $menuItems,
        // add this line
    	'encodeLabels' => false,
    ]);
	...           

8.打開頁面檢視效果

Yii2 framework學習筆記(三) -- 語言與國際化

繼續閱讀