這是一個(gè)完整的指南,,展示了如何為一個(gè)Python應(yīng)用程序進(jìn)行國(guó)際化(i18n),。當(dāng)我在handroll項(xiàng)目中添加i18n時(shí),我很難找到支持其他語(yǔ)言的明確建議,。這是我個(gè)人的一點(diǎn)經(jīng)驗(yàn),,解釋了我是如何做到這一點(diǎn)的。 目錄:
概述要使代碼國(guó)際化,,您必須以一種特定的方式處理用戶(hù)文本字符串。所有的文本字符串都必須用一個(gè)特殊的函數(shù)調(diào)用來(lái)包裝,。這個(gè)特殊的函數(shù)將字符串標(biāo)記為需要翻譯的東西,。一旦所有的字符串都被標(biāo)記之后,i18n工具就可以掃描您的代碼,,生成一個(gè)包含所有內(nèi)容的主列表,。有了主列表,翻譯器就可以為每種需要的語(yǔ)言生成一個(gè)翻譯后的字符串列表,。翻譯后的字符串被添加回Python代碼中,,這些字符串都被打包成一個(gè)很好的翻譯后的最終產(chǎn)品。然后您可能就想測(cè)試一下,。 這牽扯到很多東西,,但是我將詳細(xì)解釋這個(gè)過(guò)程的每一部分,。出于本指南的目的,,我的所有示例代碼都將引用handroll包。如果這是您的Python代碼,,請(qǐng)用您的頂級(jí)Python包的名稱(chēng)替換handroll,。 標(biāo)記字符串我在概述中提到的特殊函數(shù)看起來(lái)像_('Hello World')。這個(gè)函數(shù)來(lái)自gettext模塊,。Python使用GNU gettext進(jìn)行翻譯,,所以讓我們看看在handroll/i18n.py中創(chuàng)建_函數(shù)的handroll代碼。 這一小段代碼使用locale目錄作為已翻譯字符串的源來(lái)創(chuàng)建一個(gè)翻譯對(duì)象,。您的locale目錄還不存在,,但它是您的應(yīng)用程序在運(yùn)行時(shí)查找譯文的地方。從translation對(duì)象中,,我為translation .gettext創(chuàng)建了一個(gè)_ 別名,。這個(gè)下劃線并不是特別特殊,但是,,它是Python社區(qū)所使用的這個(gè)函數(shù)的常見(jiàn)名稱(chēng),。 我希望現(xiàn)在這里有足夠的內(nèi)容來(lái)幫助我們?nèi)ダ斫膺\(yùn)行時(shí)將發(fā)生什么,。重要的是,“Hello World”就像一個(gè)鍵,。當(dāng)代碼執(zhí)行時(shí),,該“鍵”將用于查找本地化數(shù)據(jù),以找到一個(gè)匹配的翻譯,。_的返回值將是翻譯后的字符串,,如果翻譯缺失,返回值將是原始字符串,。 _ and format strings如果您為您的字串使用format,,您很快就會(huì)遇到一個(gè)奇怪的情況,那就是在哪里關(guān)閉_圓括號(hào),。這里有一個(gè)例子可以說(shuō)明這一點(diǎn),。 提取主列表使用_()將所有字符串標(biāo)記之后,現(xiàn)在是將它們提取到一個(gè)主列表中的時(shí)候了,。Gettext會(huì)將這個(gè)主列表引用為Portable Object Template (POT)文件,。為了生成該P(yáng)OT文件,我使用了一個(gè)名為Babel的工具,。Babel旨在幫助開(kāi)發(fā)人員以多種方式處理i18n問(wèn)題,。它有很多很酷的特性,但在本指南中,,我將重點(diǎn)介紹它對(duì)gettext的支持,。 Babel使用新命令擴(kuò)展了一個(gè)setup.py文件。(Python打包超出了本指南的范圍,,所以如果setup.py對(duì)您來(lái)說(shuō)是完全陌生的,,請(qǐng)查看《分發(fā)Python模塊》以獲得更多信息。 要生成一個(gè)POT文件,,請(qǐng)運(yùn)行python setup.py extract_messages,。您將需要一些類(lèi)似這樣的設(shè)置: 獲得其他語(yǔ)言的翻譯現(xiàn)在您已經(jīng)生成了一個(gè)POT文件,您已經(jīng)準(zhǔn)備好獲取您的字符串的翻譯版本了,。記住,,POT中的T是表示模板。翻譯后的文件稱(chēng)為PO文件,,翻譯人員使用該P(yáng)OT文件作為一個(gè)起點(diǎn)來(lái)生成他們的PO文件,。通過(guò)手動(dòng)創(chuàng)建PO文件來(lái)進(jìn)行翻譯是可能的,但是這很單調(diào),。此時(shí),,我轉(zhuǎn)向一個(gè)名為T(mén)ransifex的服務(wù)。 Transifex致力于使翻譯變得簡(jiǎn)單,。它對(duì)開(kāi)源項(xiàng)目是免費(fèi)的,,而且非常容易使用,。我為handroll設(shè)置了一個(gè)項(xiàng)目,并配置了Transifex來(lái)“監(jiān)視”P(pán)OT文件的變化,,這樣翻譯器就可以輕松地翻譯本項(xiàng)目中的所有字符串,。Transifex有一個(gè)API,可以讓我在需要的時(shí)候把PO文件拖回存儲(chǔ)庫(kù),。這個(gè)腳本太長(zhǎng)了,,不適合放在本文中,但是您可以在GitHub上查看它,。 此腳本所做的一件重要事情是將PO文件以一種特定的結(jié)構(gòu)存儲(chǔ)在locale目錄中,。Gettext期望一個(gè)類(lèi)似于<language>/LC_MESSAGES/handroll.po的順序。 打包在一起翻譯后的PO文件就緒后,,您就可以打包您的翻譯數(shù)據(jù)了,。設(shè)置過(guò)程所包括的額外數(shù)據(jù)在MANIFEST.in中。添加一個(gè)類(lèi)似下面的行,,以確保將所有l(wèi)ocale數(shù)據(jù)被放入包存檔中,。 recursive-include handroll/locale * 到目前為止,為了解釋清楚,,我撒了個(gè)小謊,。Gettext并不直接使用PO文件來(lái)查找譯文。事實(shí)上,,PO文件必須被編譯成一個(gè)二進(jìn)制機(jī)器對(duì)象(MO)文件(為了獲得更快的速度),。我們可以再次向Babel求助。Babel有一個(gè)compile_catalog命令,,可以將PO編譯成MO,。您可以使用python setup.py compile_catalog來(lái)運(yùn)行它。 它需要如下設(shè)置: 因?yàn)闆](méi)有MO文件,,譯文就無(wú)法起作用,,所以我擴(kuò)展了setup.py,,以便sdist命令將始終運(yùn)行compile_catalog,。 如果您要這樣做,請(qǐng)不要忘記在您的setup調(diào)用中添加cmdclass={'sdist': Sdist} 和 setup_requires=['Babel'],。 此時(shí),,運(yùn)行python setup.py sdist應(yīng)該會(huì)為您的項(xiàng)目創(chuàng)建一個(gè)帶有翻譯的tarball。您幾乎就完成了! 測(cè)試該包測(cè)試翻譯并不容易,。如果您多做一點(diǎn)此測(cè)試,,您就會(huì)知道來(lái)自不同文化的人都可以享受您的軟件。但是翻譯測(cè)試并不容易,,因?yàn)槟枰\(yùn)行代碼中的每個(gè)字符串的測(cè)試,。對(duì)于handroll來(lái)說(shuō),,那意味著我必須達(dá)到100%的測(cè)試覆蓋率,才能得到那些非常奇怪的邊角情況,。 測(cè)試的原因是因?yàn)椴徽_翻譯的字符串會(huì)破壞您的代碼,。如果您有一個(gè)像_('Hello {name}!').format(name='Johnny')這樣的格式字符串,并且翻譯人員犯了一個(gè)像'?Hola {nombre}!'這樣的錯(cuò)誤!,,然后該代碼對(duì)西班牙用戶(hù)來(lái)說(shuō)就會(huì)崩潰,。 要測(cè)試這些字符串,您需要兩樣?xùn)|西:MO文件和 LANGUAGE環(huán)境變量,。我們假設(shè)您使用的是nose運(yùn)行器,。要測(cè)試您的西班牙語(yǔ)支持,您可以運(yùn)行: 在您使用的任何持續(xù)集成系統(tǒng)中,,對(duì)您支持的每種語(yǔ)言運(yùn)行您的單元測(cè)試,,會(huì)給您一些信心,讓您相信您的翻譯沒(méi)有破壞軟件,。handroll tox.ini提供了一個(gè)可以比較的例子,。Tox對(duì)這類(lèi)東西來(lái)說(shuō)是非常棒的。 問(wèn)題,?在本指南中,,我盡我最大的努力記錄了我為使我的項(xiàng)目國(guó)際化所做的一切。我希望所有的具體細(xì)節(jié)都能幫助您了解如何翻譯您自己的項(xiàng)目,。如果有什么東西丟了或損壞了,,請(qǐng)及時(shí)告訴我,我很樂(lè)意更新此帖,。
|
|