前言

在项目中遇到国际化语言的问题是常有的事情,之前在做关于MVC国际化语言时,刚开始打算全部利用AngularJS来实现,但是渐渐发现对于页面Title难以去控制其语言转换,于是对于页面Tiltle利用后台的资源文件来实现而前台利用AngularJS来实现,这样更好简洁和方便,本节我们来讲讲MVC中的国际化问题。

话题引入

为了效率的问题全部利用前端脚本实现是个不错的选择,但是有时候也稍显麻烦一点,本文只讨论利用MVC来实现,下面我们首先来看一个例子。

我们在项目新建一个il8n文件夹在此下面新建一个资源文件【注意:将访问修饰符修改为public】

接下来我们新建一个【 InternationalizationController 控制器】 ,在此下面获取其资源文件的键对应的值

  1. Assembly myAssem = Assembly.GetExecutingAssembly();
  2. ResourceManager rm = new ResourceManager("ASP.NET_MVC_7.il8n.Resource.zh-cn", myAssem);
  3.  
  4. ViewBag.title = rm.GetString("Cnblogs");
  5. ViewBag.blog = rm.GetString("BlogName");
  6. ViewBag.sign = rm.GetString("MySignature");

我们首先调试来看看是否已经获取到值。

错误详细如下:

  1. 其他信息: 未能找到任何适合于指定的区域性或非特定区域性的资源。请确保在编译时已将“ASP.NET_MVC_7.il8n.Resource.zh-cn.resources”正确嵌入或链接到程序集“ASP.NET MVC_7”,或者确保所有需要的附属程序集都可加载并已进行了完全签名。

出现此错误时不知所以然,经查资料有说,查看在项目的obj/debug(看项目运行模式选择对应模式即可)下是否有有对应的一扩展名 .resources 结尾的文件,若有则复制除开以扩展名的字符串,先看是否有相应的文件吧,如下:

看到这里复制这里的内容和代码里写的是一致的,还是无解。思前想后,看看这个  ResourceManager 类的参数具体是指的什么意思,第一个是basename,提示也说的不是太明确,还是看看msdn上的说明是否有注意的地方。果不其然。看看如下:

资源文件名称不能有任何扩展名,看之前我们的名称,我在第一次演示创建资源文件时就已经在左上角明确标出,其创建的资源名称为 Resource.zh-cn.resx ,上述注意本意就是说只能有一个.结尾的资源名称,我们现在将Resource.去掉再看看,代码也进行相应的修改如下。

  1. ResourceManager rm = new ResourceManager("ASP.NET_MVC_7.il8n.zh-cn", myAssem);

之前为如下,对比一下:

  1. ResourceManager rm = new ResourceManager("ASP.NET_MVC_7.il8n.Resource.zh-cn", myAssem);

我们在对应的视图给出如下代码:

  1. <html>
  2. <head>
  3. <meta name="viewport" content="width=device-width" />
  4. <title>@ViewBag.title</title>
  5. </head>
  6. <body>
  7. <h1>@ViewBag.blog</h1>
  8. <h3>@ViewBag.sign</h3>
  9. </body>
  10. </html>

我们完整来看看最终效果:

注意:在创建资源文件命名时必须以一个扩展名命名,要么以下划线来命名。

当然为了方便管理可以将资源文件单独建立成一个项目,此时只需要加载对应的项目程序集即可,例如 :

  1. var il8mAssem = Assembly.Load("Il8nResource");
  2. ResourceManager rm = new ResourceManager("Il8nResource.zh-cn", il8nAssem);
  3. var blog = rm.GetString("BlogName");

MVC实现国际化

实现国际化选择语言无非两种形式:

(1)通过下拉框自己选择语言。

(2)根据用户的pc或者phone的语言来选择对应的语言进行翻译。

本文以下拉框来展示。在此之前我们首先需要了解下国际化,国际化是什么,不就是不同国家之间的语言么,恩,是的,如果你不是干计算机的,我会马上认同你,否则就有点鄙视你了。我们接下来来看看。

国际化

国际化被缩写为i18n,i18n又是代表什么鬼玩意,它代表从i到n的18中字母。国际化用来开发产品或者软件,在这种情况下它们很容易被本地化为语言和文化,它又分为全球化和本地化。

(1)Globalization:全球化被缩写为G11n,代表以G到n的11的字母,在开发产品或者软件时使得它们可以支持不同的文化的方式处理。

