ASP.NET MVC 多語言方案
前言:
好多年沒寫文章了,工作很忙,天天加班, 每天都相信不用多久,就會升職加薪,當上總經理,出任CEO,迎娶白富美,走上人生巔峰,想想還有點小激動~~~~
直到後來發生了郵箱事件,我竟然忘了給郵箱密碼賦值,導致遇到“郵箱不可用。 伺服器響應為: 5.7.1 Unable to relay for”的問題,網上一查後,讓Boss去設定IIS裡的SMTP。
結果Boss力證不用設定也可以發,還給我發了N多Demo程式碼,讓我蛋碎一地, 最後那點小激動,就在這小事件上栽沒了~~~
好了,不多扯了,回正文吧~~~
引子:
關於系統的多語言,我在之前的文章都寫過不少,包括秋色園QBlog的開源部落格裡,也有相應的實現方案,不過隨著專案環境的不同,往往實現的方案也不盡相同。
今天就來扯扯,ASP.NET MVC下的方案。
1:資料的多語言:
在QBlog裡,資料的多語言,我是分成兩種方案一起處理:
A:多條資料,文章資料,用一個語言欄位來標識該條資料為何種語言。
B:對於其它資料,標題,公告等,用一個[#LangSplit]標識來分隔前後兩種語言。
不過現在的方案有點不同,看如下圖:
看到大量的Xml欄位了吧,這就是上一個專案繼承而來的精華,在專案裡動不了事實存在。
關於表名和欄位命名方式,走的是國際範,大夥不要學。
針對Xml,需要有一小套處理方案:
資料庫以Xml欄位存檔多語言,格式為:<ML V="1.0">
<
<M L="en">English</M>
<M L="..">其它語言</M>
</ML>
然後針對這種存檔,需要有相應的處理:
SQL:查詢語法為:取值:欄位名.value('(/ML/M[@L="zh-cn"])[1]','nvarchar(max)')
取節點:欄位名.query('/ML/M[@L="en"]')
判斷:欄位名.exists('/ML/M[@L="zh-cn"]')
排序:用取值後的欄位名進行排序
處理流程大體如下:
2:UI多語言
2.1:MVC View的多語言流程:
經過對MVC的原始碼除錯,發現在Control基類(自己定義)統一處理即可。
Demo程式碼:
protected override void OnResultExecuted(ResultExecutedContext filterContext){
if (filterContext.Result is ViewResult)
{
string html = RenderViewToString(this, ((ViewResult)filterContext.Result).View);
html = LanguageMgr.Replace(html,"zh");
Response.Clear();
Response.Write(html);
}
}
protected static string RenderViewToString(Controller controller, IView view)
{
//IView view = ViewEngines.Engines.FindView(controller.ControllerContext, viewName, masterName).View; using (System.IO.StringWriter writer = new System.IO.StringWriter())
{
ViewContext viewContext = new ViewContext(controller.ControllerContext, view, controller.ViewData, controller.TempData, writer);
viewContext.View.Render(viewContext, writer);
return writer.ToString();
}
}
一開始的想法是處理完後寫回去,後來除錯了半天原始碼發現找不到寫回去的,靈光一閃,發現數據在Response.OutPut流裡,直接清空,輸出新的Html即可。
2.2:JS指令碼的多語言流程:
具體的實現,看下面的語法定義。
3:UI多語言的語法方案
介面標籤定義:[#物件名稱-欄位名#],標籤內不允許帶有空格。 或者直接:[#欄位名#](由Controller自動取得物件名稱處理) 例如:[#UserID#] 或者[#Login-UserID#] 中文時將被替換成:登陸名,英文就是Login了。配套的Demo實現:
public class LanguageMgr{
///<summary>/// 替換多語言。
///</summary>///<param name="html"></param>///<param name="lang"></param>///<returns></returns> public static string Replace(string html, string lang)
{
MatchCollection matchs = Regex.Matches(html, @"\[#([\S\s]*?)#\]", RegexOptions.Compiled | RegexOptions.IgnoreCase);
if (matchs != null && matchs.Count > 0)
{
List<string> 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;
}
internal static Dictionary<string, string> GetLanguageDic(string lang)
{
Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("aaa", "中文");
dic.Add("bbb", "英文");
return dic;
}
}
4: JavaScript 多語言定義
對於JavaScript需要在客戶端呼叫的多語言,可以在View中進行如下定義語言json: <script>var lang={loginID:”[#LoginID#]”,userName:”[#UserName#]”};
<script>
該View會在Controller端提前會替換成相應語言的文字。
之後的引用呼叫alert(lang.loginID)即可。總結:
以上的多語言方案,有特定的專案環境背景,僅供參考,討論,借鑑,反省,請勿輕易模仿。
謝謝觀賞。