原文地址:Advanced GTK Techniques。
這篇教程中你將學會:
- 使用
Gettext
完成源代碼中的翻譯工作辉懒;
- 使用
Intltool
完成其它文件的翻譯工作拓售。
這篇文章是《如何開始一個真正的 GTK 項目》的一部分桌硫,如果你不想回看之前的章節(jié)俺叭,可以直接下載教學示例程序
app-skeleton3
发魄。你也可以從頭開始铃拇。
這是我們在開始正式的代碼工作前又一個基礎準備工作钞瀑,這將實現(xiàn)程序在不同語言環(huán)境下的本地化。你可能覺得翻譯工作一般都是在應用成型后才展開慷荔,但是在編寫程序時同步開始翻譯往往更利于保持掌控翻譯的質量雕什。
你是否需要為了這項工作學習 30 門外語呢?當然不用显晶。在真實的場合中贷岸,人們用英語編寫程序(準確地說是 C locale
),然后依賴一個名為 gettext
的工具將所有程序中顯示給用戶的詞句歸納到一個 翻譯模板
或一個 .pot
文件中磷雇。
之后要做的就是招募一些翻譯人員到你的項目中來(這才是最困難的部分)偿警,讓他們翻譯模板中的所有詞句,生成一個 .po
文件唯笙。通常螟蒸,你需要給你的翻譯人員向源代碼倉庫 commit
的權限盒使,這樣他們就能提交 .po
文件。之后七嫌,make install
命令會負責為用戶系統(tǒng)選擇正確的翻譯少办。
一個程序開始運行之后,它會查詢 LANG
系統(tǒng)變量抄瑟。如果程序自身存在一個與 LANG
對應的翻譯文件就會調用它凡泣,如果不存在就顯示英語。另外皮假,如果翻譯文件沒有實現(xiàn)完整的翻譯工作鞋拟,程序會調用所有已經翻譯的內容,而未被翻譯的依舊使用英語惹资。這使得翻譯工作可以逐步展開贺纲,只要翻譯者貢獻盡可能多的翻譯即可;并且褪测,如果你在程序新的版本中添加了一些新詞句猴誊,而翻譯人員度假去了,你也不用擔心整個工程前功盡棄侮措。
使用 gettext
首先懈叹,將我們現(xiàn)在的目錄拷貝一份到 app-skeleton4
,或者直接重命名分扎,然后修改版本號澄成。為了將 gettext
添加到我們的編譯系統(tǒng)中,我們需要在 configure.ac
的“工具箱”部分添加如下內容:
app-skeleton4/configure.ac
AM_GNU_GETTEXT([external])
AM_GNU_GETTEXT_VERSION([0.18.1])
此外畏吓,在“輸出”部分的 AC_CONFIG_FILES
中添加一行:po/Makefile.in
墨状,在 Makefile.am
的 SUBDIRS
中將 po
添加進去(po
目錄是 gettext
文件默認存儲的地方。
將
Makefile.in
而非Makefile
放入AC_CONFIG_FILES
中可能有些令人困惑菲饼。這是因為gettext
生成的文件名為Makefile.in.in
肾砂,我們需要把它轉換為Makefile.in
。隨后宏悦,由AM_GNU_GETTEXT
宏生成的代碼會自動將它轉換為Makefile
镐确。當然,我們希望這種運行邏輯以后盡量少點出現(xiàn)饼煞,否則我們就可能會看到類似于Makefile.in.in.in.in
的文件了辫塌。
我們現(xiàn)在需要運行 autoreconf -i
來安裝 gettext
相關文件。在執(zhí)行 configure
之前派哲,我們還需要在 po
文件夾中添加一些文件臼氨。第一個是 POTFILES.in
,這個文件列出了 gettext
需要翻譯的所有文件芭届;第二個是 LINGUAS
储矩,它列出了所有可用的翻譯語言感耙,元素之間用空格分隔。現(xiàn)在我們先創(chuàng)建這樣兩個空文件持隧,隨后我們再添加內容即硼。
最后一個需要添加的文件名為 Makevars
。這個文件包含了一些可由用戶自定義的變量屡拨,這些變量將被應用于生成 po
目錄中的 Makefile
只酥。剛才運行了 autoreconf
之后,目錄中應該已經有了一個模板文件 Makevars.template
呀狼。我們用它拷貝出一個 Makevars
文件并修改少量內容:我把 COPYRIGHT_HOLDER
改成了自己的名字裂允,MSGID_BUGS_ADDRESS
改成了 $(PACKAGE_BUGREPORT)
,這樣翻譯人員就將會把 bug 匯報到我的郵箱中(再一個大型項目中哥艇,你可能需要設立不同的郵箱)绝编。
Autoconf
將PACKAGE_BUGREPORT
變量定義為我們在configure.ac
的AC_INIT
中設定的郵箱。
接下來貌踏,我們需要標記 hello-world.c
中所有需要翻譯的界面字符串十饥。首先在文件開頭加入一行:
// app-skeleton4/src/hello-world.c
#include <glib/gi18n.h>
這是 GLib
中專門定義 gettext
的庫(i18n
表示 “internationalization”,因為在首字母 “i” 和末字母 “n” 之間有 18 個字母)祖乳。這個頭文件中定義了函數(shù) _()
用于處理翻譯字符串(如果 gettext
沒有啟用逗堵,_()
就不會做任何事;程序名設計成 _
是為了盡可能減少對讀寫代碼造成的影響)眷昆。
隨后蜒秤,我們在 main()
函數(shù)開頭添加下面這段代碼,在第 40 行輸入:
// app-skeleton4/src/hello-world.c
/* Set up internationalization */
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
這段代碼使得程序能夠讀取翻譯文件的信息隙赁。最后垦藏,還要在 Makefile.am
中告訴程序去哪里尋找這些翻譯文件:
# app-skeleton4/src/Makefile.am
AM_CPPFLAGS = -DLOCALEDIR=\""$(localedir)"\"
目前我們有四個地方需要被標記成翻譯位置:一個在 print_hello()
中梆暖,一個在 on_delete_event()
中伞访,一個在 main()
的 gtk_window_set_title()
的參處中,還有一個在 main()
的 gtk_button_new_with_label()
中轰驳。我們用 _()
把這些字符串括起來厚掷,比如 "Hello World"
就變成了 _("Hello World")
。
注意并不是所有的字符都需要翻譯级解!例如在函數(shù)
g_signal_connect()
中的信號名和gtk_window_set_icon_name()
中的圖標名就不需要任何處理冒黑。程序內部調用的字符串均不需要翻譯,只有程序界面顯示的字符串才需要勤哗。如果你將"destroy"
信號翻譯成德語抡爹,那程序就崩潰了,畢竟它可不知道 “zerst?ren” 信號是個什么鬼芒划。
完成上述工作后冬竟,我們需要在 POTFILES.in
中添加需要被翻譯的文件:
# app-skeleton4/po/POTFILES.in
src/hello-world.c
如果我們現(xiàn)在在 po
目錄下運行 make update-po
欧穴,就會產生一個名為 app-skeleton.pot
的文件。這是翻譯人員的模板文件泵殴。
翻譯程序
我們試著將程序翻譯成其它的語言來測試上面的工作涮帘。我將以荷蘭語(語言代碼 nl
)做介紹。
首先要做的是創(chuàng)建一個翻譯語言的 .po
文件笑诅,在 po
目錄下運行:
msginit -l nl
這將會基于之前的翻譯模板生成一個名為 nl.po
文件调缨。你可以用你喜歡的編輯器編輯它,在更大型的項目中吆你,你可能會需要一個專業(yè)的翻譯文件編輯器弦叶,比如 Virtaal 和 Poedit。你可以自己翻譯早处,也可以直接用我的:
#: src/hello-world.c:11
msgid "Hello World\n"
msgstr "Hallo Wereld\n"
#: src/hello-world.c:27
msgid "delete event occurred\n"
msgstr "delete event heeft plaatsgevonden\n"
#: src/hello-world.c:52
msgid "Hello"
msgstr "Hallo"
#: src/hello-world.c:76
msgid "Hello World"
msgstr "Hallo Wereld"
翻譯完成后湾蔓,將語言代碼添加到 LINGUAS
中:
nl
隨后在 po
目錄下再一次運行 make update-po
。這條命令很重要砌梆,每次有翻譯人員上傳了新的文件時默责,你都應該運行一次,否則文件就不會被應用咸包。隨后我們可以運行 make install
來安裝桃序。
你現(xiàn)在應該已經可以運行荷蘭語的程序了(或者其它你選擇的語言)。如果你的系統(tǒng)區(qū)域設定為荷蘭烂瘫,直接運行程序就能看到效果媒熊。如果是其它的區(qū)域則需要在運行程序時單獨設定 LANG
環(huán)境變量(在終端中輸入 LANG=nl app-skeleton
)。
譯者注:常用的語言代碼有:
zh_CN
:中文(中國大陸)
zh_HK
:中文(中國香港)
zh_TW
:中文(中國臺灣)
zh_SG
:中文(新加坡)en_US
:英語(美國)
en_UK
:英語(英國)
en_CA
:英語(加拿大)
en_HK
:英語(中國香港)
更多語言代碼請參閱 Language Codes 和 Locale Helper坟比。
翻譯非代碼文件
gettext
有一個缺陷:它只對代碼文件有效芦鳍,可以通過調用 gettext()
讀取翻譯。而類似于 xml
葛账、桌面文件等數(shù)據(jù)文件則愛莫能助柠衅。這便是引入 intltool
的原因。它將這些文件中需要翻譯的字符串也添加到了翻譯模板中籍琳。在這些詞句被翻譯后菲宴,它還會將這些翻譯整合回數(shù)據(jù)文件中。我們現(xiàn)在將 intltool
添加到我們的程序中來翻譯桌面文件趋急。
首先喝峦,intltool
有它自己的引導程序——intltoolize
,它必須在 autoreconf
之后才能運行呜达。使用了 intltool
之后我們的引導過程就不能再只用一句 autoreconf -i
敷衍了事了谣蠢,我們需要制作一個引導腳本。在項目根目錄下,我們創(chuàng)建一個 autogen.sh
文件眉踱,賦予它可執(zhí)行權限勋颖,寫入:
# app-skeleton4/autogen.sh
#!/bin/bash
echo "Regenerating autotools files"
autoreconf --force --install || exit 1
echo "Setting up Intltool"
intltoolize --copy --force --automake || exit 1
我們需要用到 --force
選項,因為 autoreconf
和 intltoolize
會覆蓋掉彼此的 po/Makefile.in.in
文件勋锤。寫好之后我們就可以運行一次引導腳本饭玲。
隨后,在 configure.ac
的 “工具箱” 部分添加如下內容:
# app-skeleton4/configure.ac
IT_PROG_INTLTOOL([0.40])
在 “庫” 部分叁执,我們添加一個新的 “變量” 部分茄厘。為了能夠正常使用 intltool
,我們需要定義一個名為 GETTEXT_PACKAGE
的變量谈宛,它指向程序在 gettext
中被定義的名字次哈。
# app-skeleton4/configure.ac
# Needed by intltool
GETTEXT_PACKAGE=${PACKAGE_TARNAME}
AC_SUBST([GETTEXT_PACKAGE])
AC_SUBST
宏會確保所有 Makefile
中的 @GETTEXT_PACKAGE@
變量都會被替換成變量指代的實際內容。現(xiàn)在再運行一次 make
吆录。
接下來窑滞,我們需要告訴 intltool
哪些數(shù)據(jù)文件包含了需要被翻譯的語句。慶幸的是恢筝,有一個叫作 intltool-prepare
的腳本會自動幫我們完成這些工作哀卫。在項目根目錄下運行 intltool-prepare
,你會注意到它自動將桌面文件添加到了 po/POTFILES
中并且修改了 Makefile.am
中桌面文件的安裝規(guī)則撬槽。
它還新建了一個文件此改,app-skeleton.desktop.in
。如果你使用了代碼控制系統(tǒng)的話侄柔,最好遵循它給出的建議從倉庫中移除你的 app-skeleton.desktop
文件 —— 它現(xiàn)在可以由編譯系統(tǒng)根據(jù) app-skeleton.desktop.in
自動創(chuàng)建出來共啃。從現(xiàn)在起,如果你想編輯桌面文件暂题,請在 app-skeleton.desktop.in
中做修改移剪。
如果需要翻譯桌面文件,我們需要在 po
目錄下再運行一次 make update-po
命令薪者。你將會看到 .pot
和 .po
文件中新添加了兩句未翻譯的語句纵苛。你可以自行翻譯它們,也可以用我的翻譯:
#: ../app-skeleton.desktop.in.h:1
msgid "A sample application from the Advanced GTK+ Techniques tutorial"
msgstr "Een voorbeeldapplicatie uit de cursus Gevorderde GTK+ Technieken"
#: ../app-skeleton.desktop.in.h:2
msgid "App Skeleton"
msgstr "Skeletapplicatie"
接著啸胧,再運行一次 make update-po
赶站,然后是 make
幔虏。你可以看到在生成的 app-skeleton.desktop
中你的翻譯已經被整合進去了纺念。如果你現(xiàn)在運行 make install
,翻譯文件就會被安裝想括。
以上就是全部編譯基礎構建的內容∠萜祝現(xiàn)在我們可以正式開始寫代碼了。:-)
文章許可協(xié)議:Attribution-NonCommercial-ShareAlike 3.0 Unported