國際化程序?qū)崿F(xiàn)步驟:
國際化(Internationalization,簡寫為I18N)是指軟件在設(shè)計(jì)結(jié)構(gòu)和機(jī)制上支持多語言的擴(kuò)展特性,其功能和代碼設(shè)計(jì)不針對某一特定語言和地域。
一:基本實(shí)現(xiàn)步驟
1 編輯源程序
用 vim編輯器編輯源程序。注意:要順利實(shí)現(xiàn)程序國際化,源程序應(yīng)當(dāng)包含相應(yīng)的標(biāo)準(zhǔn)頭文件,主函數(shù)中要調(diào)用相關(guān)的函數(shù),如庫libintl,函數(shù)setlocale(),bindtextdomain(),textdomain()等。
如下程序?yàn)楹唵蔚氖纠?/p>
#include<stdio.h>
>#include<locale.h>
>#include<libintl.h>
>#include<stdlib.h>
#define _(String) gettext (String)
int main(int argc,char**argv)
{
setlocale(LC_ALL,"");
bindtextdomain("gettext",".");
textdomain("gettext");
printf("%s\n",_("one world,one dream!"));
return 0;
}
2 編譯源程序
用gcc命令對源程序進(jìn)行編譯,生成可執(zhí)行文件。執(zhí)行后,可以顯示源程序中的輸入函數(shù)的字符。命令示例:
gcc -o gettext gettext.c
3 創(chuàng)建翻譯文件模板pot
用xggetxt命令提取源程序中的翻譯信息,創(chuàng)建翻譯文件模板pot(Portable Object Template可移植的對象模板)文件。命令示例:
xgettext –keyword=_ gettext.c -o gettext.pot
4 由pot生成可移植對象po文件
每一種語言都有其可移植的對象文件,即po(Portable Object )文件。該文件是由一對對的msgid和msgstr組成的,其中,msgid表示從程序中提取的信息,msgstr表示譯文。命令示例:
cp gettext.pot gettext.po
5 編輯po文件中的翻譯字符,修改字符的編碼
用gedit或vim編輯器編輯po文件,翻譯相關(guān)信息,并將charset改為UTF-8,否則不可編碼。完成后,保存文件。注意:如果要實(shí)現(xiàn)多種語言,此時應(yīng)復(fù)制多分po文件,并分別進(jìn)行翻譯。命令示例:
gedit gettext.po或vim gettext.po
6 由po文件生成二進(jìn)制mo文件
用msgfmt命令將po文件轉(zhuǎn)為二進(jìn)制mo(MachineObject)文件,供計(jì)算機(jī)讀取執(zhí)行。命令示例:
msgfmt gettext.po -o gettext.mo
7 將mo文件放在正確的目錄結(jié)構(gòu)下
mo文件存放位置是否正確是能否實(shí)現(xiàn)程序國際化的關(guān)鍵。一般情形下,應(yīng)將其放在相應(yīng)地區(qū)的locale下相應(yīng)的子目錄中。通常默認(rèn)目錄結(jié)構(gòu)為/usr/locale/share/local,因此本例中生成的mo應(yīng)放在該目錄下相應(yīng)的子目錄中。但是,由于程序中setlocale()函數(shù)設(shè)定在當(dāng)前目錄結(jié)構(gòu)下查找翻譯信息,因此只需在當(dāng)前目錄(即源程序所在目錄)下新建相應(yīng)的地區(qū)目錄即可。如本例中,可以創(chuàng)建如下目錄結(jié)構(gòu):
zh_CN/LC_MESSAGES/和en_US/LC_MESSAGES/
建好目錄后,分別將兩個不同的mo文件放在這兩目錄下
8 設(shè)置環(huán)境變量
本示例程序會從當(dāng)前的環(huán)境設(shè)定LANG來讀取地區(qū)信息,因此需要設(shè)置LANG,如下。注意:每次只能設(shè)置一個地區(qū)。
LANG=zh_CN.UTF-8
LANG=en_US.UTF-8
9 執(zhí)行程序,得到結(jié)果
在終端界面運(yùn)行 ./gettext 即可得到所要顯示的結(jié)果。
二:國際化程序的升級
調(diào)試程序的過程中,對源程序進(jìn)行相應(yīng)的修改是不可避免的。如何在源程序修改之后,仍能正確的顯示當(dāng)前新修改的翻譯,同時又有效利用原來的翻譯信息以提高效率,即如何對國際化程序進(jìn)行“升級”呢?
采用如下步驟可以解決此問題。
1 修改(增、刪)源程序
2 運(yùn)行xgettext生成新的pot文件
命令示例:
xgettext –keyword=_ gettext.c -o gettext.pot
3 將原程序的po文件更名,以區(qū)分新pot文件將生成的po文件
命令示例:
mv gettext.po old_gettext.po
4 運(yùn)行msgmerge將新、舊pot文件進(jìn)行比較、合并,生成升級版本的po文件
命令示例:
msgmerge old_gettext.po gettext.pot –output-file gettext.po
或者可以使用poedit的POT導(dǎo)入功能
5 為了記錄新舊pot的區(qū)別,可以用diff命令記錄下,兩次pot文件中的異同。
命令示例:
diff -u old_gettext.po gettext.po old_gettext.diff
6 在第4步生成新的po文件生成后,可以刪除原來的po文件,以免干擾。
命令示例:
rm -f old_gettext.po
7 將新生成的po文件生成mo文件
命令示例:
msgfmt gettext.po -o gettext.mo
8 將新生成的mo文件放在正確的目錄結(jié)構(gòu)下
9 設(shè)置環(huán)境變量
10 執(zhí)行程序,得到新的結(jié)果
三:注意的一些問題
1 源程序中的setlocale()函數(shù)與mo文件的目錄結(jié)構(gòu)應(yīng)相一致,否則不能得到正確的結(jié)果。
2 編輯po文件時,注意要將字符調(diào)整為可移植的編碼UTF-8,才可以得到正確結(jié)果。否則會有如下警告:
(gettext.po:警告:字符集“CHARSET”不是可移植的編碼名稱。將消息轉(zhuǎn)換為用戶字符集可能不工作。)
3 設(shè)置多個環(huán)境變量(地區(qū))時,要拷貝多份po并分別進(jìn)行編輯,并將各自生成的mo文件放在正確的目錄下。
4 修改源程序?qū)ζ溥M(jìn)行國際化升級后,應(yīng)刪除原程序(修改前)的可執(zhí)行文件,否則不能得到修改后的程序的運(yùn)行結(jié)果
四:對源程序的一些解釋
#include<stdio.h>
#include<locale.h> //定義本地化函數(shù)。
#include<libintl.h>//包含gettext庫,gettext是GUN為解決程序國際化問題專門建立的一套工具和庫。
#include<stdlib.h>
#define _(String) gettext (String)
int main(int argc,char**argv)
{
setlocale(LC_ALL,"");//設(shè)置本程序的環(huán)境變量(即指特定地區(qū)locale),第一參數(shù)是命令的作用域,可以指日期、貨幣、數(shù)字、文本的顯示樣式;第二參數(shù)是一個文本字符串,標(biāo)志你希望使用哪個地區(qū)。若設(shè)置成一個空的字符串,則程序會從LANG環(huán)境變量獲取地區(qū)信息。
bindtextdomain("gettext",".");//告訴gettext最終的生成的翻譯文件mo的位置,“.”表示在當(dāng)前目錄下尋找mo文件。
textdomain("gettext");//設(shè)定翻譯環(huán)境,即指定使用gettext的翻譯。
printf("%s\n",_("one world,one dream!"));
return 0;
}