Chinese Programming
Chinese Programming
Goldencat [email protected]
现在越来越多的华人开始用 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 执行 http://www.study-area.org/gb/?http://www.study-area.org/tips/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=gb2312\n"
或者:
"Content-Type: text/plain; charset=gb2312\n"
其中 big5 是繁体中文所以用的编码, gb2312 (GBK) 则是简体中文所 使用的.
接下来,我就需要更改 msgstr 了:
msgid "Chinese::Input Line:"
msgstr "请输入中文:"
* Tips: 注意,如果您是用 gb2312 简体来输入的那麽 您需要在 charset 中选择 gb2312. 同样的, big5 繁体输入,就需要选择 charset=gb2312 您不能用同一种编码的输入法,同时去写两 个 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 <[email protected]>\n"
然後存档,退出.先在我们还需要最後一步,就是把 chinese.po 文件转成 chinese.qm 的格式给程式来读.这时侯我们就用到了 一苹叫做 msg2qm2 的程式.
msg2qm2 chinese.po chinese.qm
现在我们就算是完成了. 执行我们的文件 http://www.study-area.org/gb/?http://www.study-area.org/tips/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 PACKAGES 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 <[email protected]>\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 PACKAGES 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;[email protected]>\n"
"Language-Team: LANGUAGE &l;[email protected]>\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 运行一下 http://www.study-area.org/gb/?http://www.study-area.org/tips/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" 就变成您改的中文了.
http://maowei.3322.net发布人:maowei 来自: