AngularJS 2 国际化支持
内容回顾
在之前的文章里面,我们探讨过 AngularJS 2 本地化支持上面的改变:
- 通过在需要翻译的内容上添加 i18n HTML 属性
- 利用ng - xi18n 工具抽取字符串到标准的交互格式XLIFF文件中
- 在翻译完成后,Angular compiler 导入翻译的文件,编译生成Application 可以直接调用的Json 字符串。
前两点除提供基本的本地化支持外。在提高翻译质量也提供了一些便利的接口:
- 上下文提示,UI 本地化最重要的一点是需要提供上下文信息,目前行业里面除了通过comments这样的方式外,类似 YouTube 这样的大公司已经可以做到上下文截图和实时预览(Live Preview)。当然AngularJS里面也提供了相应的机制,给普通的message加comments,以便于翻译人员理解上下文。
<p i18n="Label to show the maximum length of characters allowed in comments.">
Limit is 255 characters.
</p>
- AngularJS 中如果message中含有占位符,在提取后会被加上提示信息:
<p>Limit is MAX_CHARS characters.</p> //Placeholders MAX_CHARS comments: Angular Expression example: 255
- AngularJS 支持复数和性别的:
{{numMessages, plural,
=0 { You have no new messages }
=1 { You have one new message }
other { You have # new messages }
}}
{{friendGender, select,
male { Invite him }
female { Invite her }
other { Invite them }
}}
- 本地化会带来的layout问题,AngularJS 也不例外。 通常情况下,翻译周期会很长。当翻译文件提交回来时,如果才发现翻译导致的样式问题,可能已经为时已晚或者说很多Bug修复起来没有那么容易。要解决这个问题可以在设计阶段通过机器翻译或者pseudo检查出潜在的样式兼容性和扩展性问题,在送翻译之前,就能先解决掉潜在的隐患。VMware 自主研发的UI Layout Sniffer 将开源,主要针对web application layout的高可用性。
说完基本的提取和可译性优化外,还有一点是本地化编译过程的选择,根据应用的特点可以灵活的选择编译的方式。在AngularJS中提供了两种编译资源文件的方式,JIT,应用启动时编译本地化的资源文件,基本流程如下:
- 确定当前用户的Locale信息。
- 将翻译文件以字符串常量的形式导入。
- 创建和插入翻译供应器到JIT 编译器。
- 基于创建的供应器启动引导应用。
<script>
// Get the locale id somehow
document.locale = 'de';
// Map to the text plugin
System.config({
map: {
text: 'systemjs-text-plugin.js'
}
});
// Launch the app
System.import('main.js').catch(function(err){ console.error(err); });
</script>
JIT 编译器是动态的加载翻译,在应用启动时,完成所有的本地化编译工作,如果应用的字符串集合比较小,可能不会影响加载的性能,相反会造成应用的加载过慢。这个时候我们要考虑提前编译(AOT),借助 ngc 编译的命令,提前编译好每一个语言特定的资源包,而在应用启动的时候,只需要确定locale,然后调用对应的资源包,省去了编译的时间。例如:
./node_modules/.bin/ngc --i18nFile=./locale/messages.es.xlf --locale=es --i18nFormat=xlf
说了很多关于AngularJS 在本地化的支持,下面我们聊下AngularJS 2 在国际化支持上面的变化。
AngularJS 国际化
AngularJS2 在国际化支持,相对于AngularJS1.x 没有太多的变化。 具体的实现我就不在这边累述了,大家如果有需要可以参考之前的文章。AngularJS 国际化的关键点:
- Locale的获取,根据应用场景不同选择合适的用户Locale获取途径,请参见之前的文章。
- 获取Locale后,调用对应 angular-locale_{{locale}}.js,所有AngularJS能提供的国际化pattern都以字符串的形式定义在此文件种。例如de的NUMBER_FORMATS:
"NUMBER_FORMATS": {
"CURRENCY_SYM": "\u20ac",
"DECIMAL_SEP": ",",
"GROUP_SEP": ".",
"PATTERNS": [
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 3,
"minFrac": 0,
"minInt": 1,
"negPre": "-",
"negSuf": "",
"posPre": "",
"posSuf": ""
},
{
"gSize": 3,
"lgSize": 3,
"maxFrac": 2,
"minFrac": 2,
"minInt": 1,
"negPre": "-",
"negSuf": "\u00a0\u00a4",
"posPre": "",
"posSuf": "\u00a0\u00a4"
}
]
},
使用过程中,假如我们在HTML模板里面定义:{{ 1000 | currency }},编译后拿到的货币符号就是locale service 里面localeID 对应的currency 符号。所以要想了解AngularJS在国际化上面的局限性,可以看看这个模式文件,里面还是缺少很多国际化元素的定义。