在网上查阅了众多方案,觉得路过秋天的方案 解耦性比较好,可以不使用微软的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[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);
string[] temp;
foreach (var str in strs)
{
temp = str.Split('|');
englishDict.Add(temp[], temp[]);
chineseDict.Add(temp[], temp[]);
}
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, );//cookie持续一个月
location.reload();
}
function addCookie(name, value, expiresHours) {
var cookieString = name + "=" + escape(value);
//判断是否设置过期时间
if (expiresHours > ) {
var date = new Date();
date.setTime(date.getTime() + expiresHours * * );
cookieString = cookieString + "; expires=" + date.toGMTString() + "; path=/";
}
document.cookie = cookieString;
}
function getCookie(name) {
var strCookie = document.cookie;
var arrCookie = strCookie.split("; ");
for (var i = ; i < arrCookie.length; i++) {
var arr = arrCookie[i].split("=");
if (arr[] == name) return arr[];
}
return "";
} function deleteCookie(name) {
var date = new Date();
date.setTime(date.getTime() - );
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, @"\[#([\S\s]*?)#\]",
RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (matchs != null && matchs.Count > )
{
var keys = new List<string>(matchs.Count); //记录已匹配过的 Dictionary<string, string> dic = GetLanguageDic(lang);
foreach (Match match in matchs)
{
string text = match.Groups[].Value;
string key = match.Groups[].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|cn\btn1.png|en\btn1.png
即可起到图片的多语言切换作用。