多语言的实现有多种途径,常见的有以下几种方法:
1. 复制程序,更改语言
此种方法最大的弊端是当程序需要再次修改时,要修改所有语言下的程序,流程是相当的繁琐。
2. 定义语言文件
如phpMyAdmin。 在phpMyAdmin项目的lang目录下有很多文件,根据用户的语言选择进行包含,然后替换掉原来定义的变量值。
3. GNU的gettext方法
如WordPress。在WordPress项目的wp-content \languages中有许多的语言文件。甚至你可以到WordPress的官网(http://svn.automattic.com/wordpress-i18n/)下载需要的.mo语言包文件,然后在wp-configure.php中更改define ('WPLANG', 'zh_CN');成相关语言包文件名即可。
GNU的gettext方式已经成为流行趋势,下面探讨的就是这种方式。下面是在windows环境下的操作,linux的操作可先在相应的安装包安装后操作就可以了。
手工设置的步骤分为:安装gettext->用xgettext命令生成.po文件->.翻译.po文件中的字符串->msgfmt命令生成.mo->提交.mo文件到语言目录->更改语系启用语言。
1. 安装gettext
下载并安装字符串抽取工具gettext-0.14.4(http://gnuwin32.sourceforge.net/packages/gettext.htm)。此工具用来生成.po和.mo文件。注意,安装完毕后要把bin目录加到系统的环境变量中并重启计算机。
Po文件,是语言包的初始文件,用以放置原语言和翻译后的语言。是用xgettext命令从程序文件中提取要翻译的字符串并生成的。具体po文件的生成见生成.po文件并翻译。
Mo文件,是po文件经过msgfmt命令后,生成的程序文件。是最终放到程序中的真正的语言包。用户切换语言,实际上对程序而言是调用不同的mo文件。
Po和mo文件的生成流程通常是这样的:开发人员生成po文件,然后翻译人员对po文件中的文字进行翻译,最后由开发人员或是翻译人员用工具生成程序可用的mo语言。
这种方式的好处在于,当需要更改翻译时,开发人员只要将po文件进行修改,翻译人员对po文件进行翻译修改就可以了,程序和翻译分离,减轻了翻译人员的工作量。
注:PO 是 Portable Object (可移植对象)的缩写;MO 是 Machine Object (机器对象) 的缩写。
2. 生成.po文件并翻译
要生成.po文件要有一个前提,那就是写程序时,要翻译的字符串必须用特殊的格式进行处理,否则gettext软件不能提取出要翻译的字符串,因为它不知道要哪些文字是需要翻译的。具体的格式举php语言说明:
在php文件中用gettext()函数来调用多语言文字,gettext可简化为_()。
Echo _("The category you are trying to create already exists.");
只有在php中用上面的方法对字符串进行处理,xgettext命令才能提取这个字符串,并将它保存到po文件中。
程序写完后,我们可以到gettext.exe的安装目录下的bin目录中,使用下面的命令进行文字的抽取,并生成.po文件。
|
//命令式样 //xgettext -d c:\input_file -o output_file --from-code=UTF-8 //命令实例 //xgettext -d C:\wwwroot\project_a\languages\page_1 -o C:\wwwroot\project_a\languages\zh_CN\LC_MESSAGES\page_1.po --from-code=UTF-8
|
在生成的.po文件中,(文件内容格式详见下面的示例)msgid对应的是原来的语言文字。翻译人员要做的是:对照msgid后面的文字,将msgstr后面的文字翻译成另一种语言。
注意:msgid表示的是Message id,msgstr表示的是Message String。每一个Message必须是既有id又要有翻译,即它们必须成对出现。还有几点要注意:不管是msgid还是msgstr,均不能换行,且msgid不允许重复。
下面是一个po文件的示例:
|
msgid "" msgstr "" "Project-Id-Version: 1.0.0.0\n"#版本,便于维护和实施 "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2009-01-15 10:17+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Language-Team: team <LL@li.org>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n"#换成utf-8 "Content-Transfer-Encoding: 8bit\n" "\n"
msgid "You did not enter a category name." msgstr "您没有输入一个分类目录名称。"
msgid "The category you are trying to create already exists." msgstr "您尝试创建的分类目录已经存在。"
msgid "Category <a href=\"#%s\">%s</a> added!" msgstr "分类 <a href=\"#%s\">%s</a> 被添加" |
每个.po文件只能放一种语言。如果您需要其他语言,您可以拷贝此.po文件,更改msgstr为对应语言翻译即可。具体如何拷贝详见4.设置mo文件位置。
Po文件的翻译。除了手工打开po文件进行翻译外,建议翻译人员使用poedit(http://www.poedit.net/)软件进行界面化的翻译操作。
3. 文件生成.mo程序文件
使用msgfmt命令将.po文件生成.mo程序文件
|
//命令式样 //msgfmt -o output.mo exist.po //命令实例 //msgfmt -o C:\wwwroot\mygoodparty\languages\zh_CN\LC_MESSAGES\page_1.mo C:\wwwroot\mygoodparty\languages\zh_CN\LC_MESSAGES\page_1.po
|
4. 设置mo文件位置
将.mo文件,拷贝到您想要放置的目录的"语言/LC_MESSAGES"文件夹下,如你有中文、韩语和日语三种语言文件,并想放置到languages文件夹下,PHP项目的文件结构如下:
|
languages |----zh_CN | |----LC_MESSAGES | |----zh_CN.mo |----ko_KR | |----LC_MESSAGES | |----ko_KR.mo |----ja |----LC_MESSAGES |----ja.mo
|
PHP语言文件目录规则:文件夹目录(任意)/语言LC_ALL名称/LC_MESSAGES/mo文件名(任意).mo
5. apache启用gettext扩展
在php.ini中,将php_gettext.dll;前的注释去掉,并重新启动apache.
Php文件程序实例
page_1.php
|
<?php if( $_REQUEST["lan"] == "" ){ $_REQUEST["lan"] = "en_US"; }
define('PACKAGE',$_REQUEST["lan"]); //mo文件名 putenv('LANG='.$_REQUEST["lan"]); //设置网页语言 setlocale(LC_ALL, $_REQUEST["lan"]); //指定要用的语系,如:en_US、zh_CN、zh_TW bindtextdomain(PACKAGE,'./languages/'); //语言包所在位置 textdomain(PACKAGE); //绑定语言包 ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" dir="ltr"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>$website->title</title> </head> <body> <?php echo _("You did not enter a category name.")."<br /><br />"; echo _("The category you are trying to create already exists.")."<br /><br />";//iconv("big5","gb2312", printf(_("Category <a href=\"#%s\">%s</a> added!"), $_REQUEST["lan"], $_REQUEST["lan"]); ?> </body> </html> |
至此,通过更换语系,就可以更换语言了。
后面,我们在做程序是,只要引用相关公共类,然后以_(“”)或者gettext(“”)的方法对字符串进行引用就可以了。
6.上述方法的缺点及解决方法:
1. 每个文件都要生成.po和.mo文件,且每个后面都可能要维护,文件中的字符串有的有重复,重用性很差,最多只能用拷贝的方式解决;
解决方法:
将所有的.po合并,做成一个.po文件,如中文就叫zh_CN.po,英文就中en_US.po,然后生成一个zh_CN.mo或en_US.mo程序文件程序文件,所有的文件都是用这一个语言包文件。这种合并,可以通过编写php后台程序或者直接使用.bat批处理命令来解决。
2. 使用中每个页面都要如此设置,代码量和磁盘空间,服务器运行代价比较大。
做成函数, 通过设置全局变量,判断语言选择,如变量则重新设置,否则不再处理,避免每次访问的重复设置。也可以暂存到COOKIE中,会员用户可自定制到数据库,避免每次访问均需要更改。
因为程序全是一样的,因此也可以将代码复制成相应语言的份数,转换语言,相当时转换目录。但这有个缺点,目录一变,可能有些文件不能共享,如上传的一些文件。
3. 每增加一种语言,或者每修改一种语言的某个文字,都要手动重新生成,对客户要求太过复杂。具体见第二大项。
7.注意事项
页面编码的改变,更换语言后,页面的编码不再是utf-8了。
8.更多命令
Msgmerge, msgunfmt等。
请参照上述两款软件下的bin目录下的相关exe文件,或阅读其帮助文件,查找更多的功能。
至此,国际化程序就实现了。在后面的第二节中将介绍语言包的自动生成和调用。