什么是 I18N 和 L10N ?
I18N 是 internationalization 的缩写形式,意即在 i 和 n 之间有 18 个字母,本意是指软件的“国际化”;与之类似,L10N 是 localization 的缩写形式,意即在 l 和 n 之间有 10 个字母,本意是指软件的“本地化”。
I18N 和 L10N 从何而来?它们有何区别?
按照软件开发的惯例,最初的软件只有英文版本,根据需要,作者再把软件界面和文档翻译成不同国家、地区的语言版本。但是由于实现翻译的途径、翻译的工作效 率、翻译的可重用性等因素各不相同,使翻译工作面临很大困境,也阻碍了软件的推广和应用。为了方便地将软件翻译成不同语言的版本,就需要一套翻译规范和通 用工具,这就导致了“国际化”机制的出现。仅仅翻译是不够的,同一种语言在不同国家、地区可能存在多个支系,它们在表达习惯、语法结构甚至文字种类和编码 上都有不同,方言更是千奇百怪,通用的翻译其质量肯定是不高的。涉及到计算机领域,还存在操作习惯上的差别,而且对某种语言提供完美的输入、显示、打印、 保存、传输并非一件轻而易举的事,这就导致了“本地化”机制的出现。简而言之,“国际化”是“本地化”的一部分,主要是指国际化的实现机制和翻译工作, “本地化”包含“国际化”,是对“国际化”的补充和完善,它还包括为实现对某种特定语言良好的支持而进行的有针对性的翻译调整以及对软件进行的打补丁工作。
I18N 和 L10N 的国际组织是什么?
I18N 和 L10N 的国际组织是 Openi18n 组织, 其前身是 li18nux 组织。它原来是制定 GNU/Linux 自由操作系统上软件全球化标准的国际计划,后来扩充 到 GNU/Linux 之外所有开放源代码的技术领域,因而更名为 Open Internationalization Initiative, 由非营利组织 Free Standards Group 赞助,并为世界各大厂商所支持,对于 GNU/Linux 系统上的多国语言 文字处理技术和环境有决定性的影响。各个开源软件开发组织通常都有负责“国际化”和“本地化”工作的分支机构。
I18N 主要使用什么工具工作?
I18N 主要使用 gettext 软件包使软件实现国际化支持。事实上它是一整套 I18N 解决方案。
什么是 GPL、LGPL 和 GFDL?它们和源代码以及商业销售之间的关系是什么?
GPL 是 GNU General Public License (GNU 通用公共许可证)的缩写形式;LGPL 是 GNU Lesser General Public License (GNU 宽通用公共许可证)的缩写形式,旧称 GNU Library General Public License (GNU 库通用公共许可证);GFDL 是 GNU Free Documentation License (GNU 自由文档许可证)的缩写形式。它们是自由软件(Free Software)的通用版权认证协议,由自由软件基金会(FSF)制定和发布。
- 基于 GPL 的软件允许商业化销售,但不允许封闭源代码。
- 如果您对遵循 GPL 的软件进行任何改动和/或再次开发并予以发布,则您的产品必须继承 GPL 协议,不允许封闭源代码。
- 基于 LGPL 的软件也允许商业化销售,但不允许封闭源代码。
- 如果您对遵循 LGPL 的软件进行任何改动和/或再次开发并予以发布, 则您的产品必须继承 LGPL 协议,不允许封闭源代码。但是如果您的程序 对遵循 LGPL 的软件进行任何连接、调用而不是包含,则允许封闭源代码。
什么是 PO 和 MO 文件?它们有何区别?
PO 是 Portable Object (可移植对象)的缩写形式;MO 是 Machine Object (机器对象) 的缩写形式。PO 文件是面向翻译人员的、提取于源代码的一种资源文件。当软件升级的时候, 通过使用 gettext 软件包处理 PO 文件,可以在一定程度上使翻译成果得以继承,减轻翻译 人员的负担。MO 文件是面向计算机的、由 PO 文件通过 gettext 软件包编译而成的二进制文 件。程序通过读取 MO 文件使自身的界面转换成用户使用的语言。
Linux系统本身具备完善的多语言支持体系,可使同一个可执行文件拥有不同地方语言的图形界面。这其中涉及到两个重要概念:国际化与本地化。
国际化是指将开发者原先使用的母语翻译成多种其他的语言。由于实现翻译的途径、翻译的工作效率、翻译的可重用性等因素各不相同,使翻译工作面临很大困境,也阻碍了软件的推广和应用。为了方便地将软件翻译成不同语言的版本,就需要一套翻译规范和通用工具,于是就诞生了i18n工具集。i18n即“internationalization”的缩写形式,主要使用gettext软件包实现国际化支持。
本地化是指可执行文件能够根据当前的语言环境选择图形界面上使用的语言。除语言以外,字符编码、语法、度量单位、日期时间格式、阅读习惯、使用习惯等也是需要考虑的问题,因此设计了l10n工具集。l10n是localization的缩写形式,主要使用locale软件包实现本地化支持。
在概念中,本地化包含国际化,两者相辅相成。
po文件意为可移植对象;mo文件意为机器对象。po文件是面向翻译人员、提取于Glade项目的一种资源文件。当软件升级的时候,通过使用gettext软件包处理po文件,可以在一定程度上使翻译成果得以继承,减轻翻译人员的负担。mo文件是面向计算机的、由po文件通过gettext软件包编译而成的二进制文件。程序通过读取mo文件使自身的界面转换成用户使用的语言。
-----------------
关于GTK GETTEXT
gettext软件包是GNU工程中解决国际化问题的重要工具,支持C/C++和JAVA语言,它在开源 界应用相当广泛,GNOME/GTK+的国际化问题都是用它来解决的,正常的情况下GNU/LINUX系统是默认安装这一软件包的。
首先,应用程序要包含两个头文件,并且做一下定义:
GTK1.2程序国际化步骤
有两种方法
第一种:使用gettext软件包
首先在源代码加入相关的头文件如下:
#include <libintl.h> //gettext支持
#include <locale.h> //locale支持
然后是定义宏,下面的定义形式在GNOME/GTK+中应用的标准格式:
#define _(string) gettext(string)
#define N_(string) string
在程序的主函数中加入下面相关函数:
//以下函数用来设定国际化翻译包所在位置
bindtextdomain(软件包名,
locale所在目录);
如:bindtextdomain("hellogtk","/usr/share/locale/");
//以下函数用来设定国际化翻译包名称,省略了.mo
textdomain(软件包名);
如:textdomain("hellogtk");
将代码中需要国际化--即多语言输出的字符串改写为_()宏,代码如下:
gtk_window_set_title (GTK_WINDOW(window), _("Hello Gtk!"));
……
label=gtk_label_new( _("Enter a message:") );
……
button=gtk_button_new_with_label (_("Print"));
完成以上修改后,执行如下命令:
xgettext –a -o hellogtk.po hellogtk.c
它的功能是将hellogtk.c中的以下划线开始括号中(如宏定义所示)的字符串加入到hellogtk.po文件中。
修改hellogtk.po文件
po文件的头部可以加入软件包的名称、版本、翻译者的邮件地址等,po文件中以#开始的行为注释内容,以下为省略了头部的hellogtk.po文件内容,msgid后面的内容为英文,msgstr后面的内容为翻译的中文,翻译好后保存为UTF8格式。
注:系统i18n最好改为zh_CN.GB2312,不然翻译的msgstr会存不上。
vi hellogtk.po
"Content-Type: text/plain; charset=
CHARSET/n"
"Content-Type: text/plain; charset=
zh_CN.GB2312/n"
#: hellogtk.c:45
msgid "Hello Gtk!"
msgstr "你好 Gtk!"
#: hellogtk.c:54
msgid "Enter a message:"
msgstr "输入一个信息:"
#: hellogtk.c:64
msgid "Print"
msgstr "打印"
下一步执行命令:
msgfmt -o hellogtk.mo hellogtk.po
cp hellogtk.mo /usr/share/locale/zh_CN.GB2312/LC_MESSAGE
gcc hellogtk.c –o hellogtk `gtk-config --cflags --libs`
./hellogtk
将 hello.po文件格式化为hello.mo文件,这样程序在运行时就能根据当前locale的设定来正确读取mo文件中的数据,从而显示相关语言的信息了。关于.mo文件的位置,在REDHAT中默认的目录是/usr/share/locale。将此步骤生成的mo文件复制到该的目录下,将locale设为zh_CN.GB2312,运行此程序,测试结果就变为中文了,如locale设为英文则显示仍为英文信息。
附录:源代码
/*hellogtk.c*/
#include<stdio.h>
#include<gtk/gtk.h>
#include <locale.h>
#include <libintl.h>
#define _(String) gettext(String)
#define N_(String) (String)
static GtkWidget *entry;
void PrintAndExit (GtkWidget *widget,GtkWidget *window)
{
char *str;
str=gtk_entry_get_text(GTK_ENTRY(entry));
if (str !=(char *) NULL)
printf( "%s/n", str);
}
void PrintByeAndExit (GtkWidget *widget,gpointer data)
{
printf( _("Goodbye,Gtk!/n" ));
gtk_exit(0);
}
int main( int argc,char *argv[ ] )
{
GtkWidget *window, *label,*vbox,*hbox,*button,*separator;
gtk_set_locale ();
bindtextdomain("hellogtk","/usr/share/locale/");
textdomain("hellogtk");
gtk_init(&argc,&argv);
window=gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_policy(GTK_WINDOW(window),FALSE,FALSE,FALSE);
gtk_signal_connect (GTK_OBJECT(window), "destroy",
GTK_SIGNAL_FUNC(PrintByeAndExit),NULL);
gtk_window_set_title (GTK_WINDOW(window), _("Hello Gtk!"));
gtk_container_border_width(GTK_CONTAINER(window),0);
vbox=gtk_vbox_new (FALSE,0);
gtk_container_add(GTK_CONTAINER(window),vbox);
hbox=gtk_hbox_new (FALSE,0);
gtk_box_pack_start (GTK_BOX (vbox),hbox, FALSE,FALSE,0);
label=gtk_label_new( _("Enter a message:") );
gtk_box_pack_start (GTK_BOX(hbox), label,FALSE,FALSE,0);
entry=gtk_entry_new ();
gtk_entry_set_text (GTK_ENTRY(entry),"");
gtk_editable_select_region(GTK_EDITABLE (entry),0,-1);
gtk_box_pack_start (GTK_BOX (hbox),entry,FALSE,FALSE,0);
separator=gtk_hseparator_new();
gtk_box_pack_start (GTK_BOX(vbox),separator,FALSE,FALSE,0);
button=gtk_button_new_with_label (_("Print"));
gtk_signal_connect_object(GTK_OBJECT(button),"clicked",
GTK_SIGNAL_FUNC(PrintAndExit),NULL);
gtk_box_pack_start (GTK_BOX(vbox),button,FALSE,FALSE,0);
GTK_WIDGET_SET_FLAGS (button,GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show_all (window);
gtk_main();
return(0);
}
第二种方法:使用资源文件(根据于明俭老师的文章《使用Gtk编写中文软件》)
GTK/GNOME 系列widgets中, 输入和显示已经是国际化了的. 所以用它们编写中文软件十分容易. 把西文软件改写成中文软件也十分容易.
· 在程序中包含 locale.h
· 在gtk_init前设置locale: gtk_set_locale()
· 接着调用gtk_rc_add_default_file("rcfilename"),其中rcfilename中含有缺省的fontset
· 如果不用资源文件, 则应对widget设置fontset
· 编译 gcc `gtk-config --cflags` entry.c -o entry `gtk-config --libs`
· 把文件gtkrc.zh 拷贝到当前目录下
在gtk的text组件中如果设置了font,则不能正常显示中文.解决的方法是把font释放(unref), 然后使用 gtk_fontset_load 字体集. 对于其它组件也是如此, 有的组件需要先拷贝一个 GtkStyle, 然后按上述方法解决.
下面的程序在显示中文时未使用中文平台,输入使用的是Chinput中的XIM协议支持,输出结果:
//file entry.c
#include <locale.h>
#include <gtk/gtk.h>
int main (int argc, char *argv[])
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *entry;
GtkWidget *text;
GtkWidget *button;
gtk_set_locale();
gtk_rc_add_default_file("./gtkrc.zh");
gtk_init (&argc, &argv);
/* 新建一个窗口 */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_usize( GTK_WIDGET (window), 200, 500);
gtk_window_set_title(GTK_WINDOW (window), "GTK Entry");
gtk_signal_connect(GTK_OBJECT (window), "delete_event",
(GtkSignalFunc) gtk_exit, NULL);
vbox = gtk_vbox_new (FALSE, 0);
gtk_container_add (GTK_CONTAINER (window), vbox);
gtk_widget_show (vbox);
entry = gtk_entry_new_with_max_length (60);
gtk_entry_select_region (GTK_ENTRY (entry),
0, GTK_ENTRY(entry)->text_length);
gtk_box_pack_start (GTK_BOX (vbox), entry, TRUE, TRUE, 0);
gtk_widget_show (entry);
text = gtk_text_new (NULL, NULL);
gtk_text_set_editable (GTK_TEXT (text), TRUE);
gtk_box_pack_start (GTK_BOX (vbox), text, TRUE, TRUE, 0);
gtk_widget_show(text);
button = gtk_button_new_with_label ("关闭窗口");
gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
GTK_SIGNAL_FUNC(gtk_exit),
GTK_OBJECT (window));
gtk_box_pack_start (GTK_BOX (vbox), button, TRUE, TRUE, 0);
GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
gtk_widget_grab_default (button);
gtk_widget_show (button);
gtk_widget_show(window);
gtk_main();
return(0);
}
>gcc entry.c -o entry `gtk-config --cflags --libs`
>./entry