您的位置:首页 > 其它

巧用Reponse.Filter实现多语言功能

2008-11-26 19:57 323 查看
source:/article/4922425.html
巧用Reponse.Filter实现多语言功能

对于有跨国业务的web系统来说,一般都需要提供多语言功能。然而在众多多语言方案里,如.net自带的Resource方式,都会在程序开发时增加程序员的额外负担,不易开发:

1.各种不同的地方实现多语言,如aspx的control绑定,js脚本,cs代码,procedure里的提示信息等,这些多语言实现方式各不相同,加重了开发难度。

2.在要实现多语言的代码中都要与获取语系文字的代码进行强耦合,不方便扩展和维护。如.net的Resource方式某个label实现多语言:
lblName.Text = Resources.Strings.name;

3.开发和维护程序时,程序员都必须同时打开source code和多语言资源文件,特别是在多人开发时,共享一个多语言文件,且对于共享的文字实难处理和同步。

以上这些只是简单地罗列了一下传统多语言开发时的困扰,那有什么方式解决这些问题,轻松实现多语言功能呢?

记得有人说过web编程,实际上就是字符串处理。

为什么呢?因为web,实际上就是Request和Response,而Request和Response就是字符串。在我们各种程序里,最终输出到Browser的都是html格式的字符串,因此,只要我们统一在程序最后一步输出html格式时,能够识别其中需要进行多语言转换的文字,将将其替换为当前设定的语言版本的文字就可以了。

在asp.net中,因为有一个Response.Filter的属性,让这一切变得很简单。
什么是Response.Filter?
简单地说,就是在经过层层转换后,最终asp.net要输出html,在输出的过程中,是将html放到一个管道(pipeline)里,然后在管道那头取出要发往客户端的html进行Response,asp.net提供Response.Filter属性,让你可以对经过的html进行相应的转换。

因此只要将多语言转换功能放在这里,并识别“中文”,将其转换为user设定的相应语系就可以完成了。

1. 首先要实现一个多语言Stream:
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;

public class HttpMulLangStream : Stream
{
private Stream strSink;
private long lngPosition;

public HttpMulLangStream(Stream sink)
{
strSink = sink;
}

// The following members of Stream must be overriden.
public override bool CanRead
{
get { return true; }
}

public override bool CanSeek
{
get { return true; }
}

public override bool CanWrite
{
get { return true; }
}

public override long Length
{
get { return 0; }
}

public override long Position
{
get { return lngPosition; }
set { lngPosition = value; }
}

public override long Seek(long offset, System.IO.SeekOrigin direction)
{
return strSink.Seek(offset, direction);
}

public override void SetLength(long length)
{
strSink.SetLength(length);
}

public override void Close()
{
strSink.Close();
}

public override void Flush()
{
strSink.Flush();
}

public override int Read(byte[] buffer, int offset, int count)
{
return strSink.Read(buffer, offset, count);
}

// 关键代码.
public override void Write(byte[] buffer, int offset, int count)
{
//读出写的文字
byte[] data = new byte[count];
Buffer.BlockCopy(buffer, offset, data, 0, count);
string inputstring = Encoding.UTF8.GetString(data);

//找出汉字(对于复杂一些的,可以设定固定识别方式,如使用这些标记识别[@多语言文字],并按设定的语言作转换
inputstring = Regex.Replace(inputstring, "[/u3000-/u9fff]+", new MatchEvaluator(capText));

//将翻译后的语言写入response
byte[] newdata = Encoding.UTF8.GetBytes(inputstring);
strSink.Write(newdata, 0, newdata.Length);
}

private string capText(Match m)
{
//简单的替换,实际开发过程可以从xml文件,Resouce资源,进行缓存等等替换策略
string x = m.Value;
if (x.Equals("账号"))
return "Account";
else if (x.Equals("登录"))
return "Login";
else if (x.Equals("你的名字"))
return "Your Name";
//如果没找到,原样返回
return x;
}
}