(2)Localization:本地化被缩写为L10n,代表从L到n的10的字母,在开发产品或者软件时可以定制为特定的文化。

在ASP.NET Framework中的文化

在ASP.NET中有两种文化: Culture 和 UICulture ,用两个小写字母来定义语言,两个大写字母来定义区域。例如,en代表英语,而GB和US分别代表Britain(英国)和American (美国),所以在这种情况下,在英国则被定义为en-GB,在美国定义为en-US。

Culture:代表相关文化的功能,如日期、数字、货币等。

UICulture:被用来定位正确的资源文件, 并通过ResourceManager类来在网页上呈现。

这两种文化属性在.NET中的每个线程中都有,当需要呈现时通过ASP.NET 框架来处理。

国际化在MVC中

大概思路:将语言存储在Session中,通过下拉框读取资源文件更改语言。接下来我们开始实现。

(1)新建一个项目 InternationalizationResources 并在其下创建中文和英文资源文件。

(2)创建用户注册类,并利用DataAnnotations中的 ResourceType 来对应其默认资源类型(中文)

  1. public class UserViewModel
  2. {
  3. [Display(Name = "UserName", ResourceType = typeof(InternationalizationResources.Resource))]
  4. [Required(ErrorMessageResourceName = "UserNameRequired", ErrorMessageResourceType = typeof(InternationalizationResources.Resource))]
  5. public string UserName { get; set; }
  6.  
  7. [Display(Name = "FullName", ResourceType = typeof(InternationalizationResources.Resource))]
  8. [Required(ErrorMessageResourceName = "NameRequired", ErrorMessageResourceType = typeof(InternationalizationResources.Resource))]
  9. public string FullName { get; set; }
  10.  
  11. [Display(Name = "Password", ResourceType = typeof(InternationalizationResources.Resource))]
  12. [Required(ErrorMessageResourceName = "PasswordRequired", ErrorMessageResourceType = typeof(InternationalizationResources.Resource))]
  13. public string Password { get; set; }
  14.  
  15. [Display(Name = "ConfirmPassword", ResourceType = typeof(InternationalizationResources.Resource))]
  16. [Required(ErrorMessageResourceName = "ConfirmPasswordRequired", ErrorMessageResourceType = typeof(InternationalizationResources.Resource))]
  17. [Compare("Password", ErrorMessageResourceName = "ConfirmPasswordCompare", ErrorMessageResourceType = typeof(InternationalizationResources.Resource))]
  18. public string ConfirmPassword { get; set; }
  19.  
  20. [Display(Name = "Address", ResourceType = typeof(InternationalizationResources.Resource))]
  21. [Required(ErrorMessageResourceName = "AddressRequired", ErrorMessageResourceType = typeof(InternationalizationResources.Resource))]
  22. public string Address { get; set; }
  23. }

(3)在初始化时设置文化。

  1. protected override void Initialize(System.Web.Routing.RequestContext requestContext)
  2. {
  3. base.Initialize(requestContext);
  4. if (Session["CurrentCulture"] != null)
  5. {
  6. Thread.CurrentThread.CurrentCulture = new CultureInfo(Session["CurrentCulture"].ToString());
  7. Thread.CurrentThread.CurrentUICulture = new CultureInfo(Session["CurrentCulture"].ToString());
  8. }
  9. }

(4)通过下拉框存储语言。

  1. public ActionResult ChangeCulture(string ddlCulture)
  2. {
  3. Thread.CurrentThread.CurrentCulture = new CultureInfo(ddlCulture);
  4. Thread.CurrentThread.CurrentUICulture = new CultureInfo(ddlCulture);
  5.  
  6. Session["CurrentCulture"] = ddlCulture;
  7. return View("Index");
  8. }

(5)用户注册并验证。

  1. [HttpPost]
  2. public ActionResult Index(UserViewModel user)
  3. {
  4. if (ModelState.IsValid)
  5. {
  6.  
  7. }
  8. return View();
  9. }

(6)利用强类型视图首先获取页面标题。

  1. @model ASP.NET_MVC_7.Models.UserViewModel
  2. @{
  3. ViewBag.Title = InternationalizationResources.Resource.Title;
  4. }

