c语言的本地化实现
說明:這篇文章并不是本人的原作,是本人在網上看到的一篇PDF,然后整理來的,原作者叫李東東(中標普華)
/********************************************************
在linux系統下,以c語言程序為例來實現程序的國際化,即讓程序根據Linux系統不同的語言環境
的不同來顯示出對應該語言的文字,即先讓c程序支持國際化然后再進行本地化翻譯。
Linux上實現這個過程需要用到xgettext和msgfmt這兩個工具。
Xgettext 是國際化的工具,用來提取程序中的字符串,生成*.po或是*.pot的文件,
msgfmt 是本地化的工具,用來編譯翻譯后的.po文件為.mo文件,這樣系統在啟動時
候會掃描系統環境提取對應名字的.mo文件中的字符串替代原來的英文,實現本地化。
下面用一個例子來說明使用過程
第一步、支持國際化的C程序(hello.c)如下:
一個支持本地化的C程序,需要用setlocale()來設定翻譯選擇的語言環境,一組或多組textdomain()和
bindtextdomain()函數來指定用到的翻譯文件和該文件所在路徑,其textdomain()函數用來指定翻譯文件的名
字,而bindtextdomain()函數用來指定該名稱的翻譯文件所在路徑(如果存在多組翻譯文件
*********************************************************/
/*========= hello.c 源程序 =========*/ #include <stdio.h> #include <stdlib.h> #include <locale.h> //本地化locale翻譯的支持 #include <libintl.h> //gettext庫的支持 #define PACKAGE "hello" //家義翻譯包的名字為hello,必須與最后生成的.mo文件一致 #define LOCALEDIR "/usr/share/locale/" //定義系統語言環境的目錄,該目錄下存放著國際化的語言,不同系統可能會有差異,我用的是紅帽4.1.2int main() {setlocale(LC_ALL, ""); //設置使用環境變量(系統當前的值)bindtextdomain(PACKAGE, LOCALEDIR); //關聯翻譯包名稱及其對應的國際化翻譯語言所在路徑textdomain(PACKAGE);//定義.mo文件的名字,最終我們生成的為hello.moprintf(gettext("Hello, World!\n"));//國際化字符串的支持,這里我們只展示對中文的支持,其他的類似!return 0; }
關于不同路徑下面的多個翻譯文件
對于一個C語言程序允許對應于系統中不同位置的多個mo文件,用一組
bindtextdomain()和textdomain()函數來定義緊跟在該組中textdomain()函數后的支持國際化的
翻譯語言包所在位置,當程序運行時根據指定的位置來查找翻譯文件并顯示。如下:
?bindtextdomain (PACKAGE, LOCALEDIR);
Linux下C語言的本地化/國際化實現
?textdomain (PACKAGE);
? ? printf(gettext("Hello, World!\n")); ? ? ? ?
? ? printf(gettext("test 001\n"));
? /*上面的翻譯用的是LOCALEDIR路徑下PACKAGE.mo的翻譯,本文中用的PACKAGE名為hello*/
?bindtextdomain (P2, L2);
?textdomain (P2);
? ? printf(gettext("Hello, World!\n"));/*該行的翻譯用的是L2路徑下P2.mo*/
當然也可以先用bindtextdomain()來定義系統語言包所在位置,然后再分別指定翻譯文件在哪
個路徑下的語言包:
?bindtextdomain (PACKAGE, LOCALEDIR);
?bindtextdomain (P2, L2);
?textdomain (PACKAGE);
? ? printf(gettext("Hello, World!\n")); ? ? ? ?
? ? printf(gettext("test 001\n"));
? ? ? ? ? /*上面的翻譯用的是LOCALEDIR路徑下PACKAGE.mo的翻譯*/
?textdomain (P2);
? ? printf(gettext("Hello, World!\n")); ? ? ? ? ?/*該行的翻譯用的是L2路徑下P2.mo*/
第二步、提取待翻譯po并進行本地化
先用下面的命令提取出c程序中需要進行本地化的語言文件。
執行命令: xgettext -k --keyword=gettext ?hello.c ?-o ?hello.pot
再用vim翻譯hello.pot中對應英文為中文并重命名為zh_CN.po ,作為中文本地化的翻譯文件。
對于po文件的頭文件格式
首先來簡單介紹下po內容的頭文件格式(詳細的可以參考“Mos翻譯注意事項-內部版”):
? 1 msgid "" ? ? ? ? ? ? ? ? ? ? ? ? ? ? //待翻譯的文字,msgid字符串是由GNU gettext工具產生和管理,并不允許翻譯人員改動
? 2 msgstr "" ? ? ? ? ? ? ? ? ? ? ? ? ? ?//對應的翻譯后文字
? 3 "Project-Id-Version: \n" ? ? ? ? ? ? ? ? ? ? ? ? //項目名稱版本,一般為該包名稱 如:hello,亦可空缺
? 4 "Report-Msgid-Bugs-To: \n" ? ? ? ? ? ? ? ? ?//Bugs信息報告方法
? 5 "POT-Creation-Date: 2010-03-11 11:52+0800\n" ? //pot文件創建時間
? 6 "PO-Revision-Date: \n" ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //生成po文件的時間
? 7 "Last-Translator: yourmail <emailaddress@cs2c.com.cn>\n" ?//最后翻譯者信息,格式:名稱<郵箱>\n
? 8 "Language-Team: \n" ? ? ? ? ? ? //翻譯小組名稱,上游社區本地化群組的翻譯成員填入其組織信息,亦可以不填
? 9 "MIME-Version: 1.0\n" ? ? ? ?//MIME版本,一般取默認即可,不影響翻譯文件
?10 "Content-Type: text/plain; charset=GB2312\n" // 剛創建的pot文件默認為“charset=CHARSET”,編輯po文件時,注
意要將字符調整為可移植的編碼格式,原文 這里寫的是UTF-8,會報錯(估計作者是想寫utf8的)否則會有如下警告:(hello.po:警告:字符
集“CHARSET”不是可移植的編碼名稱。將消息轉換為用戶字符集可能不工作。改成utf8也會有這個警告,所以筆者改成了GB2312)
?11 "Content-Transfer-Encoding: 8bit\n"?
?12 "Plural-Forms: nplurals=1; plural=0;\n" ? ? ? ?//此行在本文中沒用 nplurals= 表示單復數變化形式的數量,中文中單復數相同所以為1
// plural= ?表示對第幾種單復數變化取相應的第幾種譯文,中文中只取msgstr[0] 即可
最終的zh_CN.po文件為:
# Chinese translations for PACKAGE package
# PACKAGE 軟件包的簡體中文翻譯.
# Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# ?<wangwei@localhost>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-11 16:06+0800\n"
"PO-Revision-Date: 2013-10-11 16:12+0800\n"
"Last-Translator: ?<shell@localhost>\n"
"Language-Team: Chinese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=GB2312\n"
"Content-Transfer-Encoding: 8bit\n"
#: hello.c:14
#, c-format
msgid "Hello, World!\n"
msgstr "你好,世界!\n"
第三步生成.mo文件
執行命令: msgfmt zh_CN.po -o hello.o
此處之所以.mo文件名為 hello,是因為我們的程序指定的PACKAGE名為hello
然后將生成的hello.mo 挎入目錄 /usr/share/locale/zh_CN/LC_MESSAGES
如果沒有可以用mkdir創建
最后編譯hello.c 測試成果
gcc hello.c -o hello
執行 ./hello 結果為
Hello, World!
我們導出 export LANG=zh_CN
再次執行 ./hello 結果變為我們漢語
你好,世界!
以上就是用實現c語言本地化的過程,其中相關的函數和命令除了以上涉及到的還有:
/********************************************************
在linux系統下,以c語言程序為例來實現程序的國際化,即讓程序根據Linux系統不同的語言環境
的不同來顯示出對應該語言的文字,即先讓c程序支持國際化然后再進行本地化翻譯。
Linux上實現這個過程需要用到xgettext和msgfmt這兩個工具。
Xgettext 是國際化的工具,用來提取程序中的字符串,生成*.po或是*.pot的文件,
msgfmt 是本地化的工具,用來編譯翻譯后的.po文件為.mo文件,這樣系統在啟動時
候會掃描系統環境提取對應名字的.mo文件中的字符串替代原來的英文,實現本地化。
下面用一個例子來說明使用過程
第一步、支持國際化的C程序(hello.c)如下:
一個支持本地化的C程序,需要用setlocale()來設定翻譯選擇的語言環境,一組或多組textdomain()和
bindtextdomain()函數來指定用到的翻譯文件和該文件所在路徑,其textdomain()函數用來指定翻譯文件的名
字,而bindtextdomain()函數用來指定該名稱的翻譯文件所在路徑(如果存在多組翻譯文件
*********************************************************/
/*========= hello.c 源程序 =========*/ #include <stdio.h> #include <stdlib.h> #include <locale.h> //本地化locale翻譯的支持 #include <libintl.h> //gettext庫的支持 #define PACKAGE "hello" //家義翻譯包的名字為hello,必須與最后生成的.mo文件一致 #define LOCALEDIR "/usr/share/locale/" //定義系統語言環境的目錄,該目錄下存放著國際化的語言,不同系統可能會有差異,我用的是紅帽4.1.2int main() {setlocale(LC_ALL, ""); //設置使用環境變量(系統當前的值)bindtextdomain(PACKAGE, LOCALEDIR); //關聯翻譯包名稱及其對應的國際化翻譯語言所在路徑textdomain(PACKAGE);//定義.mo文件的名字,最終我們生成的為hello.moprintf(gettext("Hello, World!\n"));//國際化字符串的支持,這里我們只展示對中文的支持,其他的類似!return 0; }
關于不同路徑下面的多個翻譯文件
對于一個C語言程序允許對應于系統中不同位置的多個mo文件,用一組
bindtextdomain()和textdomain()函數來定義緊跟在該組中textdomain()函數后的支持國際化的
翻譯語言包所在位置,當程序運行時根據指定的位置來查找翻譯文件并顯示。如下:
?bindtextdomain (PACKAGE, LOCALEDIR);
Linux下C語言的本地化/國際化實現
?textdomain (PACKAGE);
? ? printf(gettext("Hello, World!\n")); ? ? ? ?
? ? printf(gettext("test 001\n"));
? /*上面的翻譯用的是LOCALEDIR路徑下PACKAGE.mo的翻譯,本文中用的PACKAGE名為hello*/
?bindtextdomain (P2, L2);
?textdomain (P2);
? ? printf(gettext("Hello, World!\n"));/*該行的翻譯用的是L2路徑下P2.mo*/
當然也可以先用bindtextdomain()來定義系統語言包所在位置,然后再分別指定翻譯文件在哪
個路徑下的語言包:
?bindtextdomain (PACKAGE, LOCALEDIR);
?bindtextdomain (P2, L2);
?textdomain (PACKAGE);
? ? printf(gettext("Hello, World!\n")); ? ? ? ?
? ? printf(gettext("test 001\n"));
? ? ? ? ? /*上面的翻譯用的是LOCALEDIR路徑下PACKAGE.mo的翻譯*/
?textdomain (P2);
? ? printf(gettext("Hello, World!\n")); ? ? ? ? ?/*該行的翻譯用的是L2路徑下P2.mo*/
第二步、提取待翻譯po并進行本地化
先用下面的命令提取出c程序中需要進行本地化的語言文件。
執行命令: xgettext -k --keyword=gettext ?hello.c ?-o ?hello.pot
再用vim翻譯hello.pot中對應英文為中文并重命名為zh_CN.po ,作為中文本地化的翻譯文件。
對于po文件的頭文件格式
首先來簡單介紹下po內容的頭文件格式(詳細的可以參考“Mos翻譯注意事項-內部版”):
? 1 msgid "" ? ? ? ? ? ? ? ? ? ? ? ? ? ? //待翻譯的文字,msgid字符串是由GNU gettext工具產生和管理,并不允許翻譯人員改動
? 2 msgstr "" ? ? ? ? ? ? ? ? ? ? ? ? ? ?//對應的翻譯后文字
? 3 "Project-Id-Version: \n" ? ? ? ? ? ? ? ? ? ? ? ? //項目名稱版本,一般為該包名稱 如:hello,亦可空缺
? 4 "Report-Msgid-Bugs-To: \n" ? ? ? ? ? ? ? ? ?//Bugs信息報告方法
? 5 "POT-Creation-Date: 2010-03-11 11:52+0800\n" ? //pot文件創建時間
? 6 "PO-Revision-Date: \n" ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //生成po文件的時間
? 7 "Last-Translator: yourmail <emailaddress@cs2c.com.cn>\n" ?//最后翻譯者信息,格式:名稱<郵箱>\n
? 8 "Language-Team: \n" ? ? ? ? ? ? //翻譯小組名稱,上游社區本地化群組的翻譯成員填入其組織信息,亦可以不填
? 9 "MIME-Version: 1.0\n" ? ? ? ?//MIME版本,一般取默認即可,不影響翻譯文件
?10 "Content-Type: text/plain; charset=GB2312\n" // 剛創建的pot文件默認為“charset=CHARSET”,編輯po文件時,注
意要將字符調整為可移植的編碼格式,原文 這里寫的是UTF-8,會報錯(估計作者是想寫utf8的)否則會有如下警告:(hello.po:警告:字符
集“CHARSET”不是可移植的編碼名稱。將消息轉換為用戶字符集可能不工作。改成utf8也會有這個警告,所以筆者改成了GB2312)
?11 "Content-Transfer-Encoding: 8bit\n"?
?12 "Plural-Forms: nplurals=1; plural=0;\n" ? ? ? ?//此行在本文中沒用 nplurals= 表示單復數變化形式的數量,中文中單復數相同所以為1
// plural= ?表示對第幾種單復數變化取相應的第幾種譯文,中文中只取msgstr[0] 即可
最終的zh_CN.po文件為:
# Chinese translations for PACKAGE package
# PACKAGE 軟件包的簡體中文翻譯.
# Copyright (C) 2013 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# ?<wangwei@localhost>, 2013.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-10-11 16:06+0800\n"
"PO-Revision-Date: 2013-10-11 16:12+0800\n"
"Last-Translator: ?<shell@localhost>\n"
"Language-Team: Chinese\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=GB2312\n"
"Content-Transfer-Encoding: 8bit\n"
#: hello.c:14
#, c-format
msgid "Hello, World!\n"
msgstr "你好,世界!\n"
第三步生成.mo文件
執行命令: msgfmt zh_CN.po -o hello.o
此處之所以.mo文件名為 hello,是因為我們的程序指定的PACKAGE名為hello
然后將生成的hello.mo 挎入目錄 /usr/share/locale/zh_CN/LC_MESSAGES
如果沒有可以用mkdir創建
最后編譯hello.c 測試成果
gcc hello.c -o hello
執行 ./hello 結果為
Hello, World!
我們導出 export LANG=zh_CN
再次執行 ./hello 結果變為我們漢語
你好,世界!
以上就是用實現c語言本地化的過程,其中相關的函數和命令除了以上涉及到的還有:
msgmerge msginit ngettext localeconv,具體可參考 man 7 locale
更詳細可參考?使用gettext本地化編程
總結
- 上一篇: 如何创建一个进度条控件
- 下一篇: 几种常用的Web安全认证方式