說明在BCB中如何撰寫多國語言程式。

如 果您寫的軟體需要考慮到轉換成為不同語言,那麼由Borland C++ Builder Enterprise Edition 所提供給您的多國語言翻譯環境將是極為有幫助的。他可以很快的幫助您將各國語言版本製作出來。並且也提供動態的方式讓您可以輕易的製作出您所需要的版本。 甚至可以讓您在不用變動程式碼本身的狀態下,將GUI 的外觀字型等進行適度的調整。

除了多國語言介面的製作外,透過本文後面所敘述的技巧,將可以讓您動態的切換不同的語系。這些BCB 都已經幫您處理得很好了,不過有些小細節您仍然需要注意,小心的處理或是避開,否則很容易的做不出來您想要的結果。

首先,我們先來看一下在設計程式時要注意的東西。

  1. 第 一個版本務必使用英文。這點非常重要,這要的理由有二。第一點是通常比較好的文字翻譯最好是由該國自己翻譯。舉例來說,要製作日文版本,當然是請道地的日 本人來翻譯會好的多。那麼你認為懂得英文的日本人多,還是懂得中文的日本人多?同理,換成韓文,法文與西班牙文也是一樣。第二點是由於在處理上,BCB 所提供的環境通常比較能夠正確的支援英文及該平台的語系。也就是說,您可以很容易找到可同時顯示及處理英文及日文的平台,或者是英文及法文的平台。因為, 沒有一個語系的平台不能處理英文。可是你比較難找到一個可同時處理中文及日文的平台,或是同時處理中文及法文的平台。例外,還有一個理由未列在上面的是, 在大部分的狀況下,英文的句子長度比較長。
  2. 不要強制設定任何元件及Form的預設字形。這是因為每個平台系統所使用的預設 字型及大小都有所不同。像是英文作業系統中預設字型是 Tohoma,但是中文及日文的windows作業系統就不是這樣。使用的語系一定要使用正確語系的字型才有辦法顯示。所以,使用預設字形,可讓AP字型 隨著系統自動調整為正確字形。或許\不見得比較好看( 大部分非英語系Windows 作業系統的預設英文字型都很難看,不知理由為何? ),但至少是正確的。要做的這點很簡單,確定您所有元件的屬性中,只要有ParentFont這項的一定要強制設為true。尤其是Form的 ParentFont一定要設為true。否則你一定會在多國語言版本的過程中遇到big trouble 。相信我!否則我就不會寫這篇文章來提醒你了。
  3. 別把要顯示的字串寫死在程式裡。像是下面這樣: ShowMessage("Hello World!"); 或是 MainForm->Caption = "Main Form" ; 理由很簡單,寫在程式裡的字串Borland C++ Builder的工具無法幫你處理他們,這樣在翻譯時,就得自己把所有的Source Code搜尋一遍找出這些字串。平常,隨便寫個小程式,這樣的字串就已經有十來個,您想想看,要是稍微大點的Project,這會有多恐怖?所以,我們要 採用一個集中的方法,這個方法還要能夠與Borland C++ Builder的翻譯工具相結合。或許,您之前看過我寫的那個使用Resource File 的StringTable的文章。但是,我要告訴你,忘了它吧。我在寫那篇文章的時候沒注意到Borland C++ Builder無法使用那個方法。也不是說那個方法是C++ Builder完全不能用,而是,如果您想要動態進行各國語系的切換,請放棄使用Resouce File的StringTable。不過,就算不為這個理由,我也是建議你換成本文後面要介紹的Resourcestring的方式,理由是他比較方便使 用。也比較像是C++ Builder的作法。不過,這個作法的缺點有二,一為要使用Pascal的語法。別擔心,保證不要一分鐘就學會。二是只有C++ Builder跟Delphi可用。其它的Compiler像是MS VC++就不能用囉。
  4. 寫程式時,無論任何理由都不要 讓自己的程式綁死在某個語系上面。例如:你可能會想說要好看一點所以寫成"92年2月2日"。可是,這樣的東西在其它語言馬上變成亂碼。因此,基本的方式 是使用國際通用的格式。當然最好的方式還是要能自動轉換成為各國的常用表示方法。但是這個部分屬於l10n的範疇,我還沒研究過,有空再說囉。

現 在,就讓我們來看看這個Delphi語法的ResourceString要怎麼用在C++ Builder中。其實,在多國語言上,Borland已經準備好了一個範例,放在$(BCB)\Examples\Apps\RichEdit。這個範 例很重要的,他裡面有些程式是我們後面介紹動態變換語系時要借來用用的。不過,這邊我們先借他的ReConst.pas這個檔案來用一下。您會看到這個檔 案有下面的內容:

