您的位置:首页 > 编程语言 > PHP开发

PHP多语言支持(gettext & po & mo)

2012-08-02 23:55 417 查看
PHP使用gettext扩展实现国际化(l18n)与本地化(l10n)

http://hi.baidu.com/tianhuimin/item/5e9d502c8b0b5b0e73863e62

PHP多语言支持(gettext & po & mo)

http://code-tech.diandian.com/post/2012-05-03/19818092

po文件本来是用来翻译程序源代码里的字符串的。

目前大部分自由软件实现国际化使用的是gettext。国际化就是让程序可以使用多国语言来显示程序里的字符串。程序里一般都有很多字符串,菜单名也好,错误信息也好,都是字符串。假设字符串为string,非国际化的程序里都是直接写”string”。如果用了gettext来实现国际化的话,就要写成gettext(“string”)。有时也会看到_(“string”),那实际上也是gettext,只不过通过宏的定义把 gettext改头换面了。这个string就是msgid。然后使用xgettext来从程序源代码文件产生po文件。然后交给专门的翻译人员来翻译
po。翻译人员根本不需要懂编程。翻译完毕后,使用msgfmt来把po转化成mo文件,并安装到系统里合适的位置。程序运行时,到底显示什么字符串就是 由gettext 函数来决定的了。主要有两个决定因素,一个是系统的locale及相关环境变量(LANGUAGE,LC_ALL,LC_MESSAGES和LANG), 一个是相关的mo文件。具体可以看我的这篇文章 。

随着程序版本的升级,程序里的字符串的数量和内容都会发生变化,但变化不会很大,以前翻译过的po里大部分msgid都能被重复利用。所以维护po的翻译人员在每次得到从新的程序源代码产生的po时,都用msgmerge来根据旧的已翻译过的po来先处理一下新的未翻译的po。处理过后,大部分情况下新po就翻译的差不多了。翻译人员的工作量被大幅度减轻了。

po文件格式解析

po文件都是由一对对的msgid和msgstr组成的。msgid就是原文。msgstr就是译文。原文译文相互对照,所以非常适于翻译。

msgid “Flash Player 9 released”

msgstr “”

有的msgid前面一行有fuzzy的字样。这说明,第一这个po是被msgmerge处理过的;第二,已翻译的po里没有和这个msgid完全等同的 msgid,只有非常相似的。这种情况下,msgmerge仍然会用那个相似的msgid来翻译此msgid。不过会给这个msgid标记为fuzzy, 表示翻译人员仍然要翻译这 个msgid,并在翻译后去掉上面带fuzzy的这一行。

#, fuzzy

msgid “Gentoo Linux PPC Handbook”

msgstr “Gentoo Linux Alpha手册”

po文件翻译的好处

1. 原文译文相互对照,适于翻译

2. 一篇文章里同一个msgid不管出现多少次,都只需要翻译一次

3. 旧有的已翻译过的po,可以重复利用,不必再次翻译,且利于统一风格

4. 有非常好的翻译工具,熟练使用后可大幅度提高工作效率

应用实例

我们在使用 WordPress 及其插件时,经常可以找到汉化的版本,一般是通过一个汉化过(翻译过)的 mo 文件来实现( WordPress 仅可识别 mo 文件),实际上不单 WordPress ,包括很多桌面应用程序都是是依靠 po 文件或 mo 文件来实现多语言版本。如果原作者提供了一个 po 文件或 mo 文件,那么我们就可以通过相关工具来自行汉化,或者翻译成其他语言版本。因为mo 文件不能直接编辑,所以我们得编辑 po 文件,若仅有 mo 文件,那么就应该先把它转换成
po 文件后再进行编辑翻译。

至于编辑工具,由于 po 文件本身就是一个文本文件,所以任何文本编辑器都可以使用。除了专门编辑 po 文件的poEdit ,还推荐使用 EditPlus、UltraEdit或者你喜欢的 vi 或 vim。

我们来看一个 po 文件,这是 yskin 制作的 WordPress 2.11 中文版 po 文件 中的一部分

msgid “”

msgstr “”

“Project-Id-Version: WordPress 2.1-1.0\n”

“PO-Revision-Date: 2007-02-22 12:35+0800\n”

“Last-Translator: yskin \n”

“MIME-Version: 1.0\n”

“Content-Type: text/plain; charset=utf-8\n”

“Content-Transfer-Encoding: 8bit\n”

“X-Poedit-Basepath: d:/wordpress\n”

“X-Poedit-Language: Simplified Chinese\n”

“X-Poedit-Country: China\n”

“X-Poedit-SourceCharset: utf-8\n”

“X-Poedit-KeywordsList: _e;__;__ngettext:1,2\n”

“Language-Team: \n”

“POT-Creation-Date: \n”

“Plural-Forms: nplurals=1; plural=0;\n”

