2011-12-11 来自:CNBLOGS 字体大小:【
大
中
小】
议题
互联网上有数以百万计来自数百个国家的人,同时也存在数百种不同的语言,甚至英国、美国、加拿大和英国之间也有多个不同的方言。不要让你的网站因为只提供一种语言而被限制浏览。
解决方案
创建资源文件,并添加Key/Value类型的静态文本,并实现CurrentUICulture以提供更改当前现实语言的能力。
讨论
资源文件是XML文件,可以为网站存储多国语言。当你创建一个资源文件时会包含当前默认语言。在资源中创建一个键/值对文本后,你就可以在控制器、模型和视图中随处使用了。如图例 1-3 资源文件示例。
图例 1-3,资源文件示例
右键单击应用程序,选择“添加”->“新建文件夹”,将新文件命名为“Resources”。右键单击新文件夹,选择“添加”->“新建项”。在后侧搜索中输入“资源”并选择“资源文件”。
如上图所示,我们在资源文件中创建“Book”模型类的所有属性的条目。接下来我们需要修改模型类,使用DisplayAttribute引用这些值:
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Web;
using
System.Data.Entity;
using
System.ComponentModel.DataAnnotations;
using
MvcApplication4.Validations;
namespace
MvcApplication4.Models
{
public
class
Book
{
public
int
ID {
get
;
set
; }
[Required]
[Display(Name
=
"
TitleDisplay
"
,
ResourceType
=
typeof
(Resources.Resource1))]
public
string
Title {
get
;
set
; }
[Display(Name
=
"
IsbnDisplay
"
,
ResourceType
=
typeof
(Resources.Resource1))]
[Required]
[IsbnValidation]
public
string
Isbn {
get
;
set
; }
[Display(Name
=
"
SummaryDisplay
"
,
ResourceType
=
typeof
(Resources.Resource1))]
[Required]
public
string
Summary {
get
;
set
; }
[Display(Name
=
"
AuthorDisplay
"
,
ResourceType
=
typeof
(Resources.Resource1))]
[Required]
public
string
Author {
get
;
set
; }
[Display(Name
=
"
ThumbnailDisplay
"
,
ResourceType
=
typeof
(Resources.Resource1))]
public
string
Thumbnail {
get
;
set
; }
[Display(Name
=
"
PriceDisplay
"
,
ResourceType
=
typeof
(Resources.Resource1))]
[Range(
1
,
100
)]
public
double
Price {
get
;
set
; }
[Display(Name
=
"
PublishedDisplay
"
,
ResourceType
=
typeof
(Resources.Resource1))]
[DataType(DataType.Date)]
[Required]
public
DateTime Published {
get
;
set
; }
}
public
class
BookDBContext : DbContext
{
public
DbSet
<
Book
>
Books {
get
;
set
; }
}
}
在上面这个例子中,DisplayAttribute使用键名字段在资源文件中检索引用相应的资源值。这样的引用可以在每个视图以及控制器上使用。
在接下来的例子中,我们将更改书籍索引视图的现实文本,将这些静态文本移动到资源文件中。如表1-1创建键/值对表:
键名 |
值 |
BookIndexTitle |
索引 |
CreateLink |
创建 |
EditLink |
编辑 |
DetailsLink |
详情 |
DeleteLink |
删除 |
表 1-1 更新资源文件
目前为止只创建了一个资源文件,而其中所有的键名必须是整个项目唯一的。如你所见,在表中所创建的五个键值对,在所有视图中都可以链接使用。
将资源文件更新完成后,打开BooksController并使用下面的代码替换Index()方法:
//
//
GET: /Books/
public
ViewResult Index()
{
#region
ViewBag Resources
ViewBag.Title
=
Resources.Resource1.BookIndexTitle;
ViewBag.CreateLink
=
Resources.Resource1.CreateLink;
ViewBag.TitleDisplay
=
Resources.Resource1.TitleDisplay;
ViewBag.IsbnDisplay
=
Resources.Resource1.IsbnDisplay;
ViewBag.SummaryDisplay
=
Resources.Resource1.SummaryDisplay;
ViewBag.AuthorDisplay
=
Resources.Resource1.AuthorDisplay;
ViewBag.ThumbnailDisplay
=
Resources.Resource1.ThumbnailDisplay;
ViewBag.PriceDisplay
=
Resources.Resource1.PriceDisplay;
ViewBag.PublishedDisplay
=
Resources.Resource1.PublishedDisplay;
ViewBag.EditLink
=
Resources.Resource1.EditLink;
ViewBag.DetailsLink
=
Resources.Resource1.DetailsLink;
ViewBag.DeleteLink
=
Resources.Resource1.DeleteLink;
#endregion
return
View(db.Books.ToList());
}
最后,书籍的索引目录视图必须将所有的文本改为ViewBag相应属性的引用:
@model IEnumerable
<
MvcApplication6
.Models.Book
>
<
h2
>
@ViewBag.Title
</
h2
>
<
p
>
@Html.ActionLink((string)ViewBag.CreateLink, "Create")
</
p
>
<
table
>
<
tr
>
<
th
>
@ViewBag.TitleDisplay
</
th
>
<
th
>
@ViewBag.IsbnDisplay
</
th
>
<
th
>
@ViewBag.SummaryDisplay
</
th
>
<
th
>
@ViewBag.AuthorDisplay
</
th
>
<
th
>
@ViewBag.ThumbnailDisplay
</
th
>
<
th
>
@ViewBag.PriceDisplay
</
th
>
<
th
>
@ViewBag.PublishedDisplay
</
th
>
<
th
></
th
>
</
tr
>
@foreach (var item in Model)
{
<
tr
>
<
td
>
@Html.DisplayFor(modelItem => item.Title)
</
td
>
<
td
>
@Html.DisplayFor(modelItem => item.Isbn)
</
td
>
<
td
>
@Html.DisplayFor(modelItem => item.Summary)
</
td
>
<
td
>
@Html.DisplayFor(modelItem => item.Author)
</
td
>
<
td
>
@Html.DisplayFor(modelItem => item.Thumbnail)
</
td
>
<
td
>
@Html.DisplayFor(modelItem => item.Price)
</
td
>
<
td
>
@Html.DisplayFor(modelItem => item.Published)
</
td
>
<
td
>
@Html.ActionLink((string)ViewBag.EditLink,
"Edit", new { id = item.ID }) |
@Html.ActionLink((string)ViewBag.DetailsLink,
"Details", new { id = item.ID }) |
@Html.ActionLink((string)ViewBag.DeleteLink,
"Delete", new { id = item.ID })
</
td
>
</
tr
>
}
</
table
>
其他的视图和控制器都可以通过这样的方式修改,完成这些修改之后,我们只需要将资源文件复制成其他语言版本。
为了避免额外的输入,建议程序完成,所有文件都被添加到资源文件中。右键单击当前资源文件点击“复制”,然后,右键单击“Resources”文件夹点击“粘贴”,并将复制所得的资源副本文件重命名为“Resource1.fr.resx”,当然,也可以以你所希望的语言创建并命名其他副本。然后将这文件中的值得部分翻译成你所希望的语言文本。
要根据请求来变化语言,必须在Global.asax.cs文件的Appliation_AcquireRequestState()方法中通过改变每个请求的CurrentUICulture来实现:
protected
void
Application_AcquireRequestState(
object
sender, EventArgs e)
{
if
(HttpContext.Current.Session
!=
null
)
{
CultureInfo ci
=
(CultureInfo)
this
.Session[
"
CurrentLanguage
"
];
if
(ci
==
null
)
{
ci
=
new
CultureInfo(
"
en
"
);
this
.Session[
"
CurrentLanguage
"
]
=
ci;
}
Thread.CurrentThread.CurrentUICulture
=
ci;
Thread.CurrentThread.CurrentCulture
=
CultureInfo.CreateSpecificCulture(ci.Name);
}
}
在上面的代码示例中,经过检测之后会将有效的CultureInfo赋值给会话变量CurrentLanguage,如果为检测到有效的CultureInfo,系统会默认将英文赋予CurrentLanguage。接下来,我们会在Home控制器中创建一个动作,为用户提供选择语言的功能:
public
ActionResult ChangeLanguage(
string
language)
{
Session[
"
CurrentLanguage
"
]
=
new
CultureInfo(language);
return
Redirect(
"
Index
"
);
}
ChangeLanguage接受设置新语言名称的参数,这个参数变量会更新Global.asax.cs中的绘画变量,然后切换至用户选中语言界面。将下面的链接添加到全局共享母版页_Layout.cshtml中:
[ @Html.ActionLink(
"
English
"
,
"
ChangeLanguage
"
,
"
Home
"
,
new
{ language
=
"
en
"
},
null
) ]
[ @Html.ActionLink(
"
Français
"
,
"
ChangeLanguage
"
,
"
Home
"
,
new
{ language
=
"
fr
"
},
null
) ]
我们将链接放置在“登录”链接的旁边,这样随着网站的逐步发展,创建一个新的资源文件,添加一个新的链接,这样用户就可以选择一种新的语言了,添加一种新语言非常容易。
在之前我们讨论过加拿大、美国、英国等国家有和很多不同的英语方言,如果想为不同的国家添加语言信息,可以在国家的代码后面添加语言代码,并通过字符“-”连接起来。例如,“en-GB”表示英国英语,添加之后还需要更新链接、语言名称以及CurrentUICulture设置。