NET MVC 2 多语言网站的实现

news/2024/5/20 22:12:29/文章来源:https://blog.csdn.net/fxhflower/article/details/7609296

.NET MVC 2 多语言网站的实现  

2010-10-24 12:26:10|  分类: .net mvc |  标签: |字号 订阅

要求如下:
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 截取?可以是可以,但是欠妥啊。
看这里,MVC 请求生命周期
当一个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 的客户端验证,可以参考:
MVC 添加自定义 Client Validation javascript 支持
就三步:
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://www.luyixian.cn/news_show_892999.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网站架构之架构演化

网站从构建之初的很少有人问津&#xff0c;用户数量较少&#xff0c;并发量较低&#xff0c;到之后的拥有千万上亿用户&#xff0c;数万量级的高并发&#xff0c;之间经历了怎样的过程&#xff0c;小型网站架构是怎样逐步演化的&#xff0c;本文简单探讨下这方面的内容&#xf…

基于renren.com和google map的sns网站

基于renren.com和google map的sns网站 网站介绍及寻找合作伙伴 站点名称 网站的功能 意见及建议 支持与合作 站点名称 本网 站基于renren.com和google map的开放的api&#xff0c;充分利用了renren的sns属性和google map的直观视图&#xff0c;故网站暂定名RenrenMap 。 回…

搭建网站之路

我是在申请一个阿里云服务器之后才想起搭建网站的&#xff0c;哈哈&#xff0c;我的驱动力就是好玩。下面说下我搭建人生中中第一个网站(博客)的心里路程 1、首先申请一个服务器 我申请的是阿里云服务器&#xff0c;centos6.6的操作系统&#xff0c;1G内存&#xff0c;20G的磁…

打开网站工程时遇到配置bower显示404的问题。

在装了mongodb和nodejs准备打开一个网站项目时&#xff08;网页包含angular&#xff09;&#xff0c;却发现&#xff0c;打开后网页的内容全是混乱的。然后查看nodejs的运行状况&#xff0c;发现有些包含bower的项目&#xff08;特别是有些angular的项目&#xff09;显示的是40…

Python学习记录-网站爬点句子

背景 想用python上网爬点句子&#xff0c;于是花一下午的时间来做这件事&#xff0c;这只是一个简单的例子&#xff0c;不过对于入坑来说nn conda使用 顺便添加一下conda的使用&#xff0c;之前一直是用python自带的virtualenv工具&#xff0c;安装了anoconda后还是觉得cond…

不同网站和页面爬虫知识点

1、json.loads()解码python json格式 json.load()加载python json格式文件 因此使用requests.get(url)和urllib.urlopen(url)获取内容的方式如下&#xff1a; 2、关于爬取Ajax动态加载&#xff08;翻页时url不变&#xff09;的网页网站 &#xff08;1&#xff09;中国票房网&a…

Github 无法登陆,网站超时问题

网络诊断为&#xff1a;电脑配置没有问题&#xff0c;但是该网站服务器资源无法访问。 简单点直接上解决办法&#xff1a;在hosts文件中添加网站IP。 在文件目录下&#xff1a;C:\Windows\System32\drivers\etc 中&#xff0c;将hosts文件复制到桌面&#xff0c;右键 【属性】…

基于httpd搭建web静态网站

.搭建静态网站 要求&#xff1a; >基于ip实现web网站访问 建立一个xxx.xxx.xxx.100的网站&#xff0c;文件放在/www/100,内容显示this is xxx.xxx.xxx.100. 建立一个xxx.xxx.xxx.200的网站&#xff0c;文件放在/www/200,内容显示this is xxx.xxx.xxx.200. 安装httpd&#x…

android源码常用网站

泡在网上的日子http://www.jcodecraeer.com/plus/list.php?tid31 2.安卓源码服务专家http://www.javaapk.com 3.伯乐在线http://hao.jobbole.com/category/android/ A5源码&#xff1a;http://down.admin5.com/ 安卓巴士&#xff1a;http://www.apkbus.com/ 当然还有开源中国&…

大规模网站架构缓存

一、前端Cache机制 1. 域名转为IP地址&#xff08;域名服务器DNS缓存&#xff09; 我们知道域名其实只是一个别名&#xff0c;真实的服务器请求地址&#xff0c;实际上是一个IP地址。获得IP地址的方式&#xff0c;就是查询DNS映射表。虽然这是一个非常简单的查询&#xff0c; 但…

