很久以前就想寫這篇blog,系統的介紹一下偶是如何使用Gettext給blogwind做多語言界面的……
很不喜歡.Net內置的多語言解決方案……因為,它使用xml……編輯XML是一件很痛苦的事情……我也不想給每個頁面弄一堆resouce文件……光看著這些資源文件我就很暈……
偶是從Django裡面知道有Gettext這套在開源軟件中廣為使用的程序多語言解決方案的……
最喜歡它的地方是它默認直接使用英文原文作為字符串的鍵值……而不是像.net默認的那樣,給所有的字符串加上一個編號……而當翻譯不存在的時候,.Net是會拋出異常,而Gettext是會返回原文……這樣子,我可以部分給網站制作一個語言版本……而不需要一步到位……
--------------------------------------------
Gettext的翻譯文件為.po文件……其實就是純文本文件……其內容類似:
#: D:/web/blogwind/default.ASPx:87
msgid "Loading..."
msgstr "讀取中..."
第一行代表偶需要翻譯的字符串在程序中的位置……msgid則是需要翻譯的字符……msgstr則是翻譯的結果……很簡單……
偶在做網站的時候,把所有需要翻譯的字符串都使用一個函數包涵起來……比方說:
ph.g("編寫網志")
然後,自己寫了個小Python程序去搜索偶網頁程序中所有的 ph.g("XXXXX"),並生成/更新現有的po文件……
可以用的PoEdit來編輯po文件……非常方便……因為注釋中可以放待翻譯的字符串在源程序中的位置,偶翻譯的時候還隨時可以查閱源程序,看看究竟是在什麼地方用到這個詞句……以保證遇到一詞多譯時能夠選擇正確的一個翻譯……
編輯完po文件之後,便需要使用Gettext包中msgfmt這個小程序把po文件直接編譯為.Net使用的資源dll……命令類似:
msgfmt --csharp -r blogwind -l zh-CHS -d . blogwind.po
--csharp 是指定輸出為.net的dll……呃……需要指定這點,是因為它還可以輸出為Java / tcl /qt有幾個.net resource文件等格式……對於.Net的支持是後來新加的……如果報錯,確定你使用的是0.13.1版或者更新的Gettext庫……
-r blogwind 是指dll的資源名稱為blogwind
-l zh-CHS 則是語系
最後的則是待編譯的po文件名了……
----------------------------------------
Gettext有C#的"wrapper"……源碼在GnuWin32裡面就有……它這個wrapper……wrap的是.Net的System.Resources類……使它符合Gettext找不到翻譯便返回原文的做法而已……順便再搞定一下資源緩存之類的……一共也就幾百行代碼……
不過,它這個版本似乎是為桌面程序設計的……要在網頁中使用,還需要做點小修改……它讀取那些msgfmt生成的dll時,使用的是:Assembly.LoadFrom(.....)
這意味著它每次只是讀一個dll……對於單一用戶的桌面程序來說,每次使用一種語言是正常……可是,對於網站來說,偶需要同時提供不用的語言界面給不同的用戶……所以……需要改成Assembly.LoadAssembly(.....)
------------------------------------------
嗯,到了最後,便是調用了……注意,下面出現的代碼都是偶自己寫的……大家完全沒有必要照偶的方式做……
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中調用一下:
lh.initcate("blogwind", Server.MapPath("langs"))
恩,這樣子,它便會去網站根目錄下langs目錄尋找它需要的各種語言dll了……當然,blogwind這個類名以及langs這個目錄可以隨意改成別的……
最先偶寫到的那個ph.g(..)函數其實是:
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……呃……我知道,我起類名很規范……總之,我在pagehelper裡面還自己保存了當前浏覽者的語言信息放在langs / pagehelper裡面……通過:
Dim cu As New System.Globalization.CultureInfo(langs.getLangString(Me.lang))
來獲得相應的CultureInfo,再傳給Gettext……
比方說,語系是zh-CHS,待尋找翻譯的Word是“編寫網志”,Gettext便會去webroot/langs/zh-CHS目錄中尋找blogwind.resources.dll這文件……找到了,便Load它,再尋找"編寫網志"等等……
因為這些翻譯的dll是動態讀取的……
其實完全可以做到讓程序在app_start中自動去遍歷langs中的子目錄,看看都有哪些語系……然後自動生成一個菜單在網頁中供用戶選擇……以後添加語言,其實就簡單到往這個目錄中建立目錄扔dll了……程序本身,絲毫不需要做任何修改……
-----------------
當然,上面說的,僅僅是最簡單的字符串翻譯……網頁中還有圖片……語言相關的CSS等等細節……而且,實際上,我在使用Gettext的時候還自己寫了個小Python程序(幾十行的樣子)去生成/維護po文件……若po文件不能自動生成、維護更新的話,管理起來是很麻煩的……
上面的說明也是非常簡略的……僅僅只是說明要給ASP.Net網站提供多語言界面……除了使用官方鼓吹的資源文件方式外,還可以有別的選擇……而對於Gettext這個選擇,偶覺得更加優雅些而已…… www.blogwind.com 的多語言界面,便是使用上述的方式實現的……
至於哪裡下載Gettext以及msgfmt等工具,wrapper中的那行修改具體是在哪裡等問題,就請不要來問偶了……
這裡,有偶修改重新編譯過後的版本:
http://www.cnblogs.com/Files/wuvist/GetText.zip