很久以前就想寫(xiě)這篇blog,系統(tǒng)的介紹一下偶是如何使用gettext給blogwind做多語(yǔ)言界面的……
很不喜歡.net內(nèi)置的多語(yǔ)言解決方案……因?yàn)椋褂脁ml……編輯xml是一件很痛苦的事情……我也不想給每個(gè)頁(yè)面弄一堆resouce文件……光看著這些資源文件我就很暈……
偶是從django里面知道有g(shù)ettext這套在開(kāi)源軟件中廣為使用的程序多語(yǔ)言解決方案的……
最喜歡它的地方是它默認(rèn)直接使用英文原文作為字符串的鍵值……而不是像.net默認(rèn)的那樣,給所有的字符串加上一個(gè)編號(hào)……而當(dāng)翻譯不存在的時(shí)候,.net是會(huì)拋出異常,而gettext是會(huì)返回原文……這樣子,我可以部分給網(wǎng)站制作一個(gè)語(yǔ)言版本……而不需要一步到位……
--------------------------------------------
gettext的翻譯文件為.po文件……其實(shí)就是純文本文件……其內(nèi)容類(lèi)似:
#: d:/web/blogwind/default.aspx:87
msgid "loading..."
msgstr "讀取中..."
第一行代表偶需要翻譯的字符串在程序中的位置……msgid則是需要翻譯的字符……msgstr則是翻譯的結(jié)果……很簡(jiǎn)單……
偶在做網(wǎng)站的時(shí)候,把所有需要翻譯的字符串都使用一個(gè)函數(shù)包涵起來(lái)……比方說(shuō):
    ph.g("編寫(xiě)網(wǎng)志")
然后,自己寫(xiě)了個(gè)小python程序去搜索偶網(wǎng)頁(yè)程序中所有的 ph.g("xxxxx"),并生成/更新現(xiàn)有的po文件……
可以用的poedit來(lái)編輯po文件……非常方便……因?yàn)樽⑨屩锌梢苑糯g的字符串在源程序中的位置,偶翻譯的時(shí)候還隨時(shí)可以查閱源程序,看看究竟是在什么地方用到這個(gè)詞句……以保證遇到一詞多譯時(shí)能夠選擇正確的一個(gè)翻譯……
編輯完po文件之后,便需要使用gettext包中msgfmt這個(gè)小程序把po文件直接編譯為.net使用的資源dll……命令類(lèi)似:
msgfmt --csharp -r blogwind -l zh-chs -d . blogwind.po
--csharp 是指定輸出為.net的dll……呃……需要指定這點(diǎn),是因?yàn)樗€可以輸出為java / tcl /qt有幾個(gè).net resource文件等格式……對(duì)于.net的支持是后來(lái)新加的……如果報(bào)錯(cuò),確定你使用的是0.13.1版或者更新的gettext庫(kù)……
-r blogwind 是指dll的資源名稱為blogwind
-l zh-chs 則是語(yǔ)系
最后的則是待編譯的po文件名了……
----------------------------------------
gettext有c#的"wrapper"……源碼在gnuwin32里面就有……它這個(gè)wrapper……wrap的是.net的system.resources類(lèi)……使它符合gettext找不到翻譯便返回原文的做法而已……順便再搞定一下資源緩存之類(lèi)的……一共也就幾百行代碼……
不過(guò),它這個(gè)版本似乎是為桌面程序設(shè)計(jì)的……要在網(wǎng)頁(yè)中使用,還需要做點(diǎn)小修改……它讀取那些msgfmt生成的dll時(shí),使用的是:assembly.loadfrom(.....)
這意味著它每次只是讀一個(gè)dll……對(duì)于單一用戶的桌面程序來(lái)說(shuō),每次使用一種語(yǔ)言是正常……可是,對(duì)于網(wǎng)站來(lái)說(shuō),偶需要同時(shí)提供不用的語(yǔ)言界面給不同的用戶……所以……需要改成assembly.loadassembly(.....)
------------------------------------------
嗯,到了最后,便是調(diào)用了……注意,下面出現(xiàn)的代碼都是偶自己寫(xiě)的……大家完全沒(méi)有必要照偶的方式做……
imports gnu.gettext
public class lh
  'lh = language helper 
  public shared catalog as gettextresourcemanager
  public shared sub init(byval name as string, byval dictpath as string)
    catalog = new gettextresourcemanager(name, dictpath)
  end sub
end class
在global.asax的application start中調(diào)用一下:
        lh.initcate("blogwind", server.mappath("langs"))
恩,這樣子,它便會(huì)去網(wǎng)站根目錄下langs目錄尋找它需要的各種語(yǔ)言dll了……當(dāng)然,blogwind這個(gè)類(lèi)名以及l(fā)angs這個(gè)目錄可以隨意改成別的……
最先偶寫(xiě)到的那個(gè)ph.g(..)函數(shù)其實(shí)是:
  public function g(byval word as string) as string
    dim cu as new system.globalization.cultureinfo(langs.getlangstring(me.lang))
    return lh.catalog.getstring(word, cu)
  end function
ph是pagehelper……呃……我知道,我起類(lèi)名很規(guī)范……總之,我在pagehelper里面還自己保存了當(dāng)前瀏覽者的語(yǔ)言信息放在langs / pagehelper里面……通過(guò):
    dim cu as new system.globalization.cultureinfo(langs.getlangstring(me.lang))
來(lái)獲得相應(yīng)的cultureinfo,再傳給gettext……
比方說(shuō),語(yǔ)系是zh-chs,待尋找翻譯的word是“編寫(xiě)網(wǎng)志”,gettext便會(huì)去webroot/langs/zh-chs目錄中尋找blogwind.resources.dll這文件……找到了,便load它,再尋找"編寫(xiě)網(wǎng)志"等等……
因?yàn)檫@些翻譯的dll是動(dòng)態(tài)讀取的……
其實(shí)完全可以做到讓程序在app_start中自動(dòng)去遍歷langs中的子目錄,看看都有哪些語(yǔ)系……然后自動(dòng)生成一個(gè)菜單在網(wǎng)頁(yè)中供用戶選擇……以后添加語(yǔ)言,其實(shí)就簡(jiǎn)單到往這個(gè)目錄中建立目錄扔dll了……程序本身,絲毫不需要做任何修改……
-----------------
當(dāng)然,上面說(shuō)的,僅僅是最簡(jiǎn)單的字符串翻譯……網(wǎng)頁(yè)中還有圖片……語(yǔ)言相關(guān)的css等等細(xì)節(jié)……而且,實(shí)際上,我在使用gettext的時(shí)候還自己寫(xiě)了個(gè)小python程序(幾十行的樣子)去生成/維護(hù)po文件……若po文件不能自動(dòng)生成、維護(hù)更新的話,管理起來(lái)是很麻煩的……
上面的說(shuō)明也是非常簡(jiǎn)略的……僅僅只是說(shuō)明要給asp.net網(wǎng)站提供多語(yǔ)言界面……除了使用官方鼓吹的資源文件方式外,還可以有別的選擇……而對(duì)于gettext這個(gè)選擇,偶覺(jué)得更加優(yōu)雅些而已…… www.blogwind.com 的多語(yǔ)言界面,便是使用上述的方式實(shí)現(xiàn)的……
至于哪里下載gettext以及msgfmt等工具,wrapper中的那行修改具體是在哪里等問(wèn)題,就請(qǐng)不要來(lái)問(wèn)偶了……
| 
 
 | 
新聞熱點(diǎn)
疑難解答
圖片精選