
壹 ❀ 引
最近項目要求支持國際化多語言,由於項目用的還是angularjs,那么首當其沖的選擇了angularjs封裝的I18N插件angular-translate
,本文主要會從三個方向展開討論,一是基本用法,怎么用,代碼是什么意思;二是問題解答,比如$translate.instant()
為什么沒效,怎么在JS程序中使用多語言等;第三便是提供我的解決方案,供大家參考,那么本文開始。
貳 ❀ 基本用法
由於是三方插件,自然要下載才能使用,請大家在項目目錄下執行npm i angular-translate
命令,下載多語言相關依賴包,OK下載完成后在node_modules
文件夾中可以看到如下內容:

文件雖多,我們需要用到的其實只有angular-translate.min.js
與angular-translate-loader-static-files
目錄下的angular-translate-loader-static-files.min.js
。
所以第一步,在HTML文件中引入相關資源,如下:
<script src="node_modules/angular/angular.min.js"></script>
<script src="node_modules/angular-translate/dist/angular-translate.js"></script>
<script
src="node_modules/angular-translate/dist/angular-translate-loader-static-files/angular-translate-loader-static-files.min.js"></script>
在項目目錄下新建一個language文件夾,用於存放我們的語言列表,這里我們就建兩個,一個中文一個英文,如下:

我們在en.json
中添加如下代碼
{
"name": "echo",
"age": "twenty-seven"
}
我們在zh.json
中添加如下代碼:
{
"name": "聽風",
"age": "27"
}
好的,現在我們創建HTML頁面主體部分,以及對應的controller,如下:
<body ng-controller="myCtrl as vm">
<p>{{"name"|translate}}</p>
<p translate="age"></p>
<select name="" id="" ng-model="vm.language" ng-change="vm.change()">
<option value="en">英文</option>
<option value="zh">中文</option>
</select>
</body>
angular.module('myApp', ['pascalprecht.translate'])
.controller('myCtrl', ['$translate', function ($translate) {
var vm = this;
vm.language = "zh";
vm.change = function () {
$translate.use(vm.language);
};
}])
.config(function ($translateProvider) {
// 讀取本地JSON文件,prefix代表文件路徑前綴,suffix代表文件后續
$translateProvider.useStaticFilesLoader({
prefix: './language/',
suffix: '.json'
});
// 設置默認的語言
$translateProvider.preferredLanguage('zh');
});
angullarjs其它部分大家執行搭建,做到這一步,利用live-server啟動本地服務器(其它本地服務器也行)打開頁面,嘗試切換select選項,可以發現我們已經實現了一個簡單的多語言了。

那么現在我們來解釋下上述代碼是什么意思,做了什么。
首先在HTML中我用了兩種方式來顯示多語言,一種是表達式,一種是指令形式,兩種皆可,官方推薦使用指令會更好,不過有特殊情況只能用表達式,這點后面我們再說。而在代碼中的name
與age
其實就是對應了JSON文件中數據的key,這點不難理解。
對於JS代碼,第一步就是得在module中加入pascalprecht.translate
模板,這樣我們才能通過config對多語言進行初步配置,比如$translateProvider.preferredLanguage('zh')
這一句用來設置多語言的默認語言,例子中默認的就是中文。
而$translateProvider.useStaticFilesLoader
這一句其實對應了我們在HTML中引用的angular-translate-loader-static-files
文件,它的作用就是用來導入項目中的其它靜態文件,畢竟引用了JSON,后程序才有可供查找的語言列表;另外屬性prefix
用來描述文件路徑,suffix
用來描述你需要引用文件的后綴。
細心的同學一定想問,那程序怎么知道要去哪個JSON文件中去查呢,在上述代碼config與controller分別有這兩段,作用都是告訴translate應該用哪個語言表查詢:
$translate.use(vm.language);
$translateProvider.preferredLanguage('zh');
再看select中option賦予的值,不是正好與我們的JSON文件名相同嗎。那么關於translate基礎介紹說到了,下面來聊聊使用中會遇到哪些問題。
叄 ❀ 進階用法與部分問題解答
叄 ❀ 壹 translate key/value包含變量
我們在上文的例子中,translate查找所用的key是一個確切的值,其實說到底,所謂translate國際化,就是在不同的語言表中定義相同的key名,再根據用戶操作切換不同的表作為查找根據而已。
那么問題來了,假設我們在使用時寫在HTML上的key是個變量怎么辦呢?不留懸念,直接看下面的例子:
我們在controller中添加如下代碼:
vm.myName = 'name';
然后在HTML中添加如下兩行:
<p>{{vm.myName|translate}}</p>
<p translate="{{vm.myName}}"></p>
刷新頁面,可以看到生效了,這里我們就是將key賦予了一個變量,通過上述兩種方式能解析key為變量的情況。
對應的,那么假設JSON配置的value中包含變量怎么辦呢,直接看下面這個例子:
我們在JSON中英文中分別添加如下代碼:
// en.json
{
"sayName":"my nam is {{userName}}"
}
// zh.json
{
"sayName":"我的名字是{{userName}}"
}
在HTML中添加如下代碼:
<p>{{ 'sayName' | translate:'{ userName: "聽風是風" }' }}</p>
<p translate="sayName" translate-values='{ userName: "聽風是風"}'></p>
<p translate="sayName" translate-value-user-name='聽風是風'></p>

