现 在越来越多的华人开始用 Linux 了.也越来越多的华人开始写我门自己的 Linux 下面的应用程序了. 开发我门自己的程序,中文当然是一个必不可少的东西了. 这里就来说说 Linux 下面的中文程序的开发. 小弟才疏学浅,只是因为看到网络上面这方面的文章不是很多很全面.所以动手写了这些东西.如果有错误,还望大家多多包含,多多指正. QT QT 现在被越来越多的人所喜爱.也有了越来越多的人选择 QT 作为开发Xwindow 下面 GUI 环境的语言. 在 Linux 中,绚丽的 KDE 桌面环境就是用 QT 开发出来的. 现在来看看如何在 QT 下面处理中文. 本文中全部在 QT 3 的环境下运作.如果您用的是比较旧的 QT 版本, 请注意: Tips: 如果您的 Linux 系统中找不到 findtr3 那么请尝试找 findtr2 或者 findtr Tips: 如果您的 Linux 系统中找不到 msg2qm2 那么请尝试找 msg2qm Tips: 可以用 which findtr3 或者 whereis msg2qm2 来寻找您的系统 Tips: 如果您希望在自己的计算机中编译本文中的范例, 您需要安装 g++, qt, qt-devel, make 这些 套件. 下面我们来看一个简单的 QT 程序: 代码: /* chinese.h */ #include #include #include #include class Chinese: public QWidget { Q_OBJECT public: Chinese(); private: QLabel *label; QLineEdit *input; private slots: void display(); }; 这里我们简单的定义了一个基于 QWidget 的 class, 命名为 Chinese 然后我们定义了一个 Label *label 和一个 LineEdit input 并且定义一个 代码: void slot display() /* chinese.cpp */ #include "chinese.moc" #include Chinese::Chinese() { resize(200,100); label=new QLabel( "Input Line:", this); label->setGeometry(10,10,90,30); input=new QLineEdit(this); input->setGeometry(10, 40, 180, 30); input->setFocus(); connect(input, SIGNAL(returnPressed()), this, SLOT(display())); } void Chinese::display() { QCString string; string=input->text(); cout< } 在 .cpp 文件中. Chinese::Chinese() 中,我们只做了四件最简单的事情 1. 显示一个叫做 Input Line: 的 label 在 10,10 这个位置上. 大小为 90 30. 然后显示一个可以用来输入的 LineEdit 在 10, 40, 大小为 180, 30. 然后告诉程序,当程序打开的时侯,将 focus 用 setFocus() 放在 input ( QLineEdit )上面.也就是说,程序一打开,我们打 keyboard 就可以直接输入到 input 这个 QLineEdit 中. 然后我们告诉程序,当在 input 中接收到 Enter 键的时侯,去呼叫 display() 这个 slot Chinese::display() 中.我们有三个动作. 1. 定义一个 QCString 用作 QT 与 C++ 之间的沟通. string=input-text() 把我们输入在 input 中的 string 抓下来,放到 string 中.然后用 cout 把 string 显示在您的 X 终端模拟中. (rxvt, qterm, xter Konsole 之类的程序) 代码: /* main.cpp */ #include #include "chinese.h" main (int argc, char **argv) { QApplication a(argc, argv); Chinese w; a.setMainWidget (&w); w.show(); return a.exec(); } 这个就不多说了.是 chinese 的 main 程序.用来显示 chinese 的. 然后建立一个如下的 Makefile: 代码: INCL= -I$(QTDIR)/include -I/usr/include/kde CFLAGS= -pipe -O2 -fno-strength-reduce LFLAGS= -L$(QTDIR)/lib -L$(KDEDIR)/lib -L/usr/X11R6/lib LIBS= -lkdecore -lkdeui -lqt -lX11 -lXext -ldl CC=g++ MOC=moc chinese: chinese.moc chinese.o main.o $(CC) $(LFLAGS) -o chinese chinese.o main.o $(LIBS) chinese.moc: chinese.h $(MOC) chinese.h -o chinese.moc main.o: main.cpp chinese.o: chinese.cpp clean: rm -f *.o rm -f *.bak rm -f *.moc rm -f chinese .SUFFIXES: .cpp .h .cpp.o: $(CC) -c $(CFLAGS) $(INCL) -o $@ $< 通 过 make 指令.我们就可以 build 出一个可执行的文件 chinese 执行 ./chinese 可以看到我们的小程序. 我们在程序中那个可以输入的地方,随便打些东西进去(请输入英文)然后按 enter 键. 我们就会看到我们在程序中输入的那些东西会被显示在我们的 X 终端模拟中. 但是目前这个程序既不能显示中文,同样的也不能接受中文输入. 不相信的话,您可以尝试在那个输入文字的地方打入随便几个中文. 例如 "中文测试" 然后按 Enter 键.您会发现 X 终端模拟中显示的只有 "??" 之类的东西. 原因后面会讲到. 首先,我们第一部需要的是让我门的程序显示中文.相信大家一定都知道, QT 中已经帮我们做好了 i18n 了.只要去用就好. 首先我们需要在 chinese.h 的文件中加入: #include qtranslator.h 是给 QTranslator 用的 include 文件. 然后在 chinese.cpp 中 Chinese::Chinese 需要改成下面的样子: 代码: Chinese::Chinese() { resize(200,100); QTranslator translator(this); translator.load("chinese", "."); qApp->installTranslator(&translator); label=new QLabel(tr( "Input Line:"), this); label->setGeometry(10,10,90,30); input=new QLineEdit(this); input->setGeometry(10, 40, 180, 30); input->setFocus(); connect(input, SIGNAL(returnPressed()), this, SLOT(display())); } 首 先,我们定义了 QTranslator translator 在 this. 然后 translator.load 去载入 chinese.qm 这个文件.这里 .qm 这个全名称我们是不需要的. QT default 就会去找 .qm 了. 所以虽然我们的中文对应的翻译文件全名是 chinese.qm ,但是我们这里只需要打入 chinese 就好了. qApp->installlTranslator(&translator)就会帮我们把翻译成中文的信息, 加载我们的程序中. 同 时, label=new QLabel("Input Line:", this) 要改成下面这样 label=new QLabel(tr( "Input Line:"), this) 这里的 tr 是代表信息需要翻译 (translator)的意思. tr 也是给 findtr 来寻找哪里需要信息翻译的一个标志 (flag) 现在用 make 重新编译我们的程序. 编译完后,我们还需要做出 qm 文件来给 QTranslator 用. 首先,我们需要用到 findtr3 这个程序. findtr3 会帮我们找出程序中所有用到 tr 的地方.同时帮我们自动产生 po 文件. findtr3 chinese.cpp > chinese.po 现在用您最喜爱的文字编辑器(vim, emacs, joe or other)打开 chinese.po 这个文件,我们会看到: 代码: # This is a Qt message file in .po format. Each msgid starts with # a scope. This scope should *NOT* be translated - eg # from French to English, "Foo::Bar" would be translated to "Pub", # not "Foo::Pub". msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "POT-Creation-Date: 2002-06-22 20时09分00秒 EDT\n" "PO-Revision-Date: YYYY-MM-DD\n" "Last-Translator: FULLNAME \n" "Content-Type: text/plain; charset=iso-8859-1\n" #: chinese.cpp:15 msgid "Chinese::Input Line:" msgstr "" 这 里 findtr3 帮我们找到,在 chinese.cpp 这个程序中的第 11 行,有一处用到 tr 的地方. 而 tr 后面的内容是 Input Line: 还记得我们的 label 是怎么写的吗? label=new QLabel(tr( "Input Line:"), this); 没错, 这里找到的就是 "Input Line:" 这几个字. 下面我们开始翻译 po 文件了 我们真正需要动到的只有两个地方,就是: "Content-Type: text/plain; charset=iso-8859-1\n" 和下面的 msgstr "" 就足够了. 代码: #: chinese.cpp:15 msgid "Chinese::Input Line:" msgstr "" 首先我们需要设定我们是用哪种于言编码来翻译 po 的.同时 qt 也会用这种语言编码来显示我们所翻译的信息.所以我们需要改成: 代码: "Content-Type: text/plain; charset=big5\n" 或者: 代码: "Content-Type: text/plain; charset=gb2312\n" 其中 big5 是繁体中文所以用的编码, gb2312 (GBK) 则是简体中文所使用的. 接下来,我就需要更改 msgstr 了: msgid "Chinese::Input Line:" msgstr "请输入中文:" Tips: 注意,如果您是用 gb2312 简体来输入的那么 您需要在 charset 中选择 gb2312. 同样的, big5 繁体输入,就需要选择 charset=big5 您不能用同一种编码的输入法,同时去写两 个 po 文件. 也就是说,不能用 xcin 的繁 体输入,同时去翻译 gb2312 的 po. 也不 能用 chinput 的简体输入来翻译 big5 的 po. 如果您需要同时翻译繁体,简体的 po 那么建议您用您所熟习的语言环境翻译好 一份出来,然后用 big5<=>gb 的转码工具 转出另外一个编码的po文件来.同时记得更 改所转出来的文件中的 charset 当然,如果您愿意,也可以把 "PO-Revision-Date: YYYY-MM-DD\n" "Last-Translator: FULLNAME \n" 加入适当的信息 PO-Revision-Date: 加入您翻译的信息 Last-Translator: 加入您的个人信息以及 e-mail "PO-Revision-Date: 2002-06-22\n" "Last-Translator: Goldencat \n" 然后存盘,退出.先在我们还需要最后一步,就是把 chinese.po 文件转成 chinese.qm 的格式给程序来读.这时侯我们就用到了一只叫做 msg2qm2 的程序. msg2qm2 chinese.po chinese.qm 现在我们就算是完成了. 执行我们的文件 ./chinese 看看,那个 "Input Line:" 已经变成中文的 "请输入中文:" 了. 下一步,我们来解决在 QT 中输入中文,然后把中文显示出来的问题. Tips: QT 中的中文输入也很重要.写一个程序,不光是 表面上看起来信息都变成中文的,就叫做中文化 了.举一个最简单的例子:现在有一个中文的 MySql 数据库.我们的 QT 程序需要正确的输入 查询中文的数据.这就需要 QT 可以正确无误的 接受并且处理我们的中文输入才可以. 在 QT 中,我们有一个 QTextCodec 可以用. QTextCodec 就是专门来为我们处理不同编码的. 为了使用 QTextCodec 我们首先需要在 chinese.cpp 中,把 qtextcodec.h 给 include 进来. include 现在来看看我们的 void Chinese::display() 吧. 代码: void Chinese::display() { QString string; string=input->text(); QTextCodec *codec=QTextCodec::codecForName("big5"); QCString chinese_string=codec->fromUnicode(string); cout< } 这 里我们看到,同样的, 把 input 中我们输入的 string 扔给 string. 下面就用到了 QTextCodec 了.我们可以把 QTextCodec *codec=QTextCodec::codecForName("big5"); 写成两行,这样比较方便看: 代码: QTextCodec *codec; codec=QTextCodec::codecForName("big5"); 第一行是通过 QTextCodec 建立 codec 第二行呢,告诉 QT 我们的 codec 是用 big5 编码的. (简体中文就要用 gb2312) 最 后,我们通过 codec->formUnicode(string) 把 Unicode 转换成我们需要用的 big5 码. ( QT default 全部是用 Unicode,这也就是为什么开始的时侯,如果我们没有通过 QTextCodec 转码,看到的中文都是 ?? 了.因为 Unicode 的标准就是不认得的 code 一律用 ?? 来表示)最后我们定义一个 QCString chinese_string, 代码: QCString chinese_string=codec->fromUnicode(string); 而 chinese_string就是已经被 codec 转码过的 big5 code 的了. codec->fromUnicode(string) 这里是做转码的动作. 现在重新 make 所 build 出来的 chinese 就已经具备了最基本的中文程序的要求了.现在在输入中文到程序中,您就可以在 X 终端模拟中看到中文了. 那么这个程序已经具备了中文处理能力,为什么还被叫做最基本的呢中文处理呢?因为我们的程序目前并不会判断 locale, 而自动设定相应的编码.现在我们把这个 chinese 的程序作成一个相对完整的中文程序. QTextCodec 中还给我们提供了一个读取当然于言环境的 function 叫做 locale. QTextCodec::locale() 就会返回当前使用者的 locale. 现在让我们来看看一个相对完整的中文程序: Tips: 这个程序中对 locale 名称的定义 是按照 RedHat 7.3 中对中文 locale 的定义为标准的,也就是说: 繁体中文 : zh_TW.Big5 简体中文 : zh_CN.GB2312 代码: /* chinese.h */ #include #include #include #include #include class Chinese: public QWidget { Q_OBJECT public: Chinese(); private: QLabel *label; QLineEdit *input; QString locale; private slots: void display(); }; 我们这里加入了一个新的 QString locale, 用来做 locale 的判断. 代码: /* chinese.cpp */ #include "chinese.moc" #include #include Chinese::Chinese() { resize(200,100); QTranslator translator(this); locale=QTextCodec::locale(); translator.load("chinese."+locale, "."); qApp->installTranslator(&translator); label=new QLabel(tr( "Input Line:"), this); label->setGeometry(10,10,90,30); input=new QLineEdit(this); input->setGeometry(10, 40, 180, 30); input->setFocus(); connect(input, SIGNAL(returnPressed()), this, SLOT(display())); } void Chinese::display() { QString string; string=input->text(); QTextCodec *codec; if (locale == "zh_TW.Big5") codec=QTextCodec::codecForName("big5"); if (locale == "zh_CN.GB2312") codec=QTextCodec::codecForName("gb2312"); QCString encoded_string=codec->fromUnicode(string); cout< } 在 chinese.cpp 里面, Chinese::Chinese 我们加入 locale 的判断. 从而自动加载相应的 .qm 文件. locale=QTextCodec::locale() 就把 QTextCodec 返回的值,也就是当前使用的 locale 传给了 locale. (locale 是一个 QString)然后我们用 translator.load("chinese."+locale, "."); 实际上就是说 chinese.+当然 locale (zh_TW.Big5 或者 zh_CN.GB2312)也就是说,最后我们加载的 locale 是 chinese.zh_TW.Big5 或者是 chinese.zh_CN.GB2312. 这样只要对应不同的 locale 环境翻译不同的 .po 然后制作成基于 locale 名称的 qm, QT 就可以帮我们自动判断在哪个locale 要加载那个文件了. (chinese.zh_TW.Big5.qm 或者 chinese.zh_CN.GB2312.qm) Tips: QT 在载入 .qm 文件的时侯,如果该文件不存在.那么 就会用程序中的语言来显示.所以不需要为了程序是否 可以找到该 .qm 文件而担心.(不用去写 这方面的 error handle) 而 在 void Chinese::display() 中,我们也做一个自动的判断,用来判断使用者是在哪个中文环境中输入中文的. 如果是 zh_TW.Big5 我们就把转码设定为 big5, 如果是 GB2312 就设定为 gb2312. 而如果是其它的,就忽略不管了. 同时在修改一下我们的 Makefile 代码: INCL= -I$(QTDIR)/include -I/usr/include/kde CFLAGS= -pipe -O2 -fno-strength-reduce LFLAGS= -L$(QTDIR)/lib -L$(KDEDIR)/lib -L/usr/X11R6/lib LIBS= -lkdecore -lkdeui -lqt -lX11 -lXext -ldl CC=g++ MOC=moc chinese: chinese.moc chinese.o main.o $(CC) $(LFLAGS) -o chinese chinese.o main.o $(LIBS) chinese.moc: chinese.h $(MOC) chinese.h -o chinese.moc main.o: main.cpp chinese.o: chinese.cpp po: findtr3 chinese.cpp > chinese.zh_TW.Big5.po findtr3 chinese.cpp > chinese.zh_CN.GB2312.po qm: msg2qm2 chinese.zh_TW.Big5.po chinese.zh_TW.Big5.qm msg2qm2 chinese.zh_CN.GB2312.po chinese.zh_CN.GB2312.qm clean: rm -f *.o rm -f *.bak rm -f *.moc rm -f chinese .SUFFIXES: .cpp .h .cpp.o: $(CC) -c $(CFLAGS) $(INCL) -o $@ $< 在 Makefile 中加入 po 和 qm. 这样我们用 make po 就会产生 chinese.zh_TW.Big5.po 和 chinese.zh_CN.GB2312.po 了.把这两个 po 翻译好以后.用 make qm 就会做出 chinese.zh_TW.Big5.qm 和 chinese.zh_CN.GB2312.qm 这两个 qm 文件.现在试试看.在简体或者繁体的 X 终端模拟环境下.我们的程序会自动的显示相应的翻译信息.也会自动接受相应 locale 下面的中文输入法了. GTK+ 在 Linux 下面,还有一个常用的 GUI 环境开发语言.就是GTK+ 了. 大家都知道, gnome 这套桌面环境就是由 GTK+ 开发出来的. 现在我们来看看 GTK+ 如何处理中文. Tips: 这里我们以 GTK 1.x 为例. (因为 GTK 2.x 目前 还不算是非常的稳定) Tips: 如果您希望在自己的计算机中编译本文中的范例, 您需要安装 gcc, gtk+, gtk+-devel, make , gettext, 这些套件. 首先我们先来用 GTK 写一个跟前面 QT 中的那个程序功能完全一样的程序. 代码: /* chinese.c */ #include #include void display (GtkWidget *widget, GtkWidget * entry) { const gchar *entry_text; entry_text=gtk_entry_get_text( GTK_ENTRY (entry)); printf ("%s\n", entry_text); } void destroy(GtkWidget *widget, gpointer *data) { gtk_main_quit(); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *entry; GtkWidget *label; gtk_init(&argc, &argv); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy),NULL); gtk_container_border_width(GTK_CONTAINER(window),10); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show(vbox); label= gtk_label_new("Input Line"); gtk_box_pack_start(GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show(label); entry= gtk_entry_new(); gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(display), entry); gtk_box_pack_start(GTK_BOX (vbox), entry, TRUE, TRUE, 0); gtk_widget_show(entry); gtk_widget_show(window); gtk_main(); return 0; } 里 面的 void display() 就相当于前面 QT 中的 void Chinese::display() 是用来把我们输入的东西显示在您的 X 终端模拟上面的. 我们首先通过 gchar 来定义一个 entry_text, 然后用 gtk_entry_get_text(GTK_ENTRY())来把我们输入的东西抓出来,放到 entry_text 中去.再用 C 语言中的 printf 把它显示在我们的 X 终端模拟上面. void destory() 告诉程序,如果收到程序结束的信号,(例如你按了窗口中的那个小 X )那么就代表程序结束. 退出 gtk 的 main loop. 我 们的 main 程序中. 定先义了 window, vbox, entry, label 这己个物件.这里面, window, 就是我们看到的主窗口. vbox 是 gtk+ 中一种用来排列对象的东西. entry 是给我们输入用的(QT 中的 QLineEdit)lable 是作为显示一个信息而用的. (QT 中的 QLabel) gtk_init() 帮我们初始化 gtk. window=gtk_window_new 就通过 gtk_window_new 把 window 定一为一个新的窗口.也就是我们的主窗口了. GTK_WINDOW_TOPLEVEL 则告诉程序,我们的这个主窗口显示的时侯,是在最上面的. ( TOPLEVEL) gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy),NULL); 这一行,首先我们连接一个 gtk 的信号, 对象是在 window 上面. 信号的内容为 destroy, 当收到这个信号以后,用 GTK_SIGNAL_FUNC() 去呼叫 destroy() 这个 function . 传给 function 的值为 NULL. 也就是说,当我们的主窗口 window 接收到遗个 destroy 的信号的时侯, 去呼叫 destroy() 结束 gtk 程序. 这里的 destroy 信号就是代表你关闭主窗口的意思. 在 gtk 中,当你关闭了一个窗口, gtk 就会帮你送出一个 destroy 的信号. gtk_container_border_width(GTK_CONTAINER(window),10); 定义了我们的主窗口的 border(边缘)宽度为 10. vbox = gtk_vbox_new (FALSE, 0); 定义了一个新的 gtk_vbox 出来.用来排列我们放在主窗口中的对象. gtk_container_add (GTK_CONTAINER (window), vbox); 就把 vbox 通过 gtk_container_add 加入到我们的主窗口 window 中. gtk_widget_show(vbox); 通过呼叫 gtk_widget_show 在主窗口中显示我们的 vbox label= gtk_label_new("Input Line"); 通过 gtk_label_new 定义一个 label,而这个 label 显示的内容为 "Input Line" gtk_box_pack_start(GTK_BOX (vbox), label, TRUE, TRUE, 0); 是通过 gtk_box_pack_start 把 label 放到我们前面生成的 vbox 中. gtk_widget_show(label); 再次利用 gtk_widget_show, 这次是在 vbox 中显示我们新加入的 label. entry = gtk_entry_new(); 用 gtk_entry_new 定义了一个 entry. 这里就是指产生一个可以接受文字输入的对象,就好像 QT 中的 LineEdit 一样. gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(display), entry); 这里,我们连接一个 gtk 信号,信号作用于 entry,也就是我们前面产生的那个文字输入对象.当我程序接收到 "activate" 这个信号的时侯,就去呼叫 display() 这个 function, 同时把 entry 传给 display(). 这里的 activate 信号,就是当我们按下键盘的 enter 键时所产生的. gtk 当适用者按下 enter 键的时侯,就会送初一个 activate 的信号.所以当我们输入一些文字以后,按下 enter 键,这些文字就会被送到 display() 去处理了. gtk_box_pack_start(GTK_BOX (vbox), entry, TRUE, TRUE, 0); 再次用 gtk_box_pack_start 把对象 entry 加入到 vbox 中. gtk_widget_show(entry); 显示 vbox 中的对象 entry gtk_widget_show(window); gtk_main(); 最后我们显示我们的主窗口.并且进入 gtk 的 main loop. Tips: 这里我们利用 gtk_widget_show() 先显示了 window 中的 vbox, label, entry, 最后才去显示主窗口 window 是因为这样的话,当主窗口 window 显示出来的时侯. vbox, label, entry 已经比 window 先显示好了.这样我们看到的 就是一个整体的 window. 有主窗口,有 label 和 entry. vbox, label, entry 都是在主窗口显示以前就已经画好的了. 所以主窗口一出来,不用等待 label, entry 的出现. 如果先去显示 window, 再去显示 vbox, label, entry, 那么在比较慢的计算机上面(或者你的程序比较复杂的情况下) 你将会先看到一个空白的主窗口出现,然后再慢慢的画出 label 和 entry 来. 现在来看一下我们的 Makefile 代码: INCL= -I/usr/lib/glib/include/ -I/usr/include/gtk-1.2/gdk/ -I/usr/include/gtk-1.2/ \ -I/usr/include/glib-1.2/ LIBS= -L/usr/X11R6/lib LFLAGS= -lglib -lgdk -lgtk -lX11 -lXext -lm CC=gcc chinese: chinese.c $(CC) $(INCL) -o chinese chinese.c $(LIBS) $(LFLAGS) clean: rm -f chinese rm -f *.bak .SUFFIXES: .c .c.o: $(CC) -c $(CFLAGS) $(INCL) -o $@ $< 写 好 Makefile 以后. make 一下,就可以编译出 GTK+ 版的 chinese 了.执行以后, 我们可以发现,在可以输入文字的地方,直接输入中文,就可以在 X 终端模拟中正确的显示出来中文. 所以我们需要的,就只有把接口中文化一下就好了. 中文化 gtk+ 程序的时侯,会比 QT 稍稍麻烦些. 代码: #include #include #include #include #define PACKAGE "chinese" #define LOCALEDIR "/home/goldencat/program/gtk/chinese/final" #define _(STRING) gettext(STRING) void display(GtkWidget *widget, GtkWidget * entry) { const gchar *entry_text; entry_text=gtk_entry_get_text( GTK_ENTRY (entry)); printf ("%s\n", entry_text); } void destroy(GtkWidget *widget, gpointer *data) { gtk_main_quit(); } int main(int argc, char *argv[]) { GtkWidget *window; GtkWidget *vbox; GtkWidget *entry; GtkWidget *label; gtk_set_locale(); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); gtk_init(&argc, &argv); window=gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_signal_connect(GTK_OBJECT(window), "destroy", GTK_SIGNAL_FUNC(destroy),NULL); gtk_container_border_width(GTK_CONTAINER(window),10); vbox = gtk_vbox_new (FALSE, 0); gtk_container_add (GTK_CONTAINER (window), vbox); gtk_widget_show(vbox); label= gtk_label_new(_("Input Line")); gtk_box_pack_start(GTK_BOX (vbox), label, TRUE, TRUE, 0); gtk_widget_show(label); entry= gtk_entry_new(); gtk_signal_connect(GTK_OBJECT(entry), "activate", GTK_SIGNAL_FUNC(display), entry); gtk_box_pack_start(GTK_BOX (vbox), entry, TRUE, TRUE, 0); gtk_widget_show(entry); gtk_widget_show(window); gtk_main(); return 0; } 首 先我们需要 locale.h 和 libintl.h 然后还要定义 PACKAGE, LOCALEDIR 这里的 PACKAGE 就是我们翻译后的 mo 文件的名称. 这里把它定义为 chinese 因为我们的程序就叫做 chinese, GTK+ 会在固定的地方寻找 mo 文件.在 RedHat 7.3 中,会在 /usr/share/locale/你的locale/LC_MESSAGES 下面寻找 mo 文件. 对于中文来说,也就是 /usr/share/locale/ 下面的 zh_TW zh_TW.Big5 zh_CN zh_CN.GB2312 这几个目录中的 LC_MESSAGES 下面.去寻找 mo 文件. 这里我们去定义 LOCALEDIR 就是告诉 gtk+ 我们希望 gtk+ 到哪里去寻找 mo 文件. /home/goldencat/program/gtk/chinese/final 就是 chinese.c 的位置.也就是我们的当前工作目录.这样 gtk+ 就不会再去 /usr/share/locale/ 下面找相应语言环境中的 LC_MESSAGES 中寻找 mo 文件了. 而是在您 LOCALEDIR 中定义的位置.(配合 bindtextdomain 使用) 而 后面的 #define _(STRING) gettext(STRING) 只是说把 gettext(STRING)换成 _(STRING) gettext 就好像前面 QT 中的那个 tr 一样.在产生 po 文件的时侯,就是根据 gettext 来决定哪些信息是需要翻译的.只不过每个需要翻译的信息都把 ("English String") 改成 (gettext("English String")) 未免有些麻烦.所以 GTK+ 中,大家都把 gettext(STRING) 换成 _(STRING), 这样我们就只需要 (_("English String") 就可以了. Tips: 如果您在您的计算机中编译这些东西,请记得把 #define LOCALEDIR "/home/goldencat/program/gtk/chinese/final" 改换成您自己的工作目录 在 gtk_init() 之前,我们需要告诉 gtk 我们有翻译的信息.所以要有下面三个动作: gtk_set_locale(); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); get_set_locale() 告诉 gtk 去找我们现在用的 locale (QT 中的 TextCodec::locale())这样 gtk+ 就会自动判断出当前 locale 的环境,然后去相应的环境下面找 mo 文件. bindtextdomain() 则是告诉 gtk 去哪里找 mo 文件. 这里我们要它去我们定义的 LOCALEDIR 下面找 PACKAGE (chinese) textdomain() 就是载入翻译的信息啦. 最后就是把 label= gtk_label_new("Input Line"); 改成 label= gtk_label_new(_("Input Line")); 这样 xgettext 就可以找到需要翻译的信息了. 现在我们就算是完成了程序这边对中文化的支持了. gtk+ 需要用 xgettext 来产生 po 文件的.所以我们用: xgettext -k_ chinese.c -o chinese.po 这里的 -k_ 就是说 keywork 是 _ ,也就是说 xgettext 会去找程序中的 _(STRING) 出来. 现在打开 chinese.po 看看: 代码: # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2002-06-23 17:44-0400\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #: chinese.c:38 msgid "Input Line" msgstr "" 跟翻译 QT 的 po 一样,我们真正需要动到的只有 charset 和 msgstr " " 而已.当然,您也可以加入相应的翻译信息, PO-Revision-Date: 翻译时间 "Last-Translator: 翻译人 翻译人_E-Mail地址 Language-Team: 翻译团队 翻译团队_E-Mail_地址 下面是翻译好的 po 代码: # SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "POT-Creation-Date: 2002-06-23 17:44-0400\n" "PO-Revision-Date: 2002-06-23 14:45-0400\n" "Last-Translator: Goldencat &l;ruili@worldnet.att.net>\n" "Language-Team: LANGUAGE &l;ruili@worldnet.att.net>\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=Big5\n" "Content-Transfer-Encoding: 8bit\n" #: chinese.c:38 msgid "Input Line" msgstr "中文输入" 存档以后.我们用: msgfmt -o chinese.mo chinese.po 生成 mo 文件. 跟 QT 不同的是, GTK+ 不是通过判断 mo 名子来载入不同的的 mo 的. 在 GTK+ 下面.任何 locale (语言环境)的 mo 名子都叫做 chinese.mo 那么 GTK+ 是如何分辨不同的 locale 需要加载相对语言的 mo 呢? GTK+ 是通过把不同的 mo 放在不同的目录下,然后通过判断目录名称来找到相应的 mo 文件的. 所以存放 GTK+ mo 文件的目录名,需要跟相应的 locale 一致. GTK+ 就会在这个目录下的 LC_MESSAGES 中找到所需要的 mo 文件了. 所以我们首先需要在当前目录下做出相应的存放 mo 文件的目录. $mkdir zh_TW $mkdir zh_TW/LC_MESSAGES $cp -r zh_TW zh_TW.Big5 $cp -r zh_TW zh_CN $cp -r zh_TW zh_CN.GB2312 这样我们就有了中文所需要的四个最基本的目录了. 现在我们把 chinese.mo 放到相应的目录下面 $cp chinese.mo zh_TW/LC_MESSAGES $cp chinese.mo zh_TW.Big5/LC_MESSAGES 然后在做一份 GB2312 的 mo 放在 zh_CN 和 zh_CN.GB2312 实 际上,在 RedHat7.3 中, export LANG=zh_TW.Big5 情况下(LC_MESSAGES=zh_TW.Big5)GTK+ 会在 zh_TW/LC_MESSAGES 下面寻找 mo 文件. 而 export LANG=zh_CN.GB2312 的情况下(LC_MESSAGES=zh_CN.GB2312)GTK+ 则是在 zh_CN.GB2312/ LC_MESSAGES 下面寻找 mo 文件. 现在试试在不同的 locale 运行一下 ./chinese 您会看到, 程序已经被中文化了.那个 Input Line 已经换成中文的 "中文输入" 了. 最后,我们再来改一下我们的 Makefile, 帮助我们产生 po, mo 并且放到相应的语言目录下. 代码: INCL= -I/usr/lib/glib/include/ -I/usr/include/gtk-1.2/gdk/ -I/usr/include/gtk-1.2/ \ -I/usr/include/glib-1.2/ LIBS= -L/usr/X11R6/lib LFLAGS= -lglib -lgdk -lgtk -lX11 -lXext -lm CC=gcc chinese: chinese.c $(CC) $(INCL) -o chinese chinese.c $(LIBS) $(LFLAGS) clean: rm -f chinese rm -f *.bak po: xgettext -k_ chinese.c -o chinese_big5.po xgettext -k_ chinese.c -o chinese_gb2312.po mo: msgfmt -o chinese_big5.mo chinese_big5.po msgfmt -o chinese_gb2312.mo chinese_gb2312.po mo_install: cp chinese_big5.mo zh_TW/LC_MESSAGES cp chinese_big5.mo zh_TW.Big5/LC_MESSAGES cp chinese_gb2312.mo zh_CN/LC_MESSAGES cp chinese_gb2312.mo zh_CN.GB2312/LC_MESSAGES .SUFFIXES: .c .c.o: $(CC) -c $(CFLAGS) $(INCL) -o $@ $< C/C++ 其是在 C/C++ 的一般程序中,也是可以中文化的. 在 C/C++ 程序中.中文化的步骤跟 GTK+ 己乎是一样的. 这里简单介绍一下: 代码: /* chinese.c */ #include main () { printf(_("This is a test.\n")); } 现在我们来中文化这只程序: 首先我们需要 libintl.h 和 locale.h 再就是 #define PACKAGE "chinese" #define _(STRING) gettext(STRING) 然后用 setlocale() 和 textdomain() 来完成中文化 代码: #include #include #include #define _(STRING) gettext(STRING) #define PACKAGE "chinese" main () { setlocale(LC_MESSAGES, ""); textdomain(PACKAGE); printf(_("This is English.\n")); } 然后跟 GTK+ 中的制作 mo 的方法一样.用 xgettext 制作出 po 文件. 翻译好以后,用 msgfmt 制作成 mo 文件. 把这个 mo 文件 copy 到 /usr/locale/你的_locale/LC_MESSAGES下面. textdoamin 会去那里找 mo 文件.现在再重新跑您的程序. "This is English" 就变成您改的中文了. |
联系客服
微信登录中...
请勿关闭此页面