2. 其次要在Global.asax中设定Response.Filter
<%@ Application Language="C#" %>
<%@ Import Namespace="System.IO" %>

<script runat="server">
//在每次Request之前设定好Response.Filter属性
void Application_PreRequestHandlerExecute(object sender, EventArgs e)
{
Response.Filter = new HttpMulLangStream(Response.Filter);
}
</script>

3. 测试代码 test.aspx
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Login.aspx.cs" Inherits="Login" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>未命名页面</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="Label1" runat="server" Text="账号"></asp:Label>
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:Button ID="Button1" runat="server" Text="登录" /></div>
</form>
</body>
</html>

使用这种方式对于程序员开发系统基本上是零侵入,程序员基本感受不到多语言功能增加需要的额外工作。

上面只是一个简单的Demo,实际运用中,还有几点需要说明:
1.识别:
不能靠单纯地识别汉字,来进行转换。因为在有的地方,确实不需要进行转换,如数据内容。比如某个user的姓名叫张三,不管在英文还是中文,都显示张三。这时候就需要对程序开发加入一点侵入,如程序员在开发时,需将多语言转换的字符串作特别标记,如[@姓名:],这样在识别时,就以[@.*]来作为识别方式。

2.转换:
转换是这种方式最成功的地方,一是效率,可以利用static或cache等方式缓存资源,提高性能。二就是,对于没有做翻译的地方,可以原样输出。这样有几个好处,可以先开发程序,最后增加资源文件来进行多语言转换。二就是有的确实不需要多语言转换时,可以不提供资源文件,它就不会转,而不需要额外写程序去指定。

3.通用性:
对于一个多语言方案来说,通用性比较重要,有的地方需要对单独的js文件进行多语言转换,这时就要将js文件在IIS中加入到asp.net引擎处理。而更简单的方式就是直接把js文件的后缀名改为aspx。
至于从DB中的程序过来的字符串,以及嵌入在aspx中的script,因为都最终会通过aspx输出到页面上,所以不用额外处理。

4.重用:
透过asp.net的HttpModule特性,将多语言实现方案进行单独封装,然后在web.config中配置就可动态装载多语言功能了。

posted on 2008-11-26 10:24 Kevin Zou 阅读(1174) 评论(23) 编辑 收藏 网摘 所属分类: asp.net


Feedback

#1楼 2008-11-26 10:40 KerryJiang @ SH [未注册用户]
替换个登陆页面还可行,文字一多,要替换的地方有几百个,你怎么办?
回复 引用

#2楼 2008-11-26 10:41 Jeffrey Zhao
似乎性能会是个大问题
回复 引用 查看

#3楼 2008-11-26 10:44 Wendy.li
是啊,要替换的地方多了,就麻烦了,而且还容易漏掉。
回复 引用 查看

#4楼 2008-11-26 11:00 xjb
这个方法如果应付简单的功能好些,如果一个庞大的系统,性能和工作量都成问题了
回复 引用 查看

#5楼 [楼主] 2008-11-26 11:02 Kevin Zou
string x = m.Value;

if (x.Equals("账号"))

return "Account";

else if (x.Equals("登录"))

return "Login";

else if (x.Equals("你的名字"))

return "Your Name";

//如果没找到,原样返回

return x;
-----------------------
是指這些代碼嗎?
呵呵,隻是簡單地模擬,實際上肯定是利用Dictionary或Array來完成。這些Dictionary和Array可以緩存起來,不會有性能問題吧?

回复 引用 查看

#6楼 [楼主] 2008-11-26 11:03 Kevin Zou
--引用--------------------------------------------------
狼Robot: --引用--------------------------------------------------
Jeffrey Zhao: 似乎性能会是个大问题
--------------------------------------------------------
以前老赵就跟我说过正则费CPU.呵呵.
--------------------------------------------------------
一個user在做一次request時,進行的一次正則查找好像不會費很大的性能吧?
在這次request中,你還要查資料庫,還要show頁面呢

