• asp.net 多语言几种方法


    转载:
    要求如下:
    1,用 Resources
    2,分离项目(Model , Controller 等分开成子项目)
    3,简单
     
    因为要用 Resources ,所以很自然的就想到了 App_GlobalResource , 但是分离的项目怎么使用它呢?为了这个,我还对着GOOGLE搜了很多资料,不幸的是,没有结果。我也在论坛里,群里发贴子,但是高手们都无暇以顾,或是觉得这个问题太过于简单,不屑于回答这等初级的问题。
     
    有什么想法,最好去试一下,不成功就当实践了。幸好我试了一把,要不然,现在都还纠结于这个问题。
     
    新建一项目,这个项目里只放资源文件,如 UI.res (Public), UI.zh-CN.res (没有生成代码),就像在 web 项目里建 App_GlobalResource 一样,只不过,这里的 Resource 是放在一个单独的项目里的。
     
     
    看看要实现的效果如何:
     
     

    第一步:添加 route

     {lang}/{controller}/{action}/{id}
    在 Global.asax ,RegisterRoutes 方法里,你可以自己加些东西,比如:
     
    routes.MapRoute(
    "Lang" ,
    "{lang}/{controller}/{action}/{id}" ,
    new {
        lang = "en" ,
        controller = "Home" ,
        action = "Index" ,
        //lang = UrlParameter.Optional,
        id = UrlParameter.Optional
    }
    );
     
    但是这样做,接着你会发现要怎么取这个 lang 啊?用 Global 的 Application_BeginRequest 截取?可以是可以,但是欠妥啊。
     
     
    当一个asp.net mvc应用程序提出请求,为了响应请求,包含一些请求执行流程步骤! 在asp.net mvc应用程序Http request
    和Http response 过程中,主要包含8个步骤:
         1)RouteTable(路由表)的创建
         2)UrlRoutingModule 请求拦截
         3)Routing engine 确定route
         4)route handler 创建相关的IHttpHandler实例
         5)IHttpHandler实例确定Controller(控制器)
         6)Controller执行
         7)一个视图引擎创建
         8) 视图呈现
     
    这里,要用到第 4 步。把上面的代码改成如下,并放 routes.MapRoute 前面:
     
    routes.Add(new Route(
        "{lang}/{controller}/{action}/{id}",
        new RouteValueDictionary( new {
            lang = "en-US",
            controller = "Home",
            action = "Index",
            id = UrlParameter.Optional
        }), 
        new MultiLangRouteHandler()
    ));
     
    注意这个 MultiLangRouteHandler
     
    MultiLangRouteHandler 类:
     
    public class MultiLangRouteHandler : MvcRouteHandler {
        protected override IHttpHandler GetHttpHandler(RequestContext requestContext) {
            string lang = requestContext.RouteData.Values["lang"].ToString();
     
            //Thread.CurrentThread.CurrentCulture = new CultureInfo(lang);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(lang);
     
            //return new MvcHandler(requestContext);
            return base.GetHttpHandler(requestContext);
        }
    }
     

    第二步,给个入口

    ,在 View 里或 Master 里加上:
     
    <div class="lang">
        <%
            string controller = ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToString();
            string action = ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
        %>
        <%= Html.ActionLink("中文", action ,  controller , new { lang = "zh-CN" }, null)%>
        <%= Html.ActionLink("English", action, controller, new {lang="en-US"}, null) %>
    </div>
     
    只需要这一个方这样写,其它的地方都不需要加 {lang="zh-CN"} 这样的东西,MVC 会自动得到当前的 lang ,并写到 Html.ActionLink 里。另外,那个 null 是必须的,要不然,生成的 Url 不正确。
     
     
     

    第三步,界面上普通文字的多语言

    <%= Html.ActionLink(AsNum.MvcWeb.Lang.UI.LABEL_LOGIN , "Login" , "User")%>
    <div class="title bg"><%= AsNum.MvcWeb.Lang.UI.LABEL_GALLERY %></div>
     
    这里的 AsNum.MvcWeb.lang.UI 就是前面所说的那个 Resource 。
     
     
     

    第四步,DisplayName 的多语言化

    在 Model 里,你可能这样写:
    [Required]
    [DisplayName("User Name")]
    [ScaffoldColumn(false)]
    public string UserName {
        get;
        set;
    }
     
    然后,你在 View 里这样写:
    <%= Html.LabelFor(l=>l.User.UserName) %>
    它就会显示一个 User Name, 但是怎么让随当前的 CurrentUICulture 变化而变化呢?
    当然,你可以用<%= AsNum.MvcWeb.Lang.UI.LABEL_GALLERY %> 这样的写法来写,但是这样写就显的你太不牛B了,有点业余。
    你也许会试着用 DisplayName(lang.UI.UserName)这样的写法,但是编译不通过:
     
    属性实参必须是属性形参类型的常量表达式、typeof 表达式或数组创建表达式
     
    因为Attribute 不接受这样的参数.
     
    我们定义个类 LocalizedDisplayName ,继承 DisplayName:
     
        public class LocalizedDisplayName : DisplayNameAttribute {
     
            private string _defaultName = "";
     
            public Type ResourceType {
                get;
                set;
            }
     
            public string ResourceName {
                get;
                set;
            }
     
            public LocalizedDisplayName(string defaultName) {
                _defaultName = defaultName;
            }
     
            public override string DisplayName {
                get {
                    PropertyInfo p = ResourceType.GetProperty(ResourceName);
                    if( p != null )
                        return p.GetValue(null , null).ToString();
                    else
                        return _defaultName;
                }
            }
        }
     
    然后改一下 Model :
     
            [Required]
            //[DisplayName("User Name")]
            [LocalizedDisplayName("User Name",ResourceName = "USER_USER_NAME" , ResourceType = typeof(Lang.UI))]
            [StringLengthRange(2 , 20 , true , ErrorMessageResourceName = "MSG_USER_NAME_LEN", ErrorMessageResourceType=typeof(Lang.Validation))]
            [ScaffoldColumn(false)]
            public string UserName {
                get;
                set;
            }
     
     

    第五步,验证消息(Validation)的多语言化

    如上面的:
    [StringLengthRange(2 , 20 , true , ErrorMessageResourceName = "MSG_USER_NAME_LEN", ErrorMessageResourceType=typeof(Lang.Validation))]
     
    指定 ErrorMessageResourceName 和 ErrorMessageResourceType 就可以了,不过,好像这两个不能同时和 ErrorMessage 同时存在,我试了,同时存在的话,这个 Validation 不会执行。
     
     

    第六步,客户端的验证消息(Javascript Validation )的多语言化

    如果不知道怎么实现 自定义 ValidationAttribute 的客户端验证,可以参考:
     
     
    就三步:
    a, 从ValidationAttribute 里派生一个类:
    public sealed class StringLengthRangeAttribute : ValidationAttribute
     
    b,从 DataAnnotationsModelValidator 里派生一个类:
    public class StringLengthRangeValidator : DataAnnotationsModelValidator<StringLengthRangeAttribute> {
     
    c,注册,在 Application_Start 里加:
    DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(StringLengthRangeAttribute), typeof(StringLengthRangeValidator));
     
     
     
    DataAnnotationsModelValidator 派生类:
     
        public class StringLengthRangeValidator : DataAnnotationsModelValidator<StringLengthRange> {
     
            private int max , min;
            private bool trim;
            private string errMsg;
     
            public StringLengthRangeValidator(ModelMetadata metaData , ControllerContext ctx , StringLengthRange att)
                : base(metaData , ctx , att) {
     
                max = att.Max;
                min = att.Min;
                trim = att.Trim;
     
                errMsg = base.Attribute.FormatErrorMessage("") ?? att.ErrorMessage;
            }
     
            public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() {
     
                ModelClientValidationRule rule = new ModelClientValidationRule {
                    ErrorMessage = errMsg ,
                    ValidationType = "StringLengthRange"
                };
                rule.ValidationParameters.Add("min" , min);
                rule.ValidationParameters.Add("max" , max);
                rule.ValidationParameters.Add("trim" , trim);
     
                return new[] { rule };
            }
     
        }
     
    注意 
    errMsg = base.Attribute.FormatErrorMessage("") ?? att.ErrorMessage; 
    这个 base.Attribute.FormatErrorMessage("") 其实就是要取 ErrorMessageString ,但是它又是 protected 的。
     
    public sealed class StringLengthRange : ValidationAttribute {
    。。。
            public override string FormatErrorMessage(string name) {
                return ErrorMessageString ?? ErrorMessage;
                //return ErrorMessage;
            }
    。。。
    }
     
    好了,至此,基本上所有的元素都支持多语言化了。
     
    源码下载:
    http://test.dajiaozi.com/other/AsNum.MvcWeb.rar
  • 相关阅读:
    Jenkins+SVN+Maven自动化部署环境搭建
    基于Maven+SSM整合shiro+Redis实现后台管理项目
    Linux学习之CentOS(一)----在VMware虚拟机中安装CentOS 7
    如何用Jmeter做压力测试
    项目沟通管理中的几种技巧
    软件生命周期管理(ALM)
    大数据入门-记录
    为啥项目做到最后都成为了“屎山”,代码改不动
    看企业如何玩转低代码,引发效率革命
    行云创新亮相云栖大会,解读云原生时代开发者工具变革探索与实践
  • 原文地址:https://www.cnblogs.com/jameslif/p/2956139.html
Copyright © 2020-2023  润新知