思路大概是這樣的,將翻譯成不同語言的詞句以xml鍵值對的格式分別存在不同文件夾下,擴展MVC HtmlHelper, 在擴展方法里根據用戶當前訪問Action所在的路徑以及當前所選的語言類型讀取語言文件夾下的xml文件,再通過HtmlHelper傳過來的key獲取對應的value。若找不到,則將key自動添加到相應的文件里面。切換語言時將所選的語言類型保存在Session,再Redirect。
寫一個靜態類LangHelper,用以操作語言文件。本例中,將中文、英文語言文件分別保存在網站根目錄下Resources下的zh-cn和en文件夾里面,文件類型為res。為防止每次訪問都去讀取操作那些語言文件,我聲明一個Dictionary靜態變量,用來保存訪問過的語言文件里的key\value,在下次(別的用戶)訪問時先從已保存在服務器內存的靜態字典中讀取。這樣就加快了訪問速度。

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 類用來控制當前用戶選擇的語言類型

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輸出,並保存在語言文件中。

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改為"用戶名",則當用戶在中英文之間切換時就會按不同語言顯示。
效果圖一:
效果圖二:
不知有沒有更好的方法,歡迎指教!
