使用gettext技术为ASP.NET网站实现国际化支持
不知道有多少人对这个题目感兴趣,因为最近在做一个网站玩玩,有点闲心给网站加了国际化支持。虽然ASP.NET已经有ResourceManager这个类,并且有标签实现国际化的支持了,但是它的问题是,ResourceManager对每一个需要翻译的句子都要求有一个键(Key):
1.
要先创建一个.resx文件,在Visual
Studio里,有一个工具编辑这个.resx文件。
2.
对每一个需要翻译的句子,添加一个键值对。
3.
然后在代码里,使用ResourceManager或者<%#这个标签,通过定义好的键来告诉ASP.NET在运行的时候查找正确的翻译文本。
太麻烦了,不知道大家有什么其它好的方法,我使用的方法是从unix gettext那边借用过来的理念。
理念
Gettext的理念很简单,文本翻译吗,说白了就是把一句话翻译成另外一句话嘛,这个要翻译的句子,本身就可以当做检索要用的关键字,何必要再新建一个另外的关键字呢?gettext的方式很简单:
1.
在源代码里,你可以编写一个特殊的函数执行翻译,这个函数只接受一个参数,就是要翻译的文本。
2.
使用一个辅助程序xgettext扫描源代码的文本,将所有待翻译的文本都找出来,保存到一个文件里,一般来说,这个文件叫做po文件。
3.
因为ASP.NET程序不支持po文件,再使用一个辅助程序msgfmt将po文件转换成ASP.NET支持的.resources文件。
这个方法的优点在于:
1.
你在编写程序的时候,不用为需要翻译的句子,定义一个新的关键字——这个关键字一般都比较难理解,也不好取名。在维护代码的时候很麻烦——因为你需要不停地在.resx编辑器和cs文件之间切换。
2.
不知道怎么搞的,很难找到可以编辑.resx文件的工具,而gettext生成的po文件是普通的文本文件,而且格式非常简单。这样在翻译的时候,就很方便了。
做法
比如写了一个ASP.NET MVC程序,当然窗体(Web Form)形式的程序理念也是一样的,
1.
写一个控制器和视图页的基类,里面都有一个执行翻译的函数T:
public class G18nController
: Controller { public
CultureInfo Culture { get; set; } public
string T(string
message) { var
obj = HttpContext.GetGlobalResourceObject("website",
message, Culture); var
translated = obj == null ? null : obj.ToString(); if
(string.IsNullOrEmpty(translated)) return
message; else return
translated; } } public abstract class G18nWebViewPage<U> : WebViewPage<U> { public CultureInfo Culture { get;
set; } public
string T(string
message) { var
obj = HttpContext.GetGlobalResourceObject("website",
message, Culture); var
translated = obj == null ? null : obj.ToString(); if
(string.IsNullOrEmpty(translated)) return
message; else return
translated; } } |
上面的Culture属性,可以从Request.Headers["Accept-Language"]属性取得。
2.
在代码里,针对每个要翻译的句子,直接调用这个T函数好了:
throw new
ArgumentException(string.Format(T("找不到ID为{0}的项目!"), id));
3.
程序写好后,要开始翻译,调用gettext程序将所有要翻译的句子找出来,保存到指定的po文件里。可以在http://gnuwin32.sourceforge.net/packages/gettext.htm这个网页下载gettext。
但是悲剧的是,gettext好像要求主语言是英文,对中文字符串支持的不是很好。所以我就用C#自己写了一个gettext,你可以在本文的附件里下载它,命令的格式是:
Zgettext
-k T -i 源代码路径名 -o 输出的po文件名
Zgettext
-k T -f 源代码路径列表文件 -o 输出的po文件名
比如:
Zgettext
-k T -i AccountController.cs -o test.po
4.
生成的po文件格式其实非常简单易懂:
1.
#: C:\workspace\Views\Role\Edit.cshtml:9 2.
msgid "管理用户组" 3.
msgstr "" 4.
5.
#: C:\workspace\Views\Role\Edit.cshtml:23 6.
msgid "用户组[{0}]的权限" 7. msgstr "" |
Msgid就是要翻译的句子,msgstr就是翻译好的句子。
5.
完成翻译后,使用一个辅助程序msgfmt将翻译好的po文件转换成ASP.NET支持的格式。因为原始的gettext程序包里的msgfmt.exe好像不能生成ASP.NET识别的.resources文件,所以 我也写了一个msgfmt程序完成这个工作——在本文的附件里可以下载到,命令格式是:
Msgfmt
-o 输出的resource文件路径 -i
输入的po文件路径
例如:
Msgfmt
-o website.en-US.resources -i website.po
注意:输出的resource文件名,必须与你在第一步里,使用HttpContext.GetGlobalResourceObject函数的第一个参数相同。
6.
我写了一个小的批处理,将3、4、5步结合在一起执行:
1. pushd src 2. del /F source.lst 3. dir /s /b src\*.cs >> source.lst 4. dir /s /b src\*.cshtml >> source.lst 5. tools\zgettext\zgettext\bin\Debug\zgettext.exe
-k T -f source.lst -o glob\website.po 6. tools\zgettext\msgfmt\bin\Debug\msgfmt.exe
-o src\App_GlobalResources\website.resources -i glob\ website.po 7. popd |
希望对你有点帮助。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库