多语言的实现有多种途径,常见的有以下几种方法:

    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文件进行翻译外,建议翻译人员使用poedithttp://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文件,或阅读其帮助文件,查找更多的功能。

 

      至此,国际化程序就实现了。在后面的第二节中将介绍语言包的自动生成和调用。