unit ReConst;
interface
uses Windows;

const
ENGLISH = (SUBLANG_ENGLISH_US shl 10) or LANG_ENGLISH;
GERMAN = (SUBLANG_GERMAN shl 10) or LANG_GERMAN;
FRENCH = (SUBLANG_FRENCH shl 10) or LANG_FRENCH;

resourcestring
SUntitled = 'Untitled';
SPercent_s = '%s - %s';
SSaveChanges = 'Save Changes?';
SConfirmation = 'Confirmation';
SNumberbetween = 'The number must be between 1 and 1638.';
SLcid = '1033'; { US = 1033; DE = 1031; FR = 1036 }

implementation
end.

看到那個resourcestring了沒?沒錯,就是這樣!只要把那些resourcestring中的字串換成你自己的定義就可以囉。稍微要注意的是這個字串是使用單引號來括住的,因為他是Pascal語法嘛!例如,您可定義自己的字串為:

resourcestring
MyResString1 = 'My First resource string' ;

你可能覺得SLcid那行有點看不懂,別擔心!在那行的分號後面的字串全是註解。因為,在Pascal中,大括號被當成註解符號使用。您也可以如法炮製的來為您的字串加上註解。

另 外,const中定義的是常數,其型態為Word,也就是2 Bytes。值介於0-65535之間。所以,建議您一併將程式內用到的常數定義在此,這樣比較符合集中管理的精神。最後,別忘了將第一行的Unit敘述 換掉。不過,您要先為您自己的檔案命名。建議您學ReConst.pas 的命名方式。例如,您的Project縮寫是CF好囉,那麼就叫他CfConst.pas吧。所以,"Unit ReConst;"也要改成"Unit CfConst;"才行囉。

好吧,完成後,請將這個pas 檔案加入到你的Project 中。OK!光是這樣是沒用的。因為,C++ 需要有include 檔案。那麼,CfConst.pas的include檔案從何而來?還好,C++ Builder有自動產生include 檔案的能力,請在打開CfConst.pas後,按下Alt-F9,讓C++ Builder單獨compile它。成功\的話,您就可看到CfConst.hpp這個檔案的出現。理論上,您該在所有的cpp 檔案中都會用到這個include檔案才對。另外,別把這個include檔案跟precompiled header的技巧合用喔。因為他會為常數進行初始化,所以precompiled header技巧遇到他就做不出來了。請個別在需要的程式檔中include這個header file就可以了。

OK! 接下來要怎麼在程式內使用這些常數及Resource字串呢?非常簡單!!用就對了!舉例來說,您要使用MyResString1。您可使用下面的方式:

    ShowMessage(Cfconst_MyResString1);

是的!在您要用的Resource string名稱前面加個"Cfconst_"的prefix。就可以了。當然,這個prefix完全是根據您Unit的定義而來。您可參考前面步驟所做出的include檔案中,的namespace名稱,就可看到囉。

在 瞭解了這個部分後,接下來就是要把你的程式寫好囉。請注意,多國語言化的翻譯務必在最後進行。而且是要在程式完成度已經相當高的時候才進行。否則,畫面一 下子變化太大的話,C++ Builder的多國語言環境也吃不消的。現在,假設您的程式已經完成了,接下來要如何才能夠進行多國語言化呢?首先,您需要開啟Resource DLL Wizard來製作Resource DLL。

你可在主選單中依照New->Others->New->Resource DLL Wizard來開啟它。接下來這個精靈程式會給您一些指示,並請您選擇要製作的語系。

首 先,您在精靈中遇到的第一個問題是精靈會詢問你要對哪個Project 製作多國語言版本。把你要製作的Project 打勾。然後,繼續後面的步驟。這邊有一點要注意的是BCB 多國語言環境似乎有點問題,如果您的Project 放在一些中文目錄中,可能會找不到,所以建議您的Project 要放在純英文的路徑內。

接著,就是要選擇您要轉換的語系了。C++ Builder 的精靈會列出所有的語系讓您選擇。您可以一次把要做的語系全部選出來。也可以一次只選一些,下次要加入其它語系時,請重複這個步驟就可以了。別擔心舊的語 系會被蓋\掉,C++ Builder 已經幫您處理好了。選好你的語系後按下下一步,您就會看到這些語系所對的目錄。例如:中文就是CHT,簡體是CHS,日文是JPN等等。

