在网上查阅了众多方案,觉得路过秋天的方案 解耦性比较好,可以不使用微软的Resource文件,而是将所有的词汇放入在一个txt的词典之中,便于维护。
步骤如下:
1)在整个程序的入口处global.asax.cs加入函数
private void ReadDic(string dicFileName) { var dicPath = Path.Combine(Server.MapPath("/File"), dicFileName); string dicStr; using (var fs = new StreamReader(dicPath, Encoding.UTF8)) { dicStr = fs.ReadToEnd(); } var englishDict = new Dictionary<string, string>(); var chineseDict = new Dictionary<string, string>(); var strs = dicStr.Split(new[] { " " }, StringSplitOptions.RemoveEmptyEntries); string[] temp; foreach (var str in strs) { temp = str.Split('|'); englishDict.Add(temp[0], temp[1]); chineseDict.Add(temp[0], temp[2]); } MyConst.chineseDictionary = chineseDict; MyConst.englishDictionary = englishDict; }
该函数的目的是将位于网站目录“File”下的词典文件,如dict.txt以键值对的形式读取到程序的内存之中,以便随时使用。
Dict.txt的内容形如:
Add|Add|增加 LearningInfo|Learning Info|学习资讯 NewColumn|New Column|新建栏目
......
第一列为key,第二列为要显示的英文,第三列为要显示的中文。
2)通过cookie切换语言
在点击切换后,调用
switchLang(),相应的cultrueInfo分别为zh-CN和en-US.
相应的js代码为
function switchLang(cultureInfo) { deleteCookie("culture"); addCookie("culture", cultureInfo, 720);//cookie持续一个月 location.reload(); } function addCookie(name, value, expiresHours) { var cookieString = name + "=" + escape(value); //判断是否设置过期时间 if (expiresHours > 0) { var date = new Date(); date.setTime(date.getTime() + expiresHours * 3600 * 1000); cookieString = cookieString + "; expires=" + date.toGMTString() + "; path=/"; } document.cookie = cookieString; } function getCookie(name) { var strCookie = document.cookie; var arrCookie = strCookie.split("; "); for (var i = 0; i < arrCookie.length; i++) { var arr = arrCookie[i].split("="); if (arr[0] == name) return arr[1]; } return ""; } function deleteCookie(name) { var date = new Date(); date.setTime(date.getTime() - 10000); document.cookie = name + "=v; expires=" + date.toGMTString(); }
3)本方案的核心逻辑在于:首先获取到输出到浏览器渲染的html代码,用词典中对应的键使用正则表达式匹配html中相应的词,然后再将全部匹配到的词替换,最后再重新输出到浏览器。
于是改写Html代码
例如:本来纯中文的视图中会这么写:
<span>新建栏目</span>
现在改为:
<span>[#NewColumn#]</span>
AddColumn即为词典中对应的键。
4)设置了cookie,然后就可以在后台的Request中使用。然后,为了做到这一点,需要在输出时给控制器加一个切面——一个自定义的HtmlReplaceFilter特性。代码如下:
public class ReplaceHtmlFilter : ActionFilterAttribute { public override void OnResultExecuted(ResultExecutedContext filterContext) { if (filterContext.Result is ViewResult) { string html = RenderViewToString(filterContext.Controller, ((ViewResult)filterContext.Result).View); var httpCookie = filterContext.HttpContext.Request.Cookies["culture"]; if (httpCookie != null) { var cookie = httpCookie.Value; html = Replace(html, cookie); } else { html = Replace(html, "zh-CN"); } filterContext.HttpContext.Response.Clear(); filterContext.HttpContext.Response.Write(html); } } private static string RenderViewToString(ControllerBase controller, IView view) { using (var writer = new System.IO.StringWriter()) { var viewContext = new ViewContext(controller.ControllerContext, view, controller.ViewData, controller.TempData, writer); viewContext.View.Render(viewContext, writer); return writer.ToString(); } } /// <summary> /// 替换多语言。 /// </summary> /// <param name="html"></param> /// <param name="lang"></param> /// <returns></returns> private string Replace(string html, string lang) { MatchCollection matchs = Regex.Matches(html, @"[#([Ss]*?)#]", RegexOptions.Compiled | RegexOptions.IgnoreCase); if (matchs != null && matchs.Count > 0) { var keys = new List<string>(matchs.Count); //记录已匹配过的 Dictionary<string, string> dic = GetLanguageDic(lang); foreach (Match match in matchs) { string text = match.Groups[0].Value; string key = match.Groups[1].Value.Trim(); if (!keys.Contains(key)) { keys.Add(key); if (dic.ContainsKey(key)) { html = html.Replace(text, dic[key]); } } } keys = null; matchs = null; } return html; } private Dictionary<string, string> GetLanguageDic(string lang) { if (lang == "zh-CN") { return MyConst.chineseDictionary; } else { return MyConst.englishDictionary; } }
将该Filter加在Controller上,至此,html的中英文切换即可实现。
5)Javascript中的多语言则需多做一步。
在视图文件中,加入类似如下的词典对象。
<script> var lang = { AllCourses:"[#AllCourses#]", AddCourseColumn:"[#AddCourseColumn#]", AtLeastOneRow: "[#AtLeastOneRow#]", DeleteSelected: "[#DeleteSelected#]", }; </script>
注意,该词典的内容实现也需要添加在dict.txt文件中。
然后,在js代码中
原本为
alert("全部课程");
改为
alert(lang.AllCourses);
由于在输出视图时,所有形如[##]的文本都会被替换为字典里相应的语言,这样js就可以输出多语言了。
6)最后图片也是类似。
注意,图片要制作多语言版本的,即如果之前都是中文,那么要制作一套英文的图片。
然后在视图中,原本为
<img src='btn1.png ' />
改为
<img src='[#btn1#] ' />
字典中加入类似
btn1|cntn1.png|entn1.png
即可起到图片的多语言切换作用。