(7)读取资源文件中语言并设置到下拉框并给其选择语言更换语言事件。

  1. <div class="col-md-4">
  2. @using (Html.BeginForm("ChangeCulture", "Internationalization"))
  3. {
  4. <p>
  5. @InternationalizationResources.Resource.SelectLanuage : @Html.DropDownList("ddlCulture", new SelectList(new[]
  6. {
  7. new{value="zh-CN",text= InternationalizationResources.Resource.Chinese},
  8. new{value="en-Us",text= InternationalizationResources.Resource.English}
  9.  
  10. }, "value", "text", Session["CurrentCulture"]), new { onchange = "this.form.submit();" })
  11. </p>
  12. }
  13. </div>

(8)进行注册并验证。

  1. <br />
  2. @using (Html.BeginForm("Index", "Internationalization"))
  3. {
  4. @Html.AntiForgeryToken()
  5.  
  6. <div class="form-horizontal">
  7.  
  8. @Html.ValidationSummary(true, "", new { @class = "text-danger" })
  9. <div class="form-group">
  10. @Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
  11. <div class="col-md-10">
  12. @Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })
  13. @Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })
  14. </div>
  15. </div>
  16.  
  17. <div class="form-group">
  18. @Html.LabelFor(model => model.FullName, htmlAttributes: new { @class = "control-label col-md-2" })
  19. <div class="col-md-10">
  20. @Html.EditorFor(model => model.FullName, new { htmlAttributes = new { @class = "form-control" } })
  21. @Html.ValidationMessageFor(model => model.FullName, "", new { @class = "text-danger" })
  22. </div>
  23. </div>
  24.  
  25. <div class="form-group">
  26. @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })
  27. <div class="col-md-10">
  28. @Html.PasswordFor(model => model.Password, new { @class = "form-control" })
  29. @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })
  30. </div>
  31. </div>
  32.  
  33. <div class="form-group">
  34. @Html.LabelFor(model => model.ConfirmPassword, htmlAttributes: new { @class = "control-label col-md-2" })
  35. <div class="col-md-10">
  36. @Html.PasswordFor(model => model.ConfirmPassword, new { @class = "form-control" })
  37. @Html.ValidationMessageFor(model => model.ConfirmPassword, "", new { @class = "text-danger" })
  38. </div>
  39. </div>
  40.  
  41. <div class="form-group">
  42. @Html.LabelFor(model => model.Address, htmlAttributes: new { @class = "control-label col-md-2" })
  43. <div class="col-md-10">
  44. @Html.TextAreaFor(model => model.Address, new { @class = "form-control" })
  45. @Html.ValidationMessageFor(model => model.Address, "", new { @class = "text-danger" })
  46. </div>
  47. </div>
  48.  
  49. <div class="form-group">
  50. <div class="col-md-offset-2 col-md-10">
  51. <input type="submit" value="@InternationalizationResources.Resource.Save" class=" btn btn-default" />
  52. </div>
  53. </div>
  54. </div>
  55. }

下面我们来完整看看演示效果:

总结

这一节我们学习了如何在MVC中如何实现国际化,注意:一般我们可以设置一个默认的语言如上述的Resource.Resx(中文),而英文必须以Resource以开头后面紧跟语言如(Resource.en-US.resx)才行。当页面中需要的翻译的不多时可以直接通过 ResourceManager 类来实现,但是上述也讲了需要注意的地方。