回复 引用 查看

#7楼 2008-11-26 11:12 狼Robot
--引用--------------------------------------------------
Jeffrey Zhao: 似乎性能会是个大问题
--------------------------------------------------------
以前老赵就跟我说过正则费CPU.呵呵.
回复 引用 查看

#8楼 2008-11-26 11:19 lisw
性能问题很严重的,一个是这么多资源都放在内存里,内存压力会很大。
另外这种判断方式,对于大数量的检索简直是灾难
不过思路可行
回复 引用 查看

#9楼 [楼主] 2008-11-26 11:29 Kevin Zou
static string[] _enLang; //英文字符串
static string[] _cnLang; //中文字符串

private string capText(Match m)
{
string x = m.Value;
//實際運用過程還可以使用Dictionary<string,stirng[]>方式來完成,其中key就是如zh_tw,zh_cn,en_us等
int index = Array.IndexOf(_cnLang, x);
if (index >= 0)
return _enLang[index];
return x;

}
回复 引用 查看

#10楼 [楼主] 2008-11-26 11:31 Kevin Zou
--引用--------------------------------------------------
lisw: 性能问题很严重的,一个是这么多资源都放在内存里,内存压力会很大。
另外这种判断方式,对于大数量的检索简直是灾难
不过思路可行
--------------------------------------------------------
其實真的不用空談性能啦,幾個字符串還是放得下的。真正的系統中,需要進行中英文轉換的無非就是輸出到browser的幾個文字而已。
我們在真實系統中,用的就是這個,還沒碰到性能問題
回复 引用 查看

#11楼 2008-11-26 11:41 瓦赛 [未注册用户]
这个性能真实问题,而且我觉得楼主所说的Resources的shortage并不是很有说服力,不过让我们了解了filter
回复 引用

#12楼 2008-11-26 11:46 diannao2008 [未注册用户]
让我们了解了filter
回复 引用

#13楼 2008-11-26 11:57 John Rambo
Bravo! 这个东西是我一直想要的。
我觉得怎么匹配模式怎么转换字符串是另外一个问题了。
至于性能,无非就是扫描一个10几k的字符串,应该也没什么问题吧。
回复 引用 查看

#14楼 2008-11-26 12:09 DecleorMX
这种方式太多限制。不灵活。

回复 引用 查看

#15楼 2008-11-26 12:45 玄天尊的小屋
方式有点。。。。不太适合在你说的大型跨国站点上
回复 引用 查看

#16楼 2008-11-26 13:31 上不了岸的鱼{ttzhang}
这样的方案根本就不可行
回复 引用 查看

#17楼 2008-11-26 14:10 颜斌
我觉得楼主的方法很好 当然某些细节的地方需要调整 但是大家看看待别人的文章的时候 应该多多从里面去获取有价值的东西 要看到别人的创意
回复 引用 查看

#18楼 2008-11-26 14:36 HahahaX [未注册用户]
颜斌 说的有道理.

其他人就是个愤青.
回复 引用

#19楼 2008-11-26 15:11 勇仔
不错。
适合一些网站。
专业性强的用这个比较好。内容太杂的不太合适。
内容太杂的那个Dictionary就大了。
回复 引用 查看

#20楼 2008-11-26 16:12 PerfectDesign
离谱
而且很多asp.net内置的功能都会用不了
回复 引用 查看

#21楼 2008-11-26 17:16 Birdshover
逐字解析,然后拼接,就不用担心性能问题了
回复 引用 查看

#22楼 2008-11-26 17:17 Birdshover
不过还是会对CPU造成一定的负担的。
回复 引用 查看

#23楼 2008-11-26 18:23 0337912 [未注册用户]
很麻烦,比如按照博主的例子用[@.*]要考虑到页面其他地方有没有可能出现[@.*]。这样为了避免其他地方出现这种[@.*],程序员还是要对很多地方做输入检查。。
回复 引用
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