在gtk+程序中顯示中文說明
(一)應用程序中該做的事情(確定所用mo文件的位置)
首先用函數textdomain設置應用程序的中文信息(mo文件)所在的位置,姑且稱為“域”
如:
setlocale( LC_ALL, "zh_CN.GB2312" );
textdomain( "test" ); // 設置代表該應用程序中文信息的名稱,默認的“域”名為message
bindtextdomain ( "test", "/usr/local/share/locale"); // 設置信息所在的目錄,默認情況下該目錄值被設置為/usr/share/locale
這樣gettext函數(下面將提到)就會在目錄/usr/local/share/locale/zh_CN.GB2312/LC_MESSAGES中去中文信息文件test.mo。
其中***代表程序的locale環境變量對應語言變量LC_MESSAGES的值
程序中,每一個將被顯示成中文的字符串都必須經過gettext函數處理。
如:
gtk_button_new_with_label( "ok" );
如果要將該按鈕的標簽名顯示成中文,那么必須將這條語句改成 gtk_button_new_with_label( (void*)gettext( "ok" ) );
gettext工作原理
char *str = "string";
gettext( str );
1. 根據locale和textdomain的設置尋找對應mo文件;
if 沒找到 then 返回str; else goto 2;
2. 以str串為id找相應的翻譯串;
if 沒找到 then 返回str; else goto 3;
3. 把翻譯串從 編碼1 轉化成 編碼2;
if 轉換成功 then 返回經編碼轉換后的翻譯串; else 返回翻譯串(或其他?);
編碼1:由mo文件的屬性charset決定
編碼2:由locale決定,如:zh_CN.GB2312決定編碼2為GB2312編碼
(二)mo文件的制作
1. 根據源程序生成po文件,如:xgettext --keyword="gettext" try.c -o test.po
例:設xgettext程序從文件中找到gettext("pepole"),則在po文件中有如下內容:
msgid "people"
msgstr ""
2. 在po文件中,根據msgid部分填寫的msgstr部分,
例:
msgid "people"
msgstr "人民"
注意,如下設置po文件的相應內容:
"Content-Type: text/plain; charset=CHARSET"
"Content-Transfer-Encoding: 8bit"
此處charset為msgstr部分的編碼格式,
由于gtk+的文本輸入都是UTF-8格式,所以此處用utf-8編碼格式編輯po文件(填入msgstr部分的簡體中文),并令charset=CHARSET,這樣msgstr部分的簡體中文被保存為UTF-8編碼格式。這樣,如果gettext從與該文件對應的mo文件中取出的信息就是簡體中文的UTF-8編碼,注意:此處charset=CHARSET則gettext的第三步沒有執行,所以返回的是utf-8串(因為文本輸入時的編碼格式為utf-8)
Content-Transfer-Encoding暫時將它寫做8bit
注:如果此處charset=有效編碼,那么由gettext返回的中文編碼格式由locale決定,此時還需將gettext的返回中文串轉成utf-8格式,這樣就進行了兩次編碼轉換;而如果charset=無效編碼,則gettext直接返回中文utf-8串,而沒必要進行編碼轉換,效率更高。
3. 生成mo文件,msgfmt test.po -o test.mo
4. 拷貝mo文件到程序中設置的相應位置/usr/local/share/locale/***/LC_MESSAGES
(三)環境設置
設置好gtk+所用的中文字體,如果所用字體是GB2312編碼,那么可以想象gtk是這樣工作(實際不是這么處理的,但效果是一樣的):將輸入的UTF-8編碼轉化成GB2312碼,然后告訴X服務器用 該碼 和 該字體文件 顯示相應字行.
(四)例子
// try.c文件內容
#include
#include
#define _(str) (void*)gettext(str)
gint delete_event( GtkWidget *win, GdkEvent *e, gpointer arg )
{
g_print( "quite application!" );
return FALSE;
}
void destroy( GtkWidget *win, gpointer arg )
{
g_print( "destroy window!" );
gtk_main_quit();
}
int main( int argc, char *argv[] )
{
GtkWidget *window,*button;
unsigned char *s;
textdomain( "testmo" );
printf( "%s", bindtextdomain( "testmo", "/usr/share/locale" ) );
gtk_init( &argc, &argv );
window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
g_signal_connect( G_OBJECT(window), "delete_event", G_CALLBACK(delete_event), NULL );
g_signal_connect( G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL );
button = gtk_button_new_with_label( _("ok") );
gtk_container_add( GTK_CONTAINER( window ), button );
gtk_widget_show( button );
gtk_widget_show( window );
gtk_main();
return 0;
}
// 生成po文件,編碼方式utf-8
// gcc -E try.c -o temp.c; xgettext temp.c -o test.po; rm -f temp.c
// 或者 xgettext --keyword=_ try.c -o test.po更方便,默認的keyword是gettext,此處增加keyword _
// 翻譯po文件(以utf-8編碼格式填寫),運行msgfmt test.po test.mo
// charset=無效編碼名,即:CHARSET為無效編碼名??捎谐绦騣conv --list查看支持的編碼名
// 拷貝test.mo文件到/usr/share/locale/zh_CN.GB2312/LC_MESSAGES目錄下
// 已翻譯的po文件的內容
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Free Software Foundation, Inc.
# FIRST AUTHOR
#
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION"
"POT-Creation-Date: 2005-03-07 20:31-0500"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE"
"Last-Translator: FULL NAME
"Language-Team: LANGUAGE
"MIME-Version: 1.0"
"Content-Type: text/plain; charset=CHARSET"
"Content-Transfer-Encoding: 8bit"
#: try.c:31
msgid "ok"
msgstr "確定"
// 編譯程序,設置locale,運行程序,正常情況應該有中文顯示
$gcc -o app try.c
$export LC_ALL=zh_CN.GB2312
$./app