ASP.NET MVC之国际化(十一)的更多相关文章

  1. 学习ASP.NET MVC(十一)——分页

    在这一篇文章中,我们将学习如何在MVC页面中实现分页的方法.分页功能是一个非常实用,常用的功能,当数据量过多的时候,必然要使用分页.在今天这篇文章中,我们学习如果在MVC页面中使用PagedList. ...

  2. ASP.NET MVC 4 (十一) Bundles和显示模式--asp.net mvc中 @Scripts.Render("~/bundles/jquery")是什么意思? 在布局文件中使用Scripts.Render()输出脚本包,Styles.Render()输出风格包:

    ASP.NET MVC 4 (十一) Bundles和显示模式 ASP.NET MVC 4 引入的js打包压缩功能.打包压缩jquery目录下的文件,在布局文件中使用Scripts.Render()输 ...

  3. ASP.NET MVC 4 (十一) Bundles和显示模式

    Bundles用于打包CSS和javascript脚本文件,优化对它们的组织管理.显示模式则允许我们为不同的设备显示不同的视图. 默认脚本库 在VS创建一个MVC工程,VS会为我们在scripts目录 ...

  4. 跟我学ASP.NET MVC之十一:URL路由

    摘要: 在MVC框架之前,ASP.NET假定在请求的URLs和服务器硬盘文件之间有直接的关系.服务器的职责是接收浏览器请求,从相应的文件发送输出. 这种方法只能工作于Web表单,每一个ASPX页面既是 ...

  5. ASP.NET MVC Filters 4种默认过滤器的使用【附示例】

    过滤器(Filters)的出现使得我们可以在ASP.NET MVC程序里更好的控制浏览器请求过来的URL,不是每个请求都会响应内容,只响应特定内容给那些有特定权限的用户,过滤器理论上有以下功能: 判断 ...

  6. Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理

    这是本人第一次写,写的不好的地方还忘包含.写这个的主要原因是想通过这个来学习下EF的CodeFirst模式,本来也想用AngularJs来玩玩的,但是自己只会普通的绑定,对指令这些不是很熟悉,所以就基 ...

  7. 学习ASP.NET MVC(七)——我的第一个ASP.NET MVC 查询页面

    在本篇文章中,我将添加一个新的查询页面(SearchIndex),可以按书籍的种类或名称来进行查询.这个新页面的网址是http://localhost:36878/Book/ SearchIndex. ...

  8. asp.net mvc笔记一,最小的MVC工程

    Asp.net MVC项目默认会引用很多第三方插件,特别是现在的5.0,默认示例项目就几十M,搞得都不知道那些才是MVC必须的,是重点,那些是可有可无的. 今天我们就来试验一下,看看一个最小的MVC工 ...

  9. Datatables 在asp.net mvc中的使用

    前言 最近使用ABP(ASP.NET Boilerplate)做新项目,以前都是自己扩展一个HtmlHelper来完成同步/异步分页,但是有个地方一直不满意,排序太费劲. 以前接触过一点点的Datat ...

随机推荐

  1. centos7 搭建nginx和tomcat集成

    一.安装jdk 1.yum install jdk 2.安装好了之后配置环境变量  在/etc/profile 二.创建项目运行目录 1. 我放在home目录  mkdir /web/webapps ...

  2. mina通信 demo

    1,要用到4个jar 2,服务端 package mina.server; import java.io.IOException; import java.net.InetSocketAddress; ...

  3. mysql外键添加error1215

    在mysql创建表外键的过程中,由于操作不当,会提示cannot add foreign key constraint的错误. 造成此错误可能的原因如下: 1.数据类型不匹配,外键与其相关联的键必须数 ...

  4. 利用js查找页面中的内链,外链

    起初没听说过内链外链,只有链接锚文本,在面试中被问到如何查找到页面中的内链和外链,就在想,什么是内链和外链啊??????? 后来面试官给我解释了一下他们的区别,自己稍微懂了,自己当时回答的是通过获取a ...

  5. 选择列表中除了第一个li的其他元素

    //选择div中除了第一个li的其他所以li元素 div li:not(:first-child){ }

  6. Unity自动寻路Navmesh之入门

    实例 我们要实现一个功能:点击场景中的一个位置,角色可以自动寻路过去.角色会绕过各种复杂的障碍,找到一条理论上”最短路径“. 步骤 1.创建地形 2.添加角色 3.创建多个障碍物,尽量摆的复杂一点,来 ...

  7. Allegro之无法保存(提示和用户有关或者和lock有关)

    使用中无意出现此情况 无奈重新打开文件时发现brd文件下面有个.brd.lck文件,顺手删掉,回复正常~ 此为bug解bug,具体方法下次遇到再仔细研究是为什么~ 养成隔几分钟手动保存的好习惯,防止b ...

  8. mysql 数据表中查找重复记录

    select mobile_phone,count(*) as count from lawyer group by mobile_phone having count>1;

  9. 通过jquery js 实现幻灯片切换轮播效果

    观察各个电商网址轮播图的效果,总结了一下主要突破点与难点 1.->封装函数的步骤与具体实现 2->this关键字的指向 3->jquery js函数熟练运用 如animate 4-& ...

  10. Code First开发系列之数据库迁移

    返回<8天掌握EF的Code First开发>总目录 本篇目录 开启并运行迁移 使用迁移API 应用迁移 给已存在的数据库添加迁移 EF的其他功能 本章小结 自我测试 本系列的源码本人已托 ...