其實說到底就是為過濾器傳遞罷了,考慮到vaule中包含多個變量的情況,如果全寫在HTML上就不太美觀了,所以我們可以將值定義成一個對象,我們分別在controller與HTML中添加如下代碼:
vm.userName = {
userName: '聽風是風'
};
<p>{{ 'sayName' | translate:vm.userName}}</p>
<p translate="sayName" translate-values='vm.userName'></p>
其實效果還是一樣,看着也舒服了很多,萬一存在多個變量,咱們也是為controller中的對象添加屬性而已。
叄 ❀ 貳 在controller中使用國際化
上面例子舉了一大堆,其實都是在HTML上使用過濾器實現語言國際化,那么問題來了,假設我在controller中有一個彈窗,彈窗內容也得支持國際化,這個文本咋整呢?我們使用$translate.instant()
方法,看個例子:
請分別在HTML於controller中添加如下代碼:
<button ng-click="vm.alert()">點我</button>
vm.alert = function () {
let msg = $translate.instant('sayName', {
userName: 'echo'
});
alert(msg);
};
這里大家自行測試,說直白點,$translate.instant
接受了兩個參數,第一個是你要找的key,第二個參數是傳遞給JSON文件中變量的值。
問題來了,有的同學說為啥我的$translate.instant
無效,就是獲取不到,大家直接在controller外層添加如下代碼,注意,不要用事件去包裹它,看看控制台打印結果:
let msg = $translate.instant('sayName', {
userName: 'echo'
});
console.log(msg);//sayName
可以看到直接輸出了key,並沒找到我們想要的值,這是因為translate加載JSON並查找的過程是一個異步,大家可以修改加載語言引用的邏輯,比如將config修改成如下代碼:
.config(function ($translateProvider) {
// 注冊語言表
$translateProvider
.translations('en', {
"sayName": "my nam is {{userName}}"
})
.translations('zh', {
"sayName": "我的名字是{{userName}}"
});
// 設置默認的語言
$translateProvider.preferredLanguage('zh');
});
OK,再刷新頁面看看控制台,我們發現成功獲取到了。
有同學就不樂意了,這樣做雖然解決了語言表異步的問題,但是語言表一旦多了,看着就非常不美觀了。沒事,咱們再將config改回到最初的樣式,然后在controller中添加如下代碼:
$translate('sayName', {
userName: 'echo'
}).then(function (resp) {
console.log(resp)
}, function (err) {
console.log(err)
});
$translate(key)
方法返回一個promise,也就是說即便文件引用是異步的情況,我們通過這種方式也能成功獲取到想要的語言內容,當然缺點也非常明顯,每次做查詢都得寫promise回調,代碼看着非常不爽。那么貼上最后的解決方法,給大家做個參考。
肆 ❀ 僅供參考的方案
HTML中我就不說了,主要說說config,我的寫法是這樣:
.config(function ($translateProvider) {
// 獲取語言模塊
let enLanguage = require("../language/en.js");
let zhLanguage = require("../language/zh.js");
// 注冊語言表
$translateProvider
.translations('en', enLanguage.language)
.translations('zh', zhLanguage.language);
// 設置默認的語言
$translateProvider.preferredLanguage('zh');
});
而語言表就不是放在JSON文件中了,而是放在了兩個JS文件中進行管理,這里我借用了mod.js讓JS模塊化,代碼如下:
//en.js
exports.language = {
"sayName": "my nam is {{userName}}"
}
//zh.js
exports.language = {
"sayName": "我的名字是{{userName}}"
}
這么做的好處其實就兩點,第一語言有獨立的文件進行管理,便於后期維護;第二解決了文件加載查詢異步問題,在controller中我們獲取多語言就非常方便。
最后提一點,假設我們在中文中配置了一個key,因為疏忽導致在英文中忘記配置了這個key,那么用戶在切換語言時因為找不到對應的key,這就會加載失敗,官方在config中還提供了一個非常棒的方法,直接上代碼:
$translateProvider
.translations('en', enLanguage.language)
.translations('zh', zhLanguage.language)
.fallbackLanguage(['en', 'zh']);
fallbackLanguage
的作用就是,假設一個key查找失敗,那么angular-translate
就會以['en', 'zh']
為替補語言進行查找,以此來保證某個key找不到,你的頁面至少是有一種候補語言能展示出來。
那么關於angular-translate
的使用介紹就說到這里了,本文結束。