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

    2012.5.13. 注:已经针对评论做了修改,现在已经可以支持多用户,而且多用户互相不影响。

  • 相关阅读:
    DFS迷宫递归所有路径 新手入门
    【翻译】Ext JS最新技巧——2016-3-4
    Android进程通信之一:两种序列化方式
    Ext JS 6应用程序Build后出现“c is not a constructor return new c(a[0])”的处理
    简约才是王道? CardView 的使用
    经过一段的努力,终于成为CSDN博客专家,感谢大家支持
    ACM_Uppercase(水题)
    ACM_01背包
    2018年北京信息科技大学第十届程序设计竞赛暨ACM选拔赛-B-precise math function
    goj N皇后问题
  • 原文地址:https://www.cnblogs.com/mikelij/p/2424313.html
Copyright © 2011-2022 走看看