巧用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 "-//W
3C
//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中配置就可动态装载多语言功能了


« 
» 
快速导航

Copyright © 2016 phpStudy | 豫ICP备2021030365号-3