查看IIS日志以及网站对应的IIS日志文件夹

1.为什么要查看IIS日志&#xff1f; 有时&#xff0c;我们在部署了一个程序之后&#xff0c;虽然程序里面记载了log日志&#xff0c;但有些类似503这样的错误在程序里面是无法记载的&#xff0c;所以我们需要通过查看IIS日志来查找问题。 2.IIS日志目录 点进去之后&#xff0c;…

极其简洁的购物商城静态网站

极其简洁的购物商城静态网站 首先介绍一下使用了那些东西做的。 整体使用html5cssjs&#xff08;少量&#xff09;jquery&#xff08;一点点 &#xff09; 实现内容有 js轮播图&#xff0c;canvas实现飘雪&#xff0c;背景音乐。这些比较垃圾的功能大部分都借鉴了其他人的实现…

Python 网站开发(一)环境搭建

前些天看到小阳买回来的一本 Python 基础教程&#xff0c;于是就产生了使用 Python 来开发一个小博客的想法。这个 Python 网站开发系列文章将不会过多说 Python 基本语法&#xff0c;主要是面向实践的。使用 Python 2.7、框架为 Django 1.3、数据库为 Sql Server&#xff08;没…

毕业设计-微信公众平台开发与设计(三:网站)

网站为 java web类型&#xff0c;在My Eclipse中完成。 微信类代码可在我网盘下载&#xff1a;http://yun.baidu.com/share/link?shareid4115214330&uk1662955403 网站的类包结构如图&#xff1a; 其中核心——微信公众账号“反应”直接代码在CoreServlet类中&#xff0c;…

Python爬虫借助Genecards网站将基因全名转换为Gene Symbol——历时8小时!

历时8小时的爬虫&#xff1a;基因全名与基因名缩写的转换——Genecards 在爬取了TCMSPW的中药材的靶向基因后&#xff0c;得到的靶向基因名称是全名&#xff0c;但是后续分析需要的是基因名称缩写&#xff08;即Gene Symbol&#xff09;。最初尝试用R语言的org.Hs.eg.db包来进…

谭云财SEO:优化网站权重,往往可以从这三个方面入手

通过在不断的工作生涯路上&#xff0c;接触到了各行各业的网站&#xff0c;做过cms系统&#xff0c;也和开发人员从0起步做一个网站的优化&#xff0c;有的人或许以为ip起来了&#xff0c;权重就增加了&#xff0c;然并卵&#xff0c;百度权重从0到1的提升需要很多因素在其中&a…

谭云财:网站更换ip之后对百度排名存在多大的影响呢?

之前听到很多人会纠结于网站是否可以更换ip地址&#xff0c;换句话说就是域名和ip做绑定解析的关系&#xff0c;这也难怪了&#xff0c;更换解析中途基本没有遇到网站不能访问的情况&#xff0c;之前分享过一篇网站更换空间影响SEO优化吗&#xff0c;其他的因素暂且不说&#x…

谭云财SEO顾问:什么样的文章倾向于被收录,原来是这样子

由于百度搜索引擎经常性的变更百度算法&#xff0c;所以这种机制会促使爬虫根据算法来调整和收录规则&#xff0c;谭云财SEO顾问分析&#xff0c;也许有人会说自己的网站比较小巧不会被碰钉子&#xff0c;那你就想错了&#xff0c;凡是在搜索引擎中检索的主页站点&#xff0c;都…

谭云财:SEO优化当中的网站不停复制采集内容,有哪些影响呢?

网站SEO优化过程中最大的难题并不是一个网站的SEO结构做的有多好&#xff0c;谭云财SEO顾问&#xff08;www.tanyuncai.com&#xff09;分析了网站优化当中存在的几个问题&#xff0c;这些都是有固定化的东西可寻的&#xff0c;而且程序员也很容易的去实现&#xff0c;SEO优化过…

谭云财成都SEO:在网站价值中,点击率和关键词排名存在什么关系?

随着SEO工作的不断深入学习和挖掘&#xff0c;我们会发现有更多的资源和渠道进行展出&#xff0c;这个时候我们往往会更加考虑到互联网的后期发展优势和资源投入力度&#xff0c;无论是继续投放资源&#xff0c;还是放弃优化&#xff0c;就会让人感觉到些许的消沉。针对SEO优化…