接 著,下一個畫面,BCB 會問您有沒有其它的要加入的處理的檔案。如果要加入的應該都是dfm 檔或是rc檔案。在接著下一步就是要產生語系了。C++ Builder 最後還會再列出一次要進行的語系給你看。沒問題的話,就按Finish囉。在最後列出所有語系的地方,有一欄為Update Mode 。如果您是第一次對這個語系建立Resource DLL,那麼這個欄位就是Create New 。如果您之前已經建立過這個語系了,而且您又再次使用Resource DLL來建立他。沒問題精靈會幫您處理好,所以您會看到Update Mode 中所顯示的是Update。如果,您不想要只是Update而已,而是要重新建立新的,在Update上面點一下,一個combo box 會出現讓您選擇。

最後都沒問題的話,您就會看到精靈跟您說他需要重新編譯您的程式以方便建立各國語言。在此同時,精靈會要求您將 Project存成Project Group。這是因為每個語系都是自己一個Project 。用成Project Group才能統一管理。對於這個Project Group的名稱我的建議是在Project名稱後面加上"_i18n"的字尾。當然,或許\有人會習慣在前面加上ML的前置詞,代表Multiple Language。不過,我還是覺得用i18n好。

存檔成功\而且Project 也重新Compile成功,這時,精靈會順便幫您叫出翻譯管理員(Translation Manager)。在這個Translation Manager中,您需要使用其中的Workspace 畫面來幫助您進行翻譯的工作。Translation Manager的用法不難,大家看看就會了。重點是除了字串外,您還可透過翻譯管理員調整元件大小,避免不同語系下,字串被元件破壞的窘境。

您 隨時都可透過主選單的View->Translation Manager來叫出翻譯管理員。只是每次翻譯完,您都需要針對有修改過的語系重新編譯。每個單獨語系都會編譯出自己的Resource DLL 。這些檔案的名字就是Project的名字,加上以語系的名字作副檔名。所以,如果您有一個名為Project1.exe的檔案。那麼他對應的中文繁體語 系檔就是Project1.CHT。日文就是Project1.JPN。這些語系檔案要與執行檔放置於同一個目錄下。

至於我們前面所說的 resourcestring,他會出現在各語系的Resource script 中。您也是透過翻譯管理員來編輯他們。不過,在這裡C++ Builder一直到6.0 update 2都有這麼個Bug 。這個Bug 會導致您的resourcestring在切換語系時,不會被載入。好的,要如何解決他呢?簡單的很,請開啟你的Project Mananger,將每個語系的Project加入一個名為XXX_DRC.rc的檔案。其中,XXX就是你的Project名稱。這個檔案在每個語系自 己的目錄下都有一個,您需要為每個語系的Project 加入他。當然,別弄錯目錄,把不同的語系檔案混在一起囉。

如果您要設定這個Project在目前平台要使用何種語系,可利用Project->Languages->Set Active設定預設語系。實際上,您的程式是根據下面這個Registry的值來決定要使用何種語系Resource DLL:

    HKEY_CURRENT_USER\Software\Borland\Locales\[Exec file name]

其中"Exec file name"就是你的執行檔名(含路徑),這個Registry的值是您希望的語系的名稱。例如,如果您需要這個軟體啟動時是中文版,那麼這個Registry就應該填CHT 。其它以此類推。

由於,要顯示哪個語系是透過上述的Registry所決定的,因此,您需要在安裝程式中就正確的設定這個Registry的值。以便能夠正確的顯示正確的語系。

或許\您要問,難道沒有辦法自動判斷系統語系,然後進行切換嗎?有的!這就是我們下面所要介紹的,不過我們要介紹的是遠比自動判斷語系更厲害的,也就是動態切換語系。讓您的使用者,可以動態的切換所要顯示的語系。嗯!厲害吧!

好了,首先第一部要做的是把前面所提到C++ Builder 範例中的那個RichEdit目錄找出來。接著,仔細找找,看下面是不是有個叫做reinit.pas的檔案。有吧!沒有的話,就去跟別人Copy吧。

把這個檔案放到你的Project裡面來。然後在您要讓使用者動態切換的地方加上由這個檔案所產生的include檔案。例如:

#include "reinit.hpp"

OK! 第一次,你的系統裡面當然沒有這個檔案囉!請利用Compile Unit的方式產生他。

接著,我們就是要利用這個檔案所提供的函式來幫助我們達到動態切換語系的效果。首先,假設您希望的是能夠自動判斷系統語系然後進行切換,那麼找個合適的地方(通常是main function的開頭。)加入下面的程式碼:

if(LoadNewResourceModule(GetSystemDefaultLCID()))
{
ReinitializeForms();
}

