在Yii 2中,官方的頁面多語言解決方案有兩個:
創(chuàng)新互聯(lián)服務項目包括潢川網(wǎng)站建設、潢川網(wǎng)站制作、潢川網(wǎng)頁制作以及潢川網(wǎng)絡營銷策劃等。多年來,我們專注于互聯(lián)網(wǎng)行業(yè),利用自身積累的技術優(yōu)勢、行業(yè)經(jīng)驗、深度合作伙伴關系等,向廣大中小型企業(yè)、政府機構等提供互聯(lián)網(wǎng)行業(yè)的解決方案,潢川網(wǎng)站推廣取得了明顯的社會效益與經(jīng)濟效益。目前,我們服務的客戶以成都為中心已經(jīng)輻射到潢川省份的部分城市,未來相信會繼續(xù)擴大服務區(qū)域并繼續(xù)獲得客戶的支持與信任!
方案1,使用Yii::t()函數(shù),在頁面中需要輸出文字的地方,使用類似如下代碼:
= Yii::t(‘views/login’, ‘hello’)?>
這樣做的后果是頁面上大量充斥著類似的代碼,導致頁面可讀性很差,而且對于同一個頁面來說,Yii::t()函數(shù)的第一個參數(shù)基本上都是一樣的,看到這些重復代碼,也是心塞。我曾經(jīng)在項目中采用這種方式實現(xiàn)多語言,一個簡單的登錄頁面都能寫到心煩的要命。
方案2,為指定語言做一個專門的視圖,假設你有個頁面是英文的,想再做個中文頁面,可是中英文頁面布局等相差很大,不是簡單的翻譯文字,那么在Yii 2中,可以在該頁面的目錄下,再建立一個zh-CN目錄,然后在這個目錄下建立一個同名的視圖文件,頁面內(nèi)容用中文實現(xiàn)即可。這個我會專門再有文章說明如何實現(xiàn)。
如果中英文頁面布局基本一樣,只是文字有變化,那么建議還是不要用方案2了,寧可用方案1降低可讀性,否則一旦頁面內(nèi)容有修改,兩個頁面之間的內(nèi)容同步會搞到你懷疑人生。
總之,不管是方案1還是2,我都不喜歡,想要尋找一種簡潔明了的頁面多語言方案,頁面看起來干凈清爽,又不需要為每個語言做單獨的頁面。
那么怎樣才能做到呢,我從Mustache中找到了實現(xiàn)的方案,假設下面是一個視圖的代碼:
{{基本信息}}
{{下載隊列}}
{{等待隊列}}
{{已安裝}}
{{當前GameInfo}}
{{剩余電量}}
{{是否允許OTA}}
如果把想要多語言顯示的文字用Mustache的變量符號給括起來,然后假設上面的內(nèi)容已經(jīng)存到一個字符串$content里,那么在Action中,可以用Mustache將其輸出為英文:
$content = $this->render('mypage', $params);
$m = new Mustache_Engine();
$content = $m->render($content, [
'基本信息' => 'Base Information',
'下載隊列' => 'Downloading',
'等待隊列' => 'Waiting',
'已安裝' => 'Installed',
'當前GameInfo' => 'GameInfo',
'剩余電量' => 'Battery Level',
'是否允許OTA' => 'Is can OTA',
]);
return $content;
這里的要點是先用Yii的render函數(shù),得到要輸出頁面的字符串,然后使用Mustache,將指定的文字轉換為英文,最后通過return輸出。
上面這段代碼就是使用Mustache實現(xiàn)頁面多語言的核心思想,首先看頁面的代碼,完全沒有任何PHP的代碼,都是標準的HTML元素,頁面看起來非常的干凈清爽,前端開發(fā)人員可以直接用這個頁面做前端的各種效果,完美實現(xiàn)前后端開發(fā)的解耦。
當然,上面展示的是核心的思想,但是要實際使用,還是需要進一步的完善。
首先,翻譯的文字其實不適合放到Action的代碼里,這樣不好維護,應該按照Yii 2的設計思想,放到messages目錄下,為指定語言建立messages文件,類似如下:
return [
'device/views/deviceLog/mypage => [
'基本信息' => 'Base Information',
'下載隊列' => 'Downloading',
'等待隊列' => 'Waiting',
'已安裝' => 'Installed',
'當前GameInfo' => 'GameInfo',
'剩余電量' => 'Battery Level',
'是否允許OTA' => 'Is can OTA',
],
];
使用視圖的路徑作為鍵值,方便為每個頁面確定翻譯的內(nèi)容。
其次,做一個自己的Controller的基類,重載render函數(shù):
public function render($view, $params = [])
{
$content = parent::render($view, $params);
$path = $this->getViewPath() . '/' . $view;
$list = EonI18nUtils::getMsgs($path);
if (empty($list)) {
return $content;
}
$m = new Mustache_Engine([
'delimiters' => '## ##',
]);
$content = $m->render($content, $list);
return $content;
}
這里,先調用父類的render函數(shù),得到正常輸出的視圖字符串,再調用EonI18nUtils::getMsgs(),根據(jù)視圖文件的路徑,得到該頁面的多語言鍵值對,然后創(chuàng)建Mustache對象,將視圖字符串中的指定鍵值修改為翻譯后的文字。
為了保證頁面上基于JavaScript的Mustache可以使用,這里將Mustache的鍵值標簽由{{}}改為####,頁面代碼類似如下:
##基本信息##
##下載隊列##
{{downloading}}
##等待隊列##
{{waitting}}
##已安裝##
{{installed}}
##當前GameInfo##
{{gameinfo}}
##剩余電量##
{{battery_level}}%
##是否允許OTA##
{{allowOTA}}
這樣,上面代碼中用##括起來的文字會被翻譯,而用{{}}括起來的,則由頁面上的JS代碼使用Mustache方案替換文字。
EonI18nUtils::getMsgs()的參考代碼如下:
public static function getMsgs($category, $lang = null)
{
$category = str_replace('\\', '/', $category);
$arr = explode("/", $category);
$arr = array_slice($arr, count($arr) - 4);
$category = implode("/", $arr);
$messageSource = \Yii::$app->getI18n()->getMessageSource('messages');
$list = $messageSource->getMsgList($category, $lang);
return $list;
}
getMsgList()代碼類似如下:
public function getMsgList($langPath, $language)
{
$language = $this->getLanguage($language);
if (!isset($this->_messages[$language])) {
$this->_messages[$language] = $this->loadMessages('messages', $language);
}
if (isset($this->_messages[$language][$langPath])) {
return $this->_messages[$language][$langPath];
}
return false;
}