当前位置:Linux教程 - Linux - Chinese Programming

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 来自: