徹底解密C 寬字元 6 國際化策略(完)

2021-05-23 02:12:19 字數 2137 閱讀 2989

硬編碼的硬傷

我們現在知道,c/c++的寬窄轉換是依賴系統的locale的,並且在執行時完成。考慮這樣一種情況,我們在簡體中文windows下編譯如下語句:

const char* s = "中文abc";

根據我們之前的討論,編譯器將按照windows codepage936(gb2312)對這個字串進行編碼。如果我們在程式中執行寬窄轉換函式,將s轉換為寬字串ws,如果這個程式執行在簡體中文環境下是沒問題的,將執行從gb2312到ucs-2be的轉換;但是,如果在其他語言環境下,比如是正體中文big5,程式將根據系統的locale執行從big5到ucs-2be的轉換,這顯然就出現了錯誤。

補救有沒有補救這個問題的辦法呢?乙個解決方案就是執行不依賴locale的寬窄轉換。實際上,這就已經不是寬窄轉換之間的問題了,而是編碼之間轉換的問題了。我們可以用gnu的libiconv實現任意編碼間的轉換,對於以上的具體情況,指明是從gb2312到ucs-2be就不會出錯。(請參考本人前面的章節:win32下的libiconv),但這顯然是乙個笨拙的策略:我們在簡體中文windows下必須使用gb2312到ucs-2be版本的寬窄轉換函式;到了big5環境下,就必須重新寫從big5到ucs-2be的寬窄轉換函式。

windows的策略

windows的策略是淘汰了窄字串,乾脆只用寬字串。所有的硬編碼全部加上特定巨集,比如text(),如果程式是所謂unicode編譯,在編譯時就翻譯為ucs2-be——windows自稱為unicode程式設計,其本質是使用了ucs-2be的16位寬字串。

linux的策略

linux下根本就不存在這個問題!因為各種語言的linux都使用utf-8的編碼,所以,無論系統locale如何變化,窄到寬轉換的規則一直是utf-8到utf32-be 。

跨平台策略

因為在16位的範圍內,utf32-be的前16位為0,後16位與ucs2-be是一樣的,所以,即使wchar_t的sizeof()不一樣,在一般情況下,跨平台使用寬字元(串)也應該是相容的。但是依然存在潛在的問題,就是那些4位元組的utf32編碼。

gettext策略

以上都是將ascii及以外的編碼硬編碼在程式中的辦法。gnu的gettext提供了另外一種選擇:在程式中只硬編碼ascii,多語言支援由gettext函式庫在執行時載入。(對gettext的介紹請參考本人前面的章節:win32下的gettext)。gettext的多語言翻譯檔案不在程式中,而是單獨的提出來放在特定的位置。gettext明確的知道這些翻譯檔案的編碼,所以可以準確的告訴給系統翻譯的正確資訊,而系統將這些資訊以當前的系統locale編碼成窄字串反饋給程式。例如,在簡體中文windows中,gettext的po檔案也可以以utf-8儲存,gettext將po檔案翻譯成mo檔案,確保mo檔案在任何系統和語言環境下都能夠正確翻譯。在執行是傳給win32程式的窄串符合當前locale,是gb2312。gettext讓國際化的翻譯更加的方便,缺點是目前我沒找到支援寬字串的版本(據說是有ugettext()支援寬字串),所以要使用gettext只能使用窄字串。但是gettext可以轉換到寬字串,而且不會出現寬窄轉換的問題,因為gettext是執行時根據locale翻譯的。例如:

const char* s = gettext("chinese a b c");

其中"chinese a b c"在po中的翻譯是"中文abc"

使用依賴locale的執行時寬窄轉換函式:

const std::wstring wstr = s2ws(s);

執行時呼叫該po檔案對應的mo檔案,在簡體中文環境下就以gb2312傳給程式,在正體中文中就以big5傳給程式,這樣s2ws()總能夠正常換算編碼。

更多在本文的最後,我想回到c++的stream問題上。用fstream轉換如此的簡單,sstream卻不支援。改造乙個支援codecvt的string stream需要改造basic_stringbuf。basic_stringbuf和basic_filebuf都派生自basic_streambuf,所不同的是basic_filebuf在構造和open()的時候呼叫了codecvt,只需要在basic_stringbuf中新增這個功能就可以了。說起來容易,實際上是需要重新改造乙個stl模板,儘管這些模板源**都是在標準庫標頭檔案中現成的,但是我還是水平有限,沒有去深究了。另外乙個思路是構建乙個基於記憶體對映的虛擬檔案,這個框架在boost的iostreams庫中,有興趣的朋友可以深入的研究。

(完)

徹底解密C 寬字元 5 利用fstream轉換

c 的流和本地化策略集 bs在設計c 流的時候希望其具備智慧型化,並且是可擴充套件的智慧型化,也就是說,c 的流可以 讀懂 一些內容。比如 std cout 123 ok std endl 這句 中,std cout是能判斷出123是int而 ok 是const char 3 利用流的智慧型,甚至可...

C 的國際化

c 通過編輯不同的資源檔案來實現國際化。也就是在c 的專案中增加幾個不同語言的資源。例如可以類似如下 resouces.zh cn.resx resouces.en us.resx 具體實現過程 1.增加不同語言的資源檔案。2.在編寫資源檔案的時候,保證資源的name是一樣的,只是在不同語言中的值是...

c 支援國際化

c 支援國際化實現方式 1 新建winform工程,名稱myresource.2 工程支援中文和英文,在當前工程中新建資源檔案resource.zh cn.resx和resource.en.resx,在這2個資源檔案中填寫好中文和英文資訊。3 在工程中新建util.cs類 如下 using syst...