asp.net MVC 3多語言方案--再次寫, 配源碼


之前寫了一篇asp.net MVC多語言方案,那次其實是為American Express銀行開發的。有許多都是剛開始接觸,對其也不太熟悉。現在再回過頭去看,自己做一個小網站,完全用asp.net mvc 3的技術。要實現多語言,並且要求可以動態換語言。在有數據輸入的地方,其數據輸入校驗的界面也是不一樣的,比如必須輸入的字段,英文顯示:required, 中文就顯示:請輸入,等等。這里的方法和之前的文章的方法略有不同。

 

1. 資源文件

 

多語言的資源文件還是一個單獨的.net 工程,里面只放資源文件。可以建一個class library的工程。工程名字叫Resource。里面只加入資源文件.resx。資源文件加入時,一種語言一個文件,這個有基礎的人都知道,不多說。

唯一要注意的是:要將Access Modifier置成Public。這樣IDE會為其產生c#代碼。其類是包以外的類也能訪問的。

 

2. 在View中使用資源文件

在_ViewStart.cshtml中最前面加上這么一行。

@{CommonUtil.ResourceLoader.SetCurrentThreadCulture(Session);}

后面會介紹 ResourceLoader.SetCurrentThreadCulture的代碼。此方法是根據Session["Culture"]來設置當前線程的Culture和UI Culture。在此處加上這么一行,將會對所有的本應用程序的view有影響。

 

見這個代碼,這是本人這個小網站的layout,即相當於asp.net 2.0時代的master page。

 1 <!DOCTYPE html>
2 <html>
3 <head>
4 <title>@ViewBag.Title</title>
5 <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
6 <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script>
7 </head>
8 <body>
9 <div class="wrap">
10 <DIV class="header">
11 <DIV id="logo" class="logo">
12 <a href="@Url.Content("~/")"><img border="0" src="@Url.Content(Resource.Views.Shared.Layout.Logo)" /></a>
13 </DIV>
14 <DIV id="logo" class="logo">
15 <img border="0" src="@Url.Content(Resource.Views.Shared.Layout.AnimAd)" />
16 </DIV>
17 <DIV id="Links" class="top_nav">
18 <UL>
19 <LI><A href="@Url.Content("~/English/")">English</A></LI>
20 <LI><A href="@Url.Content("~/Chinese/")">中文</A></LI>
21 <LI><A href="@Url.Content("~/ContactUs/")">@Resource.Views.Shared.Layout.ContactUS</A></LI>
22 </UL>
23 </DIV>
24 </div>
25 <div class="content">
26 @RenderBody()
27 </div>
28 <div id ="FooterSection" class="footer">
29 <p>&copy; @Resource.Views.Shared.Layout.CopyRight </p>
30 </div>
31 </div>
32 </body>
33 </html>

見到使用資源文件的地方了嗎?如:@Resource.Views.Shared.Layout.ContactUS,還有@Resource.Views.Shared.Layout.CopyRight,這兩個是文本的多語言。還有圖片的多語言,即在<img中的Resource.Views.Shared.Layout.Logo。即實現了兩個語言版本的圖片,用這個資源存儲多個語言版本的圖片路徑。頁面中顯示哪一個,就根據當前用戶的語言偏好。

 

3. 動態切換語言

 

注意到上面的代碼里有一個English和中文的鏈接了嗎。點這兩個鏈接都會有相應的controller處理。這里的controller是這樣的代碼:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Threading;
using CommonUtil;

namespace ApplicationExpertShare.Controllers
{
    public class EnglishController : Controller
    {
        //
        // GET: /English/

        public ActionResult Index()
        {
            System.Globalization.CultureInfo englishCulture = new System.Globalization.CultureInfo("en-US");
            Session["Culture"] = englishCulture;
            return this.Redirect(this.Request.UrlReferrer.ToString());
        }

    }
}

這里調用了一個ResourceLoader類來切換語言。中文的controller也一樣:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
using System.Reflection;
using System.Threading;
using CommonUtil;

namespace ApplicationExpertShare.Controllers
{
    public class ChineseController : Controller
    {
        //
        // GET: /Chinese/

        public ActionResult Index()
        {
            System.Globalization.CultureInfo chineseCulture = new System.Globalization.CultureInfo("zh-CN");
            Session["Culture"] = chineseCulture;
            return this.Redirect(this.Request.UrlReferrer.ToString());
        }
    }
}

那么究竟ResourceLoader類做了什么呢,竟然能動態切換語言?看代碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Resources;
using System.Web;
using System.Web.Mvc;

namespace CommonUtil
{
    public static class ResourceLoader
    {
        public static void SetCurrentThreadCulture(HttpSessionStateBase session)
        {
            if (session != null && session["Culture"] != null)
            {
                System.Threading.Thread.CurrentThread.CurrentCulture = (System.Globalization.CultureInfo)session["Culture"];
                System.Threading.Thread.CurrentThread.CurrentUICulture = (System.Globalization.CultureInfo)session["Culture"];
            }
        }
    }
}

它究竟干了什么呢?

第一步:判斷Session是否空,還有Session["Culture"]是否空。因為這兩個都有可能為空。
第二步:根據Session["Culture"]設置當前線程的Culture和UI Culture。

 

4. Model類的多語言


