zoukankan      html  css  js  c++  java
  • 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的资源文件。这些的问题只有遇到的时候才会找到合适的办法。需要根据实际情况来采取一些办法。

  • 相关阅读:
    yzoj P2344 斯卡布罗集市 题解
    yzoj P2350 逃离洞穴 题解
    yzoj P2349 取数 题解
    JXOI 2017 颜色 题解
    NOIP 2009 最优贸易 题解
    CH 4302 Interval GCD 题解
    CH4301 Can you answer on these queries III 题解
    Luogu2533[AHOI2012]信号塔
    Luogu3320[SDOI2015]寻宝游戏
    Luogu3187[HNOI2007]最小矩形覆盖
  • 原文地址:https://www.cnblogs.com/zwb7926/p/3257726.html
Copyright © 2011-2022 走看看