昨天我們介紹了 實驗性功能
裡的 Resizable
元件,另一個基於 Monaco Editor
開發的 Code Editor
元件,對於開發線上編輯器或者程式碼預覽等功能時很有用處,我們不過多介紹,感興趣的同學可前往官網檢視使用示例。
今天我們介紹一下 NG-ZORRO 的國際化方案,同時也會介紹 Angular i18n 的部分內容。
使用過 Angular 的同學都應該瞭解過其國際化相關的知識,其 i18n 模板翻譯流程有四個階段:
Angular 本身簡化了國際化工作的下列幾個方面:
而這些工作,我們只要在需要翻譯的元素上打上標籤,執行ng xi18n即可自動創建出xlf檔案,通常為message.xlf,搭配語義化的 ID,可很好地維護,這部分內容在 國際化(i18n)
一章可瞭解到詳細的知識。
一個最簡單的翻譯標籤:
<html>
<head>
<meta charset="utf-8">
<title>Angular i18n</title>
</head>
<body>
<h1 i18n="Site Header|An introduction header for i18n Project@@stTitle">Angular 國際化專案</h1>
<p>
<span i18n="@@agDescription">國際化是一項很具有挑戰性,需要多方面的努力、持久的奉獻和決心的任務。</span>
<span class="delete" i18n-title="@@agDelete" title="刪除"></span>
</p>
<p><ng-container i18n=@@agLetGo>讓我們現在開始吧!</ng-container>朋友!</p>
</body>
</html>
我們最初在專案的 app.module.ts
檔案裡看到過 locale 的設定,這是 Angular 本地化設定地區操作:
import { registerLocaleData } from '@angular/common';
import zh_Hant from '@angular/common/locales/zh-Hant';
// the second parameter 'zh-tw' is optional
registerLocaleData(zh_Hant, 'zh-tw');
關於 Angular 國際化基礎我們不過多展開,我們下面來看一下 NG-ZORRO 是如何設定國際化的。
/** 配置 angular i18n **/
import { registerLocaleData } from '@angular/common';
import en from '@angular/common/locales/en';
registerLocaleData(en);
/** 配置 ng-zorro-antd 國際化 **/
import { NZ_I18N, en_US } from 'ng-zorro-antd/i18n';
@NgModule({
...
imports : [ NgZorroAntdModule ],
providers : [
{ provide: NZ_I18N, useValue: en_US }
]
})
export class AppModule { }
可以看到,NG-ZORRO 提供了幾個配置型 token
用於全域性配置國際化文案和日期,NZ_I18N
用於國際化文案。除此之外,NZ_DATE_CONFIG
用於修改日期相關特性,預設使用 Angular 的語言包來進行日期格式化(需要引入相應的Angular語言包)。
之前介紹 Date
元件的專案中,我們也寫過如何使用 NzI18nService
來動態切換語言顯示:
import { en_US, NzI18nService } from 'ng-zorro-antd/i18n';
...
constructor(private i18n: NzI18nService) { }
switchLanguage() {
this.i18n.setLocale(en_US);
}
另外,它還提供了可選的 NZ_DATE_LOCALE
用於 date-fns
方式來格式化本地日期。
預設配置如下:
{
/** 指定哪一天為一週的開始(null表示採用內部預設值,0表示星期日,1表示星期一,以此類推) */
firstDayOfWeek: null
}
日期配置通常是為了適應不同國家對一週第一天的不同情況,一些操作我們在介紹 Date
元件時也有所涉及。當然,如果有需要使用 date-fns 進行日期格式化的需求,也可以切換至 date-fns 方式日期格式化
。
我們下載 NG-ZORRO 原始碼可以發現,其 components
資料夾下存放著 i18n
資料夾,所有國際化相關的程式碼都在這裡:
components/i18n
├── date-config.ts
├── date-helper.service.spec.ts
├── date-helper.service.ts
├── index.ts
├── languages(all languages files)
├── nz-i18n.interface.ts
├── nz-i18n.module.ts
├── nz-i18n.pipe.ts
├── nz-i18n.service.spec.ts
├── nz-i18n.service.ts
├── nz-i18n.token.ts
├── package.json
└── public-api.ts
我們先看一下 languages
檔案的全域性翻譯結構是什麼 - zh_CN.ts
:
import Calendar from './calendar/zh_CN';
import DatePicker from './date-picker/zh_CN';
import Pagination from './pagination/zh_CN';
import TimePicker from './time-picker/zh_CN';
export default {
locale: 'zh-cn',
Pagination,
DatePicker,
TimePicker,
Calendar,
// locales for all comoponents
global: {
placeholder: '请选择'
},
Table: {
filterTitle: '筛选',
filterConfirm: '确定',
filterReset: '重置',
selectAll: '全选当页',
selectInvert: '反选当页',
sortTitle: '排序'
},
Modal: {
okText: '确定',
cancelText: '取消',
justOkText: '知道了'
},
Popconfirm: {
cancelText: '取消',
okText: '确定'
},
Transfer: {
searchPlaceholder: '请输入搜索内容',
itemUnit: '项',
itemsUnit: '项'
},
Upload: {
uploading: '文件上传中',
removeFile: '删除文件',
uploadError: '上传错误',
previewFile: '预览文件'
},
Empty: {
description: '暂无数据'
},
Icon: {
icon: '图标'
},
Text: {
edit: '编辑',
copy: '复制',
copied: '复制成功',
expand: '展开'
},
PageHeader: {
back: '返回'
}
};
所有的語言檔案都遵循這個結構,於是 nz-i18n.service.ts
的核心方法(如下)就可以按照 path
路徑去解析查詢到對應的文字從而渲染預設設定:
// [NOTE] Performance issue: this method may called by every change detections
// TODO: cache more deeply paths for performance
/* tslint:disable-next-line:no-any */
translate(path: string, data?: any): string {
// this._logger.debug(`[NzI18nService] Translating(${this._locale.locale}): ${path}`);
let content = this._getObjectPath(this._locale, path) as string;
if (typeof content === 'string') {
if (data) {
Object.keys(data).forEach(key => (content = content.replace(new RegExp(`%${key}%`, 'g'), data[key])));
}
return content;
}
return path;
}
// tslint:disable-next-line:no-any
private _getObjectPath(obj: IndexableObject, path: string): string | object | any {
let res = obj;
const paths = path.split('.');
const depth = paths.length;
let index = 0;
while (res && index < depth) {
res = res[paths[index++]];
}
return index === depth ? res : null;
}
其餘幾個關於 Date
日期的國際化處理也是差不多的邏輯,如果你在使用中發現部分翻譯並不是正確的或者要提供一個新的地區語言檔案,你也可以按照這些格式修改檔案並提交 Pull Request
要求開源社群組來儘快修復它。
我們今天粗略地介紹了 Angular 和 NG-ZORRO 的國際化方案,如果在使用中出現問題也可以去 Github Issue 去查詢或者建立提問,通常來說,你想要知道的答案都能在 Issue 列表中找到,無法解決的按照官方提問連結建立 Issue 也會很快得到解釋。