asp.net MVC少不了Model類,Model類在輸入界面里還有input validation信息,這些input validation的信息也應該是能多語言的。比如最常見的必須輸入字段,我們用英文就顯示"Required",用中文就顯示:“請輸入”。如何做呢?見代碼:

  1 using System;
2 using System.Collections.Generic;
3 using System.ComponentModel.DataAnnotations;
4 using System.Web.Mvc;
5 using Resource.Entity;
6
7 namespace DataEntity
8 {
9 public class UserAccount
10 {
11 #region private members
12 private int _iID;
13 private string _strName;
14 private string _strEmail;
15 private string _strPassword;
16 private string _strConfirmPassword;
17 private System.Decimal _Balance;
18 #endregion
19
20 #region Properties
21 public int ID
22 {
23 get
24 {
25 return _iID;
26 }
27 set
28 {
29 _iID = value;
30 }
31 }
32
33 [Required(ErrorMessageResourceType=typeof(Resource.Entity.UserAccount), ErrorMessageResourceName="Common_Required_ErrorMessage")]
34 [StringLength(30, ErrorMessageResourceType=typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "NAME_StringLength_ErrorMessage")]
35 [RegularExpression(@"[a-zA-Z].*", ErrorMessageResourceType=typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "NAME_RegularExpression_ErrorMessage")]
36 [Display(ResourceType=typeof(Resource.Entity.UserAccount), Name="NAME_DisplayName")]
37 public string NAME
38 {
39 get
40 {
41 return _strName;
42 }
43 set
44 {
45 _strName = value;
46 }
47 }
48
49 [Required(ErrorMessageResourceType=typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "Common_Required_ErrorMessage")]
50 [RegularExpression(@"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?"
51 , ErrorMessageResourceType=typeof(Resource.Entity.UserAccount), ErrorMessageResourceName="EMAIL_RegularExpression_ErrorMessage")]
52 [Display(ResourceType=typeof(Resource.Entity.UserAccount), Name="EMAIL_DisplayName")]
53 public string EMAIL
54 {
55 get
56 {
57 return _strEmail;
58 }
59 set
60 {
61 _strEmail = value;
62 }
63 }
64
65 [Display(ResourceType = typeof(Resource.Entity.UserAccount), Name = "PASSWORD_DisplayName")]
66 [Required(ErrorMessageResourceType = typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "Common_Required_ErrorMessage")]
67 [StringLength(32, ErrorMessageResourceType = typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "PASSWORD_StringLength", MinimumLength = 8)]
68 public string PASSWORD
69 {
70 get
71 {
72 return _strPassword;
73 }
74 set
75 {
76 _strPassword = value;
77 }
78 }
79
80 [Required(ErrorMessageResourceType = typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "Common_Required_ErrorMessage")]
81 [Display(ResourceType = typeof(Resource.Entity.UserAccount), Name = "CONFIRMPASSWORD_DisplayName")]
82 [Compare("PASSWORD", ErrorMessageResourceType = typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "CONFIRMPASSWORD_CompareErrorMessage")]
83 public string CONFIRMPASSWORD
84 {
85 get
86 {
87 return _strConfirmPassword;
88 }
89 set
90 {
91 _strConfirmPassword = value;
92 }
93 }
94
95 [Required(ErrorMessageResourceType = typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "Common_Required_ErrorMessage")]
96 [Display(ResourceType = typeof(Resource.Entity.UserAccount), Name = "OLDNAME_DisplayName")]
97 public string OldName { get; set; }
98
99 [Required(ErrorMessageResourceType = typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "Common_Required_ErrorMessage")]
100 [Display(ResourceType = typeof(Resource.Entity.UserAccount), Name = "OLDEMAIL_DisplayName")]
101 public string OldEmail { get; set; }
102
103 [Required(ErrorMessageResourceType = typeof(Resource.Entity.UserAccount), ErrorMessageResourceName = "Common_Required_ErrorMessage")]
104 [Display(ResourceType = typeof(Resource.Entity.UserAccount), Name = "OLDPassword_DisplayName")]
105 public string OldPassword { get; set; }
106
107 [Display(ResourceType = typeof(Resource.Entity.UserAccount), Name = "Balance")]
108 public decimal Balance { get; set; }
109 #endregion
110 }
111 }

這個類顯示了如何在DataAnnotations中使用資源文件的多語言信息。這些Attribute都接受一個ResourceType, 和一個Resource String的名字。這里可以再說一點,就是RegularExpressionAttribute, 可以用資源文件存儲正則表達式,這樣還可以實現不同的語言采用不同的數據驗證規則。剩下的就是如何在Resource工程里規划好資源文件了。稍有基礎的人都知道,就不多說了。

 

5. 結束語

 

一個全局的資源文件可以帶來許多好處。比如集中管理資源。所有資源都在這個特定的工程里面。當然也有壞處,就是當資源越來越多時,就會難於管理。到時可以想一些折衷的辦法。要么將資源文件放到兩個資源工程里面;要么也可以允許一些local的資源文件。這些的問題只有遇到的時候才會找到合適的辦法。需要根據實際情況來采取一些辦法。

 

2012.5.13. 注:已經針對評論做了修改,現在已經可以支持多用戶,而且多用戶互相不影響。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM