1. 程式人生 > >ASP.NET MVC 多語言方案

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">
  <
L="zh-cn">中文</M>
  <L="en">English</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<stringstring> 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<stringstring> GetLanguageDic(string lang)
        {
            Dictionary<stringstring> dic = new Dictionary<stringstring>();
            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)即可。

總結: 

以上的多語言方案,有特定的專案環境背景,僅供參考,討論,借鑑,反省,請勿輕易模仿。

謝謝觀賞。