細翻翻看歷史文章,其實關於Angular的總結已經有了不少,然而實際開發和測試工作中發現關於Angular的i18n bug依然層出不窮。近日又碰到一個“頁面未載入,請返回上一個頁面或重新整理頁面再試一次”的問題,而App本應該向用戶展示一個帶有date-picker的頁面,如下圖所示。
打開console會發現如下的錯誤信息。
個人看來,凡是在某個問題上不斷犯錯,正如“大師兄,師傅和二師兄又被妖怪抓走了”……再好似段譽的六脈神劍時靈時不靈的情景,大抵上是因爲依然沒有理解該問題癥結所在,同時並未掌握解決該問題的套路和招式。不揣冒昧,這裏嘗試提出解決AngularJS i18n問題的五部曲。
1. 添加需要支持的所有locale
如果我們希望Angular pipes同時支持所有locale默認對應的時間,日期,貨幣,小數點,千分位,百分號之類的格式,請務必執行改步驟。因爲Angular默認使用en-US作爲語言環境,沒有考慮其他。如果我們需要支持zh等locale,就需要在app.module.ts中進行配置,示意代碼如下。
import { registerLocaleData } from '@angular/common';
import locale_zh from '@angular/common/locales/zh';
registerLocaleData(locale_zh, 'zh');
// 注意zh這裏僅僅表示簡體中文,一旦需要繁體臺灣,繁體香港,請import zh-Hant, zh-Hant-HK
2. 設置當前locale
Angular會讀取名爲LOCALE_ID的注入令牌來設置當前的語言環境。這意味着我們每次必須根據所需使用的語言環境來更改該令牌,如下所示:
providers: [{provide: LOCALE_ID, useValue: 'zh-Hans' }]
如果我們希望支持用戶在runtime的時候來切換語言環境,則必須創建一個類或工廠函數來讀取該值,示意代碼如下:
export class DynamicLocaleId extends String {
locale: string;
toString() {
return this.locale;
}
}
...
providers: [
...
{ provide: LOCALE_ID, useClass: DynamicLocaleId }
],
3. 對所有文本使用翻譯策略
Angular 通過在HTML元素上使用簡單的i18n屬性來支持文本翻譯,這種實現方式最大的問題就是——每種語言都需要一個構建。也就是說,如果我們期望支持六種自然語言,則需要在不同的文件夾中部署6種不同的內部版本,同時在runtime切換到另一種語言需要重新加載應用程序。所以實踐中我們大多放棄該策略,轉而使用ngx-translate來處理i18n的原因。
4. 安裝配置ngx-translate
5. 使用ngx-translate
關於4-5部分,細節內容非常多,需要單獨的文章進行詳述,本文僅爲Angular的使用套路做個框架性的勾勒和白描,故不多累述。
閒言少敘,使出招式一,添加我們所需要的所有locale
public registerAngularLocaleData(culture: string): Promise<void> {
...
private initLocalization$(context: ApplicationContext): Observable<ApplicationContext> {
...
return import(
`@angular/common/locales/${culture}.js`
)
.then((locale) => {
registerLocaleData(locale.default);
});
...
const culture = context.locale.split('-')[0];
...
const angularLocalizationInit$ = culture === 'en' ? of(true) : this.registerAngularLocaleData(culture);
只一招,頁面無法正常顯示的問題似乎煙消雲散了。萬事大吉,收工了事?其實不然,細心的同學一定已經發現,這裏我們使用了locale.split導致只import並register了zh這樣的locale,而zh-Hant,zh-Hant-HK的細分市場完全被忽略了。不信就讓我們重新打開帶有date-picker的頁面看看現在顯示的是“週日”還是“週日”吧。