天天看點

建構面向全世界的網站——gettext支援多種語言

原文位址:http://book.51cto.com/art/200905/123469.htm

建構面向全世界的網站

Web的出現使人們之間的交流簡單得不可思議,通過一個Internet連接配接和一個Web浏覽器,你就可以與任何人通信,而此時此刻也許他們正坐在莫斯科紅場旁的一家咖啡店裡,或者俄亥俄州的一個農舍裡,也可能在上海一座摩天大樓的某個房間裡,或者是以色列的一間教室裡。不過對此還有一個小問題:在全部Internet群眾中,隻有大約29%的人講英語 。其他人可能講中文、日語、西班牙語、德語、法語,或者是另外幾十種語言之一。是以,如果你确實希望擁有世界各地的通路者,建立網站時就應考慮不僅要符合通路者的本地語言,還要遵循一定的标準(最重要的标準包括貨币、日期、數字和時間)。

不過建立全球使用的軟體很困難,原因很明顯:必須有适當的資源來翻譯網站文本。不僅如此,還有另外一個原因,需要考慮以一種合适的方式在現有的應用程式中內建語言和标準的修改,進而防止混亂。本章将幫助你解決第二個問題。

注解 PHP 6的關鍵特性之一就是對Unicode(http://www.unicode.org/)的内置支援,這個标準能大大降低建立用于多種平台和支援多種語言的應用程式和網站時所帶來的開銷。盡管本書并不讨論Unicode和PHP的Unicode實作,不過如果可全球通路的應用程式在你的項目中是一個重要組成部分,就應該多了解一些這方面的内容。

支援本地語言和标準分為兩步,要求開發人員分别完成網站的國際化(internationalize)和本地化(localize)。網站國際化是指對網站做必要的修改,以便實作本地化;本地化則是更新網站來支援具體的語言和特性。因為程式員很懶,你可能經常看到國際化(internationalization)寫作i18n,本地化(localization)寫作l10n。

(上面這段對國際化與本地化說得比較模糊,參考以下:

國際化是指在設計軟體時,将軟體與特定語言及地區脫鈎的過程。當軟體被移植到不同的語言及地區時,軟體本身不用做内部工程上的改變或修正。本地化則是指當移植軟體時,加上與特定區域設定有關的資訊和翻譯檔案的過程。 國際化和本地化之間的差別雖然微妙,但卻很重要。國際化意味着産品有适用于任何地方的“潛力”;本地化則是為了更适合于“特定”地方的使用,而另外增添的特色。用一項産品來說,國際化隻需做一次,但本地化則要針對不同的區域各做一次。 這兩者之間是互補的,并且兩者合起來才能讓一個系統适用于各地。

本節将介紹完成網站國際化和本地化時可以考慮的一種方法。

23.1 用gettext翻譯網站

gettext(http://www.gnu.org/software/gettext/)是自由軟體基金會(Free Software Foundation)建立和維護的衆多優秀項目之一,包括許多可用于實作軟體國際化和本地化的實用工具。多年來,它已經成為不計其數應用程式和網站實作内容翻譯的實際标準解決方案。PHP通過一個同名擴充包與gettext互動,這說明你需要下載下傳gettext實用工具,并在系統上安裝。如果運作的是Windows平台,可以從http://gnuwin32.sourceforge.net/下載下傳,記住一定要更新PATH環境變量以指向這個安裝目錄。

由于PHP的gettext擴充在預設情況下并不啟用,可能還需要重新配置PHP。如果運作的是Linux,可以指定--enable-gettext選項重新建構PHP來啟用這個擴充。在Windows上,所要做的隻是去除php.ini檔案中php_gettext.dll代碼行的注釋。關于配置PHP的更多資訊請參見第2章。

本節餘下部分将帶領你完成所有必要的步驟,進而使用PHP和gettext來建立一個多語言網站。

23.1.1 第一步:更新網站腳本

gettext必須能夠識别出你希望翻譯哪些字元串。為此所有可翻譯的輸出都要通過gettext()函數傳遞。每次遇到gettext()時,PHP會查找特定語言的本地化庫(有關内容見第二步),并将傳入函數的字元串與相應的翻譯比對。由于先前調用了setlocale()以及bindtextdomain()和textdomain(),是以腳本知道擷取哪個翻譯。setlocale()函數告訴PHP和gettext需要遵循哪個語言和國家的約定,bindtextdomain()和textdomain()則告訴PHP在哪裡查找翻譯檔案。

要特别注意語言和國家的記法,因為不能向setlocale()簡單地傳入一個語言名(如Italian),而需要選擇一個預定義的語言和國家(地區)代碼組合,這些組合由國際标準組織(International Standards Organization,ISO)定義。例如,你可能希望本地化為英語,但是需要使用美國的數字和時間/日期格式。在這種情況下,就要向setlocale()傳入en_US,而不是傳入en_GB。因為英國英語和美國英語之間的差别微乎其微,主要是一些拼法上的不同,可能隻需要維護少許有差别的字元串,如果傳入函數的字元串在庫中未找到,則讓gettext()預設為原來的字元串。

注解 許多網站上都可以找到ISO定義的語言和國家(地區)代碼;隻需搜尋關鍵字ISO, country codes(國家(地區)代碼)和language codes(語言代碼)。表23-1提供了一個常用的代碼組合的清單。

表23-1 常用國家(地區)和語言代碼組合

組合 本地化環境 組合 本地化環境
pt_BR 巴西 it_IT 意大利
fr_FR 法國 es_MX 墨西哥
de_DE 德國 es_ES 西班牙
en_GB 英國 en_US 美國
he_IL 以色列

代碼清單23-1給出了一個簡單的例子,将字元串"Choose a password:"翻譯為意大利語。

代碼清單23-1 使用gettext()支援多種語言

建構面向全世界的網站——gettext支援多種語言

當然,代碼清單23-1若要正常工作,還需要建立前面提到的翻譯庫,并把字元串翻譯為指定的語言。你将了解如何在第一步、第二步和第四步完成這些工作。

第二步:建立本地化庫

接下來需要建立一個存放翻譯檔案的本地化庫。應當為每個語言/國家(地區)代碼組合分别指定一個目錄,在這個目錄中還需要建立另一個名為LC_MESSAGES的目錄。是以,舉個例子,如果打算将網站本地化為支援英語(預設語言)、德語、意大利語和西班牙語,目錄結構将如下所示:

建構面向全世界的網站——gettext支援多種語言

可以把這個目錄放在你喜歡的任何位置,因為bindtextdomain()函數(代碼清單23-1顯示了這個函數的具體使用)會負責将這個路徑映射到一個預定義域名。

第三步:建立翻譯檔案

接下來需要從PHP腳本抽取可翻譯的字元串。可以用xgettext指令來完成,這是一個與gettext捆綁的實用工具。xgettext提供了豐富的選項,執行xgettext時通過指定--help選項可以了解各個選項的更多資訊。執行以下指令将使xgettext檢查目前目錄中所有擴充名為.php的檔案,并生成一個檔案,其中包含需要翻譯的字元串:

建構面向全世界的網站——gettext支援多種語言

指定-n選項時,會在輸出檔案中的各個字元串前面包含檔案名和行号。預設情況下,輸出檔案名為messages.po,不過也可以使用--default-domain=FILENAME選項改變輸出檔案名。以下是一個示例輸出檔案:

建構面向全世界的網站——gettext支援多種語言
建構面向全世界的網站——gettext支援多種語言

把這個檔案複制到适當的本地化目錄,繼續下一步。

第四步:翻譯文本

打開你要翻譯的語言目錄中的messages.po檔案,通過完成與抽取字元串對應的空msgstr項來翻譯這些字元串。然後将用全大寫字母表示的占位符替換為你的應用程式的相關資訊。要特别注意CHARSET占位符,因為你使用的具體值将直接影響gettext最終翻譯應用程式的能力。需要将CHARSET替換為用于表示所翻譯字元串的适當字元集的名字。例如,字元集ISO-8859-1用于表示使用拉丁文字母的語言,包括英語、德語、意大利語和西班牙語。Windows-1251用于表示使用斯拉夫語字母的語言,包括俄語。這裡并不打算逐一介紹數不勝數的各種字元集,建議從http://en.wikipedia.org/wiki/ Character_encoding檢視最全面的Wikipedia總結。

提示 要用某種本地語言寫出道地的文本确實很困難,是以如果想把你的網站翻譯成另一種語言,最好找一位擅長這種語言的人提供幫助。專業的翻譯服務可能成本很高,是以可以考慮聯系當地的大學,通常大學裡會有很多外國學生,他們會很歡迎有這種機會來獲得一些經驗,而且費用往往相當便宜。

第五步:生成二進制檔案

之後一個必要的步驟是生成messages.po檔案的二進制版本,gettext将使用這些二進制檔案。這個工作使用msgfmt指令完成。切換到适當的語言目錄,并執行以下指令:

建構面向全世界的網站——gettext支援多種語言

執行這個指令将生成名為messages.mo的檔案,這就是gettext最終用來完成翻譯的檔案。類似于xgettext,msgfmt也通過選項提供了豐富的特性。執行msgfmt --help可以了解這個工具提供了哪些選項。