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         #endregion110     }111 }

这个类显示了如何在DataAnnotations中使用资源文件的多语言信息。这些Attribute都接受一个ResourceType, 和一个Resource String的名字。这里可以再说一点,就是RegularExpressionAttribute, 可以用资源文件存储正则表达式,这样还可以实现不同的语言采用不同的数据验证规则。剩下的就是如何在Resource工程里规划好资源文件了。稍有基础的人都知道,就不多说了。

 

5. 结束语

 

一个全局的资源文件可以带来许多好处。比如集中管理资源。所有资源都在这个特定的工程里面。当然也有坏处,就是当资源越来越多时,就会难于管理。到时可以想一些折衷的办法。要么将资源文件放到两个资源工程里面;要么也可以允许一些local的资源文件。这些的问题只有遇到的时候才会找到合适的办法。需要根据实际情况来采取一些办法。

 

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

时间: 2024-10-24 14:50:14

asp.net MVC 3多语言方案--再次写, 配源码的相关文章

ASP.NET MVC的多语言方案概述

1:数据的多语言: 在QBlog里,数据的多语言,我是分成两种方案一起处理: A:多条数据,文章数据,用一个语言字段来标识该条数据为何种语言. B:对于其它数据,标题,公告等,用一个[#LangSplit]标识来分隔前后两种语言. 不过现在的方案有点不同,看如下图: 看到大量的Xml字段了吧,这就是上一个项目继承而来的精华,在项目里动不了事实存在. 关于表名和字段命名方式,走的是国际范,大伙不要学. 针对Xml,需要有一小套处理方案: 数据库以Xml字段存档多语言,格式为: <ML V="

Android中图片压缩方案详解及源码下载

Android中图片压缩方案详解及源码下载 图片的展示可以说在我们任何一个应用中都避免不了,可是大量的图片就会出现很多的问题,比如加载大图片或者多图时的OOM问题,可以移步到Android高效加载大图及多图避免程序OOM.还有一个问题就是图片的上传下载问题,往往我们都喜欢图片既清楚又占的内存小,也就是尽可能少的耗费我们的流量,这就是我今天所要讲述的问题:图片的压缩方案的详解. 1.质量压缩法 设置bitmap options属性,降低图片的质量,像素不会减少 第一个参数为需要压缩的bitmap图

&amp;amp;lt;&amp;amp;lt;asp.net信息管理系统开发实例&amp;amp;gt;&amp;amp;gt;源码谁有,麻烦帮忙,请发到我的邮箱409922757@qq.com

问题描述 <<asp.net信息管理系统开发实例>>源码谁有,麻烦帮忙,请发到我的邮箱409922757@qq.com谢谢....

C语言实现的ls命令源码分享_linux shell

在之前的一些看书或者学习中,一直有一种感觉有问题的态度,那就是认为看懂了,但是不动手,感觉这样看书的效果不是很大.ls命令估计是我们在linux/unix里面用的最多的一个命令了,我们就用c来简单的实现一下ls命令. // // ls.c // apue // // Created by chenqing on 13-8-22. // Copyright (c) 2013年 chenqing. All rights reserved. // #include "/usr/include/apue

ASP.NET MVC应用程序如何把文字写在图片上

Insus.NET实现这篇<MVC把随机产生的字符串转换为图片>http://www.cnblogs.com/insus/p/3624235.html 之后,把字符串转换为图片,不如尝试,把字符串写在一张图片之上.好像有点添加水印的意思. 如果你了解此篇,实现水印的功能也自然懂得了. 参考下面方法,是核心的功能函数,传入文本,以及图片,返回的是Bitmap: 创建控件器,编写两个Action: 更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.c

asp.net开发中常见公共捕获异常方式总结(附源码)_实用技巧

本文实例总结了asp.net开发中常见公共捕获异常方式.分享给大家供大家参考,具体如下: 前言:在实际开发过程中,对于一个应用系统来说,应该有自己的一套成熟的异常处理框架,这样当异常发生时,也能得到统一的处理风格,将异常信息优雅地反馈给开发人员和用户.我们都知道,.net的异常处理是按照"异常链"的方式从底层向高层逐层抛出,如果不能尽可能地早判断异常发生的边界并捕获异常,CLR会自动帮我们处理,但是这样系统的开销是非常大的,所以异常处理的一个重要原则是"早发现早抛出早处理&q

asp.net中BaiduTemplate模板引擎使用示例(附源码)

1.新建项目,asp.net 空Web应用程序 添加data,js,styles,templates文件夹,添加baiduTemplate.js,jquery.js,bootstrap.css 2.添加list.js脚本,代码如下 vardata = {  "list": [   {    "col1":"行1",    "col2":"数据2",    "col3":"数据3

用ASP实现距指定日期的倒记时程序源码_ASP基础

给一个特殊的日子设计一个倒记时,也挺有意思的,而且利用几个时间函数,就可简单地完成ASP网页中距某个时间点的倒记时功能,改变Cdate函数的参数就可完成其他日期的倒记时.下面是给麦布一周年站庆设计的倒记时,大家有兴趣不妨代码拿过去秀秀. ·ASP源代码如下:  麦布一周年站庆倒记时:<BR>  '显示当前时间  当前时间为<%= Date() %> <%= Time() %><BR>  '计算显示距指定日期的天数  距2005年8月10日还有<%= D

用ASP实现距指定日期的倒记时程序源码

给一个特殊的日子设计一个倒记时,也挺有意思的,而且利用几个时间函数,就可简单地完成ASP网页中距某个时间点的倒记时功能,改变Cdate函数的参数就可完成其他日期的倒记时.下面是给麦布一周年站庆设计的倒记时,大家有兴趣不妨代码拿过去秀秀. ·ASP源代码如下: 麦布一周年站庆倒记时:<BR>  '显示当前时间  当前时间为<%= Date() %> <%= Time() %><BR>  '计算显示距指定日期的天数  距2005年8月10日还有<%= Da