這樣,便可正確的顯示語系囉。上面這幾行,其實就是C++ Builder自己偷偷在用的。所以,如果你有提供Resource DLL,而且沒有依照前面所說的在Registry中指定語系。那麼你的程式就會自己依照抓取系統語系了。

正 因如此,我們只需要把GetSystemDefaultLCID()換掉,換成特定的語系就可以囉。所以,現在要做的就是如何製作出給特定語系 LCID呢?首先,在C++ Builder的include目錄中,找到winnt.h 這個檔案。找到LANG_ 及SUBLANG_開頭的定義巨集。我們以法文為例。要做出法文的LCID,其作法如下:

    LCID lcid = (SUBLANG_FRENCH << 10) | LANG_FRENCH ;

這樣就可以了,很明顯LANG_ 是在定義國家的語言。那麼SUBLANG_呢?指的是地方語系。比如說,同樣是中文,在LANG_CHINESE之下,就有這些SUBLANG:

 #define SUBLANG_CHINESE_TRADITIONAL 0x01 // Chinese (Taiwan)
#define SUBLANG_CHINESE_SIMPLIFIED 0x02 // Chinese (PR China)
#define SUBLANG_CHINESE_HONGKONG 0x03 // Chinese (Hong Kong)
#define SUBLANG_CHINESE_SINGAPORE 0x04 // Chinese (Singapore)
#define SUBLANG_CHINESE_MACAU 0x05 // Chinese (Macau S.A.R.)

全部使用上面的計算方式,就可組合出您要的LCID。然後再把他餵給LoadNewResourceModule(),就可載入正確的Resource DLL了。前提是那個Resource DLL 檔案要存在喔。

到 此為止,您應該已經能夠掌握C++ Builder 中多國語言的作法囉。最後再提醒您一點,一旦您對於Form上面或是resourcestring有所新增,刪除,或是其它外觀上的變動。務必要用 Project->Languages->Update Resource DLLs 來更新您的Resource DLL。並且重新編譯出各語系的版本。

千萬不要讓自己重複一直做這個工作,否則您會很累。多國語言一定要等所有的畫面都確定之後,甚至是經 過相當程度測試之後再進行。也就是說,英文的 Release 版本沒出來前,別做多國語言化。否則,一定會浪費掉數倍的時間。無論任何理由都一定要堅持這點。否則,請直接叫公司給您一個專門做多國語言化的小組,然後 將Project 的時間延長一倍。

最後附帶提醒一點!當您將英文的稿送去給別人翻譯時,無論哪一國的語言,都請翻譯人員堅守一個原則,翻 譯過後的字串長度,不可超過原來英文的長度。除非那個字串的翻譯非常固定,例如像是Yes, No, OK, Cancel 等。翻譯人員如果跟你說做不到,那麼就換個翻譯。這點也很重要,因為單是『字譯』,一個句子長度可能遠超過原來的句子。這會對你的程式產生極大的困擾。如 果,為了這個原因,你要針對各語系調整你的畫面。那麼,請直接將Project 的時間再延長一倍,看看有沒有可能做完。務必跟翻譯人員堅持這點!請他用『意譯』的方式調整句子的長度。我們這裡所說的長度是畫面上看到的長度(單位為像 點),不是指一個句子有幾個字。

创建人: garylee
上次修改时间: 2005-02-27 06:17 PM

Trackback: http://blog.csdn.net/fanhongbin/archive/2006/01/15/580049.aspx

創作者介紹

邱小新の工作筆記

台南小新 發表在 痞客邦 PIXNET 留言(1) 人氣()


留言列表 (1)

發表留言
  • 阿毛
  • 小弟照著文章中的步驟 程式Compiler沒有 任何錯誤
    1. 加入了 ReConst.pas 並 #include "reconst.hpp"
    2. 加入了 reinit.pas 並 #include "reinit.hpp"
    3. New->Others->New->Resource DLL Wizard (設定了 CHT CHS JPN ENU)
    4. 在Workspace 做翻譯
    5. Project->Languages->Set Active設定預設語系 (ENU)
    但是卻一直沒有辦法看到 語言的切換 (簡 繁 日 英)
    想請教版上的前輩 指導一下 謝謝

    小弟目前猜測 是不是切換上沒設定好

    LCID lcid = (SUBLANG_ENGLISH_US << 10) | LANG_ENGLISH ;
    if(LoadNewResourceModule(lcid))
    {
    ReinitializeForms();
    }

  • 不好意思,這個資料是COPY別人的,我自己也沒有實驗過,你的問題我也不懂。

    台南小新 於 2010/12/23 10:00 回覆

找更多相關文章與討論