更新 : 2017-06-17
<h1 i18n="site header|An introduction header for this sample">Hello {{ name }} world</h1>
<source>Hello <x id="INTERPOLATION"/> world</source>
<target>哈喽 <x id="INTERPOLATION"/> 世界</target>
angular 支持 interpolation {{ }}
你要在 target 去掉 interpolation 也是 ok 的.
说说真实项目中的场景. 除了这种能写在模板上的翻译,我们通常还有一些动态的翻译比如 sql 资料.
比如 :
class Member
{
name_en : string;
name_cn : string;
}
我的做法是为每一个 member 对象添加一个 name 属性, getter(){ if( this.locale == 'zh-CN'...) { return this.... } }
import { LOCALE_ID, Inject } from '@angular/core';
constructor( @Inject(LOCALE_ID) private locale: string) { }
locale 如果没有使用 i18n 的话,会拿 user-agent 的哦
日期 : 2017-04-24
refer :
https://v2.angular.io/docs/ts/latest/cookbook/i18n.html#!#aot
https://github.com/angular/angular-cli/issues/2201
http://blog.danieleghidoli.it/2017/01/15/i18n-angular-cli-aot/
针对翻译, ng 提供了一个解决方案.
流程大概是这样的.
在写模板的时候我们通过一些记号, 标识出要翻译的部分
<h1 i18n="User welcome|An introduction header for this sample">Hello i18n!</h1>
类似上面这样, i18n 是个标识, 内容是一些描述
所有模板都写好了以后
windows cmd 运行 "./node_modules/.bin/ng-xi18n" --i18nFormat=xlf
这时 ng 会从我们的模板中提取这些标识的内容创建出一个 messages.xlf 的 file.
<?xml version="1.0" encoding="UTF-8" ?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="ng2.template">
<body>
<trans-unit id="af2ccf4b5dba59616e92cf1531505af02da8f6d2" datatype="html">
<source>Hello i18n!</source>
<target>我爱你妈</target>
<note priority="1" from="description">An introduction header for this sample</note>
<note priority="1" from="meaning">User welcome</note>
</trans-unit>
</body>
</file>
</xliff>
大致上长这样, <target> 一开始是空着的, 我们把翻译写进去.
如果你支持很多语言,那么就 copy paste 这个 file 给每个 file 一个特别的名字比如 : messages.cn.xlf, messages.en.xlf
翻译完成了以后
cmd : ng build --prod --i18nFile=./src/locale/messages.zh-cn.xlf --locale=zh-CN --i18nFormat=xlf --bh=/cn/ --output-path=cn
ng serve --aot --i18nFile=./src/locale/messages.zh-cn.xlf --locale=zh-CN --i18nFormat=xlf (只有 aot 可以跑 ng serve 哦)
bh 是 base href, output-path 默认是 dist, 因为我们有很多版本语言, 所以我们需要重复 build 很多个版本出来.
最后就是 publish to server 咯.
整个流程看完. 我们可以了解到, ng 的做法是让每个语言独立一个 index.html 版本.
好处是快咯,隔离的好咯
坏处是, 如果要改视乎 rebuild 的工作量不少. 当然我觉得这个应该是最后的环节了. 不太可能一直改.
网页中除了一般的静态资料需要翻译,动态资料也是需要翻译的,比如 sql 的 data, alert error message. 这些不在 ng 包含的范围内, 我们得自己处理哦。
外传 :
refer : https://github.com/googlei18n/libphonenumber
介绍一下 google i18n/ libphonenumber
做国际站, 电话号码也是需要处理好的.
npm install google-libphonenumber --save
npm install @types/google-libphonenumber --save-dev ( 版本可能不够新哦, 比如目前是 7.4 但是 lib 已经 8.4 了, getSupportRegions 方法就没找着 /.\ )
import { PhoneNumberUtil, PhoneNumberFormat } from 'google-libphonenumber'; let sg = '+65 9026 9356';
let phoneUtil = PhoneNumberUtil.getInstance();
let number = phoneUtil.parse(sg, '');
let code = phoneUtil.getRegionCodeForNumber(number); //SG
let ok = phoneUtil.isValidNumber(number);
let formatA = phoneUtil.format(number, PhoneNumberFormat.INTERNATIONAL); //+65 9026 9356
let formatB = phoneUtil.format(number, PhoneNumberFormat.NATIONAL); // 9026 9356
需要注意的是,任何操作都是使用 phone number 对象, 所以记得要 parse.
主要用途是验证是不是 phone number, 还有转换格式.
除了 js 还有其它版本的哦,比如 c#.
public ActionResult Index()
{
var sg = "+65 9026 9356";
var phoneUtil = PhoneNumberUtil.GetInstance();
var number = phoneUtil.Parse(sg, "");
var code = phoneUtil.GetRegionCodeForNumber(number); //SG
var ok = phoneUtil.IsValidNumber(number);
var formatA = phoneUtil.Format(number, PhoneNumberFormat.INTERNATIONAL); //+65 9026 9356
var formatB = phoneUtil.Format(number, PhoneNumberFormat.NATIONAL); // 9026 9356
List<string> x = phoneUtil.GetSupportedRegions().ToList();
int codex = phoneUtil.GetCountryCodeForRegion(x[]);
return View();
}