使用 Gettext 方案製做多國語系程式 - 總覽
有時候程式寫著寫著一不小心生意愈做愈大,常常就會需要面對不同語言文化客戶的問題, 也就是「國際化與地區化」的議題(Internationalisation and Localisation), 而這些問題中的第一個需要解決的問題常常就是:如何讓我的程式可以切換顯示各國語言的文字? 對於這個問題,我要介紹使用的是 gettext 方案, 這是在自由軟體以及 UNIX 平臺上廣泛被使用的方案。
方案比較
讓應用程式支援多國語系的解決方案可能有很多不同的方式,那麼為什麼我推薦 gettext 方案呢? 這裡就要來比較 gettext 在一些常見的方案中有哪些突出的優點? 對於桌面三大平臺: 在 Linux 和其他 UNIX like 平臺上使用比例最高的就是 gettext 方案,好像也就沒什麼好比較的; 在 OS X 平臺上,我對 Apple 的東西涉略不多,難下論斷, 但既然 OS X 繼承自 Free BSD,那麼理論上應該也可以使用 gettext 無縫接軌; 因此最後會發現,似乎只有在 Windows 平臺上才有不同方案比較的意義, 所以接下來就來就來看看在 Windows 上面可能常見到的多語系開發方案。
不像在 Linux 下被 gettext 統一天下, Windows 平臺下的多語系支援方案比較凌亂,各種解決方案百花齊放。 這可能是因為微軟主推的方案太過繁複,然後其他的方案又都有一些窒礙難行的地方, 沒有誰能夠大大的優於另外一個,最終導致各種稀奇古怪的方案充斥的結果。 在這些方案當中,比較常見的一些如下:
INI 類文字檔
做法最簡單也很常見的一個方案是把程式中使用到的各種文字編為 ID, 然後把這些 ID 和對應的實際文字寫在一個 INI 檔案 (或其他格式文字檔案、這裡僅以 INI 為代表), 實務上有人為每一個支援的語言各建立一個 INI 檔, 也有人把所有支援語言的文字編在同一個 INI 檔(這時就要注意編碼問題 ^_^)。 當程式執行時,首先依據自身設定載入對應的 INI 檔案, 然後在後面程式運作的途中需要輸出文字時,就查詢並取用 INI 檔內的字串即可, 例如「INI 多國語言介面」。
這個方案的優點是簡單容易實現,而且似乎不管什麼樣的程式、什麼樣的平臺都可適用; 然而缺點是缺乏現成的相關處理工具。
要知道一個在具有一定規模的實際專案中,所使用的字串數量成千上萬, 並且隨著程式的開發過程可能還會不斷變化, 那麼翻譯人員難道要手工搜尋處理這樣龐大且隨時變化的文字檔? 通常我們會希望透過一些處理工具來輔助翻譯人員, 至少能夠執行合併新舊翻譯檔、區分已翻譯和未翻譯條目等等工作; 可是因為整個文字檔的格式內容是自訂的、載入以及使用方式也是自己設計的, 因此可能沒有現成的工具可以處理這些工作, 那麼要不就是需要自己開發相關工具,要不就是讓翻譯人員全手動處理翻譯檔!
這些因素使得 INI 方案只適用於不那麼複雜的小型程式、或者缺乏開發資源的專案 (不過就苦了翻譯人員了,雖然在缺乏開發資源的情況下通常程式開發和翻譯會是同一票人)。
Windows 資源檔
對於熟悉 Windows 程式開發的人可能多半知道, Windows GUI 程式有一個特別的「Windows 資源檔」這種東西, 還要用資源檔編譯器編譯後再連結到最終的程式。 微軟對於多國語系開發的部份主打使用資源檔, 就是將所有程式中使用的字串都編到資源檔裡面去,執行時期再透過 ID 來找對應的字串, 概念上與使用 INI 檔類似,只不過把 INI 檔換成資源檔。
這麼做的好處除了微軟在 官方文件上對於多語系程式推薦使用這種方式、 以及可以把程式全包成一個執行檔而不用附帶一大堆檔案以外,似乎就沒再有什麼太大的優點。 使用 Windows 資源檔做為多國語系解決方案倒是存在不少缺點:
- 當人們需要增加一些翻譯字串、或想要擴充支援原來沒有被支援的語言時, 需要修改資源檔並重新編譯程式。
- 除了使用 Visual Studio 以外,有沒有什麼好的資源檔編輯器? 要知道一般的翻譯人員可能通常不會寫程式,難道要先教會他們使用 Visual Studio?
- 如果開發的程式不是 MFC 或 WTL 專案,能夠簡單順暢的使用資源檔嗎?
- 如果不使用 Visual C++ 編譯器的話,能夠簡單順暢的使用資源檔嗎?
- 既然 Windows 資源檔是 Windows 下特有的產物,那如何面對跨平臺程式開發的需求?
此外,若專案沒有建基在 Unicode 環境的話,還會面臨一些嚴重的問題。 我在剛畢業的時候負責開發維護一個建立在 Borland C++ Builder 6 下的專案, 就是使用 Windows 資源檔以及一些小腳本處理多國語言的問題, 我們還做了一些工具用來掃描 DFM 檔案並生成翻譯用的 Excel 檔, 再把 Excel 檔內容取出並覆蓋回 DFM 檔和 RC 檔。 那時我們的程式主要需要中文、簡中、和英文版本,為此我們需要編出三套執行檔。 英文的部份在任何語系下都能被支援, 但為了編譯 GBK 編碼的資源,我們需要重新開機到簡中環境下編譯這部份的程式碼, 然後再重開機回來進行程式打包工作,你看那如果我們要支援更多一點語言的話不就忙死了! 我後來寫了 batch 腳本處理各種工序,使得一個按鍵可以完成絕大部分的編譯打包工作; 只是碰到需要切換語系並重新開機的部份就沒輒了,整個程序最終仍然無法一鍵完成。
有人會說那如果把整個專案改成 Unicode 環境呢?這個我嘗試過了,最終仍以失敗告終。 為了這件事我還寫了一份關於 「字元編碼與程式設計」的心得。
其他 GUI 框架自己的方案
其實除了微軟的 MFC、WTL 等等之外,Windows 平臺上還有一些其他的 GUI 框架, 這些框架可能也覺得現有多語系程式的開發存在許多困難的問題, 因此索性也各自提出了自己的多語系方案,比如 Qt 早早就推出了多語系方案, 較新版本的 Borland VCL framework 也推出了自己的 ITE 多語系方案, 這樣,Windows 上的多語系方案就更凌亂了!
使用這些 GUI 框架多語系方案的好處是這些方案與框架本身最匹配, 並且可以無需理會平臺的差異,在不同平臺下都使用同一套做法(如果該框架本身有跨平臺的話)。 而缺點就是該方案只適用於該框架,當轉換框架時就要重新來過; 或者比如說我今天想要做個 console 工具程式, 難道為了多語系的緣故我還要大費周張把 GUI 框架給拉進來嗎?
-
最後介紹重頭戲,就是廣泛被用在跨平臺程式的 gettext 方案, 這個方案有一些優點:
- 由於使用廣泛且歷史悠久,存在許多現成的工具程式。
- 可以將開發者和翻譯者的工作流程分離,翻譯者無需涉及程式碼和編譯工作。
- 該方案是一個僅僅用於處理多語系文字相關的程式庫和工具集,無涉任何框架, 可被使用於任何專案。
- 除了 C/C++ 以外,gettext 還有如 Java、Python、C# 等等多種語言的 bundle, 適用範圍挺大。
- 該方案本身無平臺上的強相依性,可被移植使用於任何平臺。
- 該方案本身結構單純,即便在執行時庫的移植或授權上遇到問題,自行實做也很容易。
- 該方案下的語系檔案本身獨立於應用程式之外, 可在不動到應用程式的情況下對翻譯資料進行更新、擴充,或加入原本所沒有的語系。
由於 gettext 的執行時庫已被納入 Glibc, 也就是說基本上在 Linux 平臺下是原生支援 gettext 環境, 連特別連結什麼程式庫的動作都不需要,只要直接使用它就好了,可說是非常方便。 由於眾多優點,特別是在跨平臺特性上面的優點, 使得大量跨平臺的自由軟體在 Windows 上都還是依循使用 gettext 方案, 比如說著名的 LibreOffice。
缺點就是 Windows 並沒有原生支援 gettext,至少需要執行時庫的移植工作; Windows 的 locale name 和 Linux 也不太一樣,需要轉換一下, 這些不方便的地方使得 gettext 方案並沒有大量流行在非跨平臺的應用程式上。
以上就是個人對一些多語系方案的見解和觀察,也許有些偏頗或不週全的地方還請多包涵。 我本人因為一些緣故需要在 Windows 使用 gettext 方案,目前在移植工作上進行的不太順利, 後來一看 MO 檔案的格式 超級簡單,索性就自己做了一個 簡單的(而且限制比較多的)程式庫 解決了我的問題。
gettext 使用指引
雖然主打著介紹和教學的標題, 但在本篇裡,我沒有打算描述太多有關於 gettext 的使用細節, 只打算做一些比較簡單的介紹,對於較多的操作細節則留待後篇描述。
對於一個使用 gettext 方案處理多語系文字的程式而言,在開發、建置、和發佈等整個過程中, 大約會需要面對幾個部份的工作:
- 如何編寫支援 gettext 的程式碼?請參閱 「使用 gettext 方案製做多國語系程式 - 程式編寫」
- 如何生成翻譯文件並進行翻譯工作?以及翻譯後產生的語系資源檔案要放在哪裡?請參閱 「使用 gettext 方案製做多國語系程式 - 製做語系檔」