如果不了解如何在cakephp中解决i18n问题,或者不知道什么是i18n问题,请先阅读:如何使用cakephp实现多语言网站。
在开发的时候,尤其是英文,单数和复数的问题很难搞,编码要考虑周全何时预留单数复数的占位符,并且要根据数量写很多if-else。如果baker们只是通过阅读cookbook来学习cake,那么是找不到好办法解决这个问题的,不知为什么,官方并没有写这方面的解决文档。通过看源码、google,今天终于想清楚了这个问题,在这里分享一下。
假设我们有一个需求,要在页面输出这样的文本:Mr Brown has 3 apples at all. 其中3是变量,可能是1-n的自然数,当布朗先生只有一个苹果时,我们应当输出:Mr Brown has 1 apple at all. 在编码时,我们可以这样写:
$text = __n("Mr Brown has %d apple at all.", "Mr Brown has %d apple at all.", 3, true);
printf($text, 3);
这里使用了cake提供的__n()方法,而不是__()方法。它的前两个参数分别是文本的单数和复数占位符,第三个参数是苹果的个数,第四个参数表示此文本只是作为结果返回给$text,而不直接输出到页面。
之后使用cake提供的命令行工具:cake i18n,生成pot文件后,可以找到这样的内容:
msgid "Mr Brown has %d apple at all."
msgid_plural "Mr Brown has %d apple at all."
msgstr[0] ""
msgstr[1] ""
前两行就是刚才我们在代码中写的第一和第二个参数。后两行分别对应翻译语句的单数和复数形式,我们根据pot来生成po,翻译第三、四句如下:
msgstr[0] "Mr Brown has %d apple at all."
msgstr[1] "Mr Brown has %d apples at all."
在查看页面,就得到了我们想要的结果:Mr Brown has 3 apples at all.
在这个过程中,有个问题需要注意:po文件的头部有这样的设置语句:"Plural-Forms: nplurals=2; plural=(n != 1);\n"。这里配置的是当前语言(English、Chinese等)的复数特征,上面所写是英文的。如果是中文po文件,应当写成:"Plural-Forms: nplurals=1; plural=0;\n"。其他语言可以到这里去查:http://translate.sourceforge.net/wiki/l10n/pluralforms。
即便如此,生成pot文件之后的翻译工作也相当麻烦,尤其是项目中有新旧版本需要比较、合并的时候。下一篇博客将会想办法改进翻译过程,敬请期待。