支持中英文多语言浏览的MVC网站实例
思路大概是这样的,将翻译成不同语言的词句以xml键值对的格式分别存在不同文件夹下,扩展MVC HtmlHelper, 在扩展方法里根据用户当前访问Action所在的路径以及当前所选的语言类型读取语言文件夹下的xml文件,再通过HtmlHelper传过来的key获取对应的value。若找不到,则将key自动添加到相应的文件里面。切换语言时将所选的语言类型保存在Session,再Redirect。
写一个静态类LangHelper,用以操作语言文件。本例中,将中文、英文语言文件分别保存在网站根目录下Resources下的zh-cn和en文件夹里面,文件类型为res。为防止每次访问都去读取操作那些语言文件,我声明一个Dictionary静态变量,用来保存访问过的语言文件里的key\value,在下次(别的用户)访问时先从已保存在服务器内存的静态字典中读取。这样就加快了访问速度。
View Code
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Linq; using System.Web; namespace Utility { public static class LangHelper { //全局静态变量 private static Dictionary<string, LanguageInfo> Languages = new Dictionary<string, LanguageInfo>(); public static string GetLangString(string key, string langType) { if (String.IsNullOrEmpty(key)) throw new ArgumentException("key can not be null!", "key"); if (String.IsNullOrEmpty(langType)) throw new ArgumentException("language type can not be null!", langType); string filename = "common"; langType = langType.ToLower(); LanguageInfo info = GetLanguageInfo(langType, filename);//默认先到通用的语言文件里去找 if (info.LanguageDictionary.ContainsKey(key.ToLower())) return info.LanguageDictionary[key.ToLower()]; else { string filePath = HttpContext.Current.Request.FilePath; if (filePath == HttpContext.Current.Request.ApplicationPath) { info.AddKey(key, key);//添加到通用语言文件 return key; } else { if (filePath[0] == '/') filePath = filePath.Substring(1, filePath.Length - 1); string[] words = filePath.Split(new char[] { '/' }); filename = String.Format("{0}", words[0]);//当前Controller所在的文件夹名字,也即语言文件的名字 info = GetLanguageInfo(langType, filename); if (info.LanguageDictionary.ContainsKey(key.ToLower())) return info.LanguageDictionary[key.ToLower()]; else { info.AddKey(key, key); return key; } } } } private static LanguageInfo GetLanguageInfo(string langType, string filename) { string cacheKey = String.Format("{0}{1}", langType, filename); LanguageInfo info = null; if (Languages.ContainsKey(cacheKey)) info = Languages[cacheKey]; else { info = new LanguageInfo(langType, filename); if (filename != "common") Languages.Clear(); Languages[cacheKey] = info; } return info; } } public class LanguageInfo { public string LanguageCode { get; set; } public string ResourceFile { get; set; } public XElement RootElement { get; private set; } public Dictionary<string, string> LanguageDictionary { get; private set; } public LanguageInfo(string languageCode, string resourceFile) { this.LanguageCode = languageCode; this.ResourceFile = HttpContext.Current.Server.MapPath( String.Format("~/Resources/{0}/{1}.res",languageCode, resourceFile)); this.LanguageDictionary = this.BuildLanguageDictionary(); } /// <summary> /// 读取XML文件构建语言字典 /// </summary> /// <returns></returns> public Dictionary<string, string> BuildLanguageDictionary() { Dictionary<string, string> dic = new Dictionary<string, string>(); if (System.IO.File.Exists(ResourceFile)) RootElement = XElement.Load(ResourceFile); else { RootElement = new XElement("language"); } IEnumerable<XElement> adds = RootElement.Elements(); foreach (XElement add in adds) { string k = add.Attribute("key").Value; string v = add.Attribute("value").Value; dic[k.ToLower()] = v; } return dic; } public void SaveKey(string key, string value) { if (String.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)) return; XElement e = RootElement.Elements().Where(a => a.Attribute("key").Value.ToLower() == key.ToLower()).FirstOrDefault(); if (e == null) return; e.SetAttributeValue("value", value); RootElement.Save(ResourceFile); } /// <summary> /// 向语言文件添加键值对 /// </summary> /// <param name="key"></param> /// <param name="value"></param> public void AddKey(string key, string value) { XElement newel = new XElement("add"); newel.SetAttributeValue("key", key); newel.SetAttributeValue("value", key); RootElement.Add(newel); try { RootElement.Save(ResourceFile); } catch (Exception e) { } LanguageDictionary[key.ToLower()] = value; } public void RemoveKey(string key) { if (String.IsNullOrEmpty(key)) return; XElement e = RootElement.Elements().Where(a => a.Attribute("key").Value.ToLower() == key.ToLower()).FirstOrDefault(); if (e == null) return; e.Remove(); RootElement.Save(ResourceFile); } } }
GlobalizeUtil 类用来控制当前用户选择的语言类型
View Code
public class GlobalizeUtil { public static string GetCurrentLanguage() { object lang = HttpContext.Current.Session["language"]; if (lang == null) return "zh-cn"; else return lang.ToString(); } public static void SetCurrentLanguage(string langCode) { HttpContext.Current.Session["language"] = langCode; } }
扩展MVC HtmlHelper,方便在View中调用。扩展方法名为String,需要一个string类型参数,此参数即为key,当语言文件中不存在此key时,将此key直接作为value输出,并保存在语言文件中。
View Code
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Linq.Expressions; using System.Web; using System.Web.Mvc; using System.Xml.Linq; namespace Utility { public static class Extensions { /// <summary> /// 在Mvc View中调用 /// </summary> /// <param name="htmlHelper"></param> /// <param name="key"></param> /// <returns></returns> public static string String(this HtmlHelper htmlHelper, string key) { return htmlHelper.Encode(GetLangString(key)); } /// <summary> /// 在C#代码中使用 /// </summary> /// <param name="key"></param> /// <returns></returns> public static string LangString(string key) { return GetLangString(key); } private static string GetLangString(string key) { string langType = GlobalizeUtil.GetCurrentLanguage(); return LangHelper.GetLangString(key, langType); } } }
在View中的使用如: Html.String("Username"),在common.res语言文件里面就会添加一条 <add key="Username" value="Username" />记录,将zh-cn文件夹下的common.res里这条记录的value改为"用户名",则当用户在中英文之间切换时就会按不同语言显示。
效果图一:
效果图二:
不知有没有更好的方法,欢迎指教!