多语言之模板机制原理及应用

多语言之模板机制原理及应用

多语言实现方法有许多种,
1.利用VS2005自带的资源文件去实现
2.重写控件,给多语言赋值<myui:Lable key="language" runat=server />;
3.利用模板,内文格式如<input type="button" value="{search}" />
。。。

以下利用模板机制实现多语言:
原理是用正则式把所有的{XXX}读取出来,然后替换,再写回到页面。


需要用到的命名空间:
using System.Text.RegularExpressions;
using System.Text;
using System.IO;
using System.Diagnostics;

具体代码如下:

 

     protected override void Render(HtmlTextWriter writer)
        {
            Stopwatch stopwatch 
= new Stopwatch();
            stopwatch.Reset();
            stopwatch.Start();
            
try
            {

                StringBuilder sb 
= new StringBuilder();
                StringWriter sw 
= new StringWriter(sb);
                HtmlTextWriter htw 
= new HtmlTextWriter(sw);
                
base.Render(htw);
                
string content = sb.ToString();

                
//模板标签{yes},{no},{search}
                Regex re = new Regex(@"{\S+}", RegexOptions.Multiline);
                MatchCollection mc 
= re.Matches(content);
 
                
//利用Hashtable来筛选所有的多语言标签,然后做替换
                Hashtable ht = new Hashtable();

                
//多语言的资源文件读取到一个Hashtable里,可以保存到缓存里,
                Hashtable ResurceHt = new Hashtable();

                
for (int i = 0; i < mc.Count; i++)
                {
                    
if (!ht.ContainsKey(mc[i].Value))
                    {
                        ht.Add(mc[i].Value, 
null);
                        
//进行替换
                        content = content.Replace(mc[i].Value, (string)ResurceHt[mc[i].Value.TrimStart('{').TrimEnd('}')]);
                    }                   
                }
                ht.Clear(); 

                
//重新写入页面
                writer.Write(content);

            }
            
catch (Exception ex)
            {
                Response.Write(ex.ToString());
                Response.End();
            }
            
finally {
                stopwatch.Stop();
                Response.Write(
"runtime:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");
            }
        }

扩展:

如果有些多语言标签不需要替换,则可以用<NOREPLACE>{xxx},hello ,一舟 </NOREPLACE>包起来,
然后用正则式把content分割开,然后分别替换,再把分割开的字符串连接起来。
代码如下:

 


      //需要替换的标签
        static readonly Regex re = new Regex(@"{\S+}", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
        
        
//不需要替换的标签
        static readonly Regex re_nr = new Regex(@"<NOREPLACE>[\w\W]*?</NOREPLACE>", RegexOptions.Multiline | RegexOptions.IgnoreCase);
        
        
//多语言的资源文件读取到一个Hashtable里,可以保存到缓存里,
        Hashtable ResurceHt = new Hashtable();

        
private string ReplaceTag(ref string content)
        {
            
//模板标签{yes},{no},{search}
            MatchCollection mc = re.Matches(content);

            
//利用Hashtable来筛选所有的多语言标签,然后做替换
            Hashtable ht = new Hashtable();

            
for (int i = 0; i < mc.Count; i++)
            {
                
if (!ht.ContainsKey(mc[i].Value))
                {
                    ht.Add(mc[i].Value, 
null);
                    
//进行替换
                    content = content.Replace(mc[i].Value, mc[i].Value.TrimStart('{').TrimEnd('}'));
                }
            }
            ht.Clear();
            
return content;
        }

        
protected override void Render(HtmlTextWriter writer)
        {
            Stopwatch stopwatch 
= new Stopwatch();
            stopwatch.Reset();
            stopwatch.Start();
            
try
            {

                StringBuilder sb 
= new StringBuilder();
                StringWriter sw 
= new StringWriter(sb);
                HtmlTextWriter htw 
= new HtmlTextWriter(sw);
                
base.Render(htw);
                
string content = sb.ToString();
                                 
                
if (re_nr.IsMatch(content))//不需要替换标签
                {
                    
string text = re_nr.Match(content).Groups[0].Value;
                    
string[] textArray = re_nr.Split(content);
                    textArray[
0= ReplaceTag(ref textArray[0]);
                    textArray[
1= ReplaceTag(ref textArray[1]);

                    content 
= textArray[0+ text + textArray[1];
                }
                
else {
                    content 
= ReplaceTag(ref content);
                }      

                
//重新写入页面
                writer.Write(content);

            }
            
catch (Exception ex)
            {
                Response.Write(ex.ToString());
                Response.End();
            }
            
finally {
                stopwatch.Stop();
                Response.Write(
"runtime:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");
            }
        }

 

如果有多个不需要替换的地方,则用Matchs来分割,完整代码如下:


using System;
using System.Collections;
using System.Data;
using System.Web;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;

using System.Text.RegularExpressions;
using System.Text;
using System.IO;
using System.Diagnostics;

namespace KiloNet.MultiLanguage
{
    
public partial class _Default : Page
    {
        
        
protected void Page_Load(object sender, EventArgs e)
        {

        }

        
//需要替换的标签,标签头为数字字母下划线
        static readonly Regex re = new Regex(@"((\{)|(\%7B))[a-zA-Z_0-9\-\+\|]+((\})|(\%7D))", RegexOptions.Multiline | RegexOptions.IgnorePatternWhitespace);
        
        
//不需要替换的标签
        static readonly Regex re_nr = new Regex(@"<NOREPLACE>[\w\W]*?</NOREPLACE>", RegexOptions.Multiline | RegexOptions.IgnoreCase);
        
        
//多语言的资源文件读取到一个Hashtable里,可以保存到缓存里,
        Hashtable ResurceHt = new Hashtable();
        
        
private string RenderTag(ref string content)
        {
            
if (re_nr.IsMatch(content))//不需要替换标签
            {
                StringBuilder sb 
= new StringBuilder();

                MatchCollection grouplist 
= re_nr.Matches(content);
                
string[] reList = re_nr.Split(content);

                
for (int i = 0; i < grouplist.Count; i++)
                {
                    sb.Append(ReplaceTag(
ref reList[i]));
                    sb.Append(grouplist[i].Value);
                    sb.Append(ReplaceTag(
ref reList[ i + 1]));
                }

                content 
= sb.ToString();
            }
            
else
            {
                content 
= ReplaceTag(ref content);
            }
            
return content;
        }

        
private string ReplaceTag(ref string content)
        {
            
//模板标签{yes},{no},{search}
            MatchCollection mc = re.Matches(content);

            
//利用Hashtable来筛选所有的多语言标签,然后做替换
            Hashtable ht = new Hashtable();
            
for (int i = 0; i < mc.Count; i++)
            {
                
if (!ht.ContainsKey(mc[i].Value))
                {
                    ht.Add(mc[i].Value, 
null);
                    
//进行替换
                    content = content.Replace(mc[i].Value, mc[i].Value.TrimStart('{').TrimEnd('}'));
                }
            }
            ht.Clear();
            
return content;
        }



        
protected override void Render(HtmlTextWriter writer)
        {
            Stopwatch stopwatch 
= new Stopwatch();
            stopwatch.Reset();
            stopwatch.Start();
            
try
            {

                StringBuilder sb 
= new StringBuilder();
                StringWriter sw 
= new StringWriter(sb);
                HtmlTextWriter htw 
= new HtmlTextWriter(sw);
                
base.Render(htw);
                
string content = sb.ToString();
                
                content 
= RenderTag(ref content);
          
                
//重新写入页面
                writer.Write(content);

            }
            
catch (Exception ex)
            {
                Response.Write(ex.ToString());
                Response.End();
            }
            
finally {
                stopwatch.Stop();
                Response.Write(
"runtime:" + stopwatch.ElapsedMilliseconds.ToString() + "ms");
            }
        }
    
    }
}


另外,关于资源文件的话,可以配置一个xml文档,或者直接配置到数据库中,然后读入hashtable,再缓存起来,这个比较简单,就不再累赘。

总结:目前我以前把模板方式和自定义控件方式整合在一起,用起来随心所欲。其实业界许多成型的产品采用的都是采用模板机制来实现多语言。其实原理很简单,就是里面的正则式以及替换规则比较麻烦,以前一直想找这方面的资料,都没有比较合适的,看来真正的好东西别人是舍不得拿出来。自己整理了一个除了给自己用,也贡献出来给大家,喜欢大家提出宝贵意见,使代码更加完善精进。

posted @ 2008-10-15 23:29  冰封的心  阅读(345)  评论(0)    收藏  举报