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

浙公网安备 33010602011771号