“X-Poedit-SearchPath-0: .\n”

# 第一条要翻译的字符串。

#: wp-comments-post.php:15

msgid “Sorry, comments are closed for this item.”

msgstr “对不起,这篇文章禁止评论。”

上面是这个 po 文件的最初部分,各行意思一目了然,注意编码尽可能采用UTF-8。

# 第一条要翻译的字符串。

#: wp-comments-post.php:15

msgid “Sorry, comments are closed for this item.”

msgstr “对不起,这篇文章禁止评论。”

这段就是po文件的主体结构了,每一个翻译项占一段。#: wp-comments-post.php:15 说明字符串相应的位置; msgid “Sorry, comments are closed for this item.” 翻译前的原文; msgstr “对不起,这篇文章禁止评论。” 翻译后的字符串。以此类推,即可完成所有资源的翻译。非常简单。

那么如何将 po 文件编译成(转换) mo 文件呢?

如果你使用的是 poEdit ,按 Ctrl + s 保存就会自动生成相应的 po 文件和 mo 文件;

或者在命令提示符界面,使用msgfmt demo.po 命令将po文件编译为可用的 demo.mo 文件,用msgunfmt demo.mo 命令转回 demo.po 文件,这些命令在 poEdit 的安裝目录下有,可以拷贝msgunfmt.exe 、msgfmt.exe 及相关链接库文件 gettextlib.dll 、gettextsrc.dll 、iconv.dll
、intl.dll 到 c:/windows/system32 目录下,或者安装 .Net 2.0环境。

另外推荐一款 GUI 界面的转化程序 po2mo.exe ,作者的说明:该程序是调用 msgfmt.exe 和 msgunfmt.exe 文件,从而进行po 、mo 文件互转。文件是用C#写的,需要.Net 2.0环境。

PHP的gettext用法

gettext程序在Linux/Unix世界中很常见,但一般人日常使用的机会不多。它用来为应用程序添加国际化支持。举个例子,如果一个程序中的字符串资源没有硬编码在程序源文件中,而是以一种语言包的文件存在的,那么就可以通过添加语言包文件来改变程序界面的语言。gettext就可以做这种事。

Windows下的PHP5中已经带有了gettext扩展,Zend Server也以带有该扩展。在php.ini文件中将“extension=php_gettext.dll”前面的分号去掉,重启Apache,如果一切正常的话,在phpinfo()的输出中应该会有gettext一节。下面有一个简单的“Hello World”的例子来看看如何用gettext来达到支持多语言的目的。

创建一个PHP文件test.php,内容如下:

<?php

putenv(“LANG=zh_CN”);

setlocale(LC_ALL, ‘zh_CN’);

bindtextdomain(‘test’, ‘./locale’);

textdomain(‘test’);

echo gettext(‘Hello World!’);

?>

开头两行代码设置语言环境为’zh_CN’,也就是简体中文bindtextdomain设置域test的目录为当前目录下的locale目录textdomain(’text’)告诉PHP解释器,gettext函数要去test域中去寻找替代字符串

在浏览器中打开这个文件,可以看到结果为“Hello World”,只是原样输出而已,因为还没有制作中文语言包。要让浏览器输出中文而不改变源程序,需要准备两个文件,PO和MO文件。为了得到这两个文件,需要使用xgettextmsgfmt两个程序。Windows用户可以去GnuWin32下载GetText软件包,里面就有这两个程序。

接着建立相应的目录结构。在test.php的目录下建立“locale\zh_CN\LC_MESSAGES”这样的目录。目录名zh_CN一定要和代码中的语言名称zh_CN相同。然后在命令提示符下执行:

xgettext -d test test.php

“-d test”表示domain为“test”,这会在当前目录下生成test.po这个文件。
用文本编辑器打开它,做如下修改:



“Content-Type: text/plain; charset=GB2312\n”

“Content-Transfer-Encoding: 8bit\n”

#: test.php:11

msgid “Hello World!”

msgstr “你好,世界!”

即将charset设置为中文编码“GB2312”,将相应的msgid中的英文字符串翻译成中文填入到下面的msgstr中。接下来用msgfmt生成MO文件。MO是一个二进制格式的文件,gettext从它里面提取字符串资源。在命令提示符中执行以下命令可以从刚刚修改的PO文件得到MO文件:

msgfmt -o test.mo test.po

最后将test.po和test.mo放在locale\zh_CN\LC_MESSAGES目录下,刷新浏览器,即可看到显示的是中文。

对于使用gettext的PHP程序来说,gettext函数往往用的非常多。因此在PHP中可以使用“_”来代替“gettext”,所以gettext(”Hello World!”)也可以写成“_(”Hello World!”)”。

总结

PO: Portable Object (可移植对象)

MO: Machine Object (机器对象) 二进制文件
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: