【譯】MVC3 20個秘方-(4)實現多語言
場景
互聯網是由千百萬個人使用。他們來自數百個不同的國家,使用數百種不同的語言。甚至在加拿大、美國和英國之間英語也有許多方言。
所以,不在你的網站上僅僅呈現一種語言是重要的。
解決方案
創建資源文件,并且以鍵值對的形式添加靜態文本,通過CurrentUICulture來提供改變語言的能力。
討論
資源文件是基于文本的XML文件,用來支持靜態網站多國語言。你創建一個主要的資源文件,包含你的默認語言。為文本創建一些key/value pair。然后,你就可以在你的controller、view、model中的任何地方使用這些文本了。下圖是個例子

注意圈紅的地方要設置為public。如果一個文件的訪問修飾符不是public ,它可能不能被訪問到。
下面開始創建你的資源文件。右鍵單擊project,添加->新建文件夾,添加新項,選擇資源文件。創建。
正如你在上邊例子看到的。我已經為書中的每一個字段創建了一個條目。下一步就是更新這個model ,在DisplayAttribute中引用這些值。
代碼如下:
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using MvcApplication.Validations;
namespace MvcApplication.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 特性中的“Name”是從資源文件檢索的key。resource type 中定義了資源文件的名稱。
提示:為了更方便調試資源文件,避免在view中處理數據。我強烈建議在controller里創建一個 ViewBag并且在view中引用這些值。因為如果直接在view里訪問資源文件。View不由Visual studio 編譯。如果你犯錯了,你將遇到一個運行時的錯誤。而在controller里使用資源文件的好處就是如果定義的key文件沒有找到。Visual studio 會編譯失敗。
下邊的例子將更新Book Index view 把靜態的文本放到資源文件里。如果你檢查那個view 你會發現沒有太多的項要放到資源文件里。
下邊我們按照下邊的表創建key/value pairs。

你們可以注意到,我把后邊4個key/value pair 寫的比較通用。
因為資源文件是整個網站都可以訪問的。在其他的地方我們一樣可以用他們來替換靜態文本。
更新之后我們的資源文件應該變成這樣了

創建完資源文件,讓我們打開BookController 并且用如下代碼替換Index() action:
View Code
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());
}
最后,要更新Books Index view去引用這些ViewBag的屬性替換掉靜態文本:
View Code
@model IEnumerable<MvcApplication.Models.Book>
@{
ViewBag.Title = "Index";
}
<h2>
Index</h2>
<p>
@Html.ActionLink("Create New", "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>
在剩余的controller 中action 和view中應該使用相同的方法去替換資源文件。
現在我們來創建一個中文的資源文件(原著是創建的法語的)。
在資源文件上點擊右鍵。復制。再點擊黏貼(ctrl V)。這樣我們得到了一個名字為:
副本Resource1.resx的資源文件。我們把它重新命名為Resource1.cn.resx。雙擊打開這個文件。
并且更改響應的values 為中文。如下圖:

下邊我們要實現語言轉換了。在每次請求發生的時候都要通過CurrentUICulture 來判斷當前的語言。
打開Global.asax.cs這個文件并在Application_AcquireRequestState() 加入如下代碼:
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);
}
}
在上邊的例子里, CurrentUICulture 是基于 CurrentLanguagesession 變量的. 如果一個合法的CultureInfo沒被找到,將默認為英文。默認的,這個session 變量是不存在的。我們應該在Home Controller創建一個action 讓用戶切換語言:
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult ChangeLanguage(string language)
{
Session["CurrentLanguage"] =
new CultureInfo(language);
return Redirect("Index");
}
public ActionResult About()
{
return View();
}
}
新的action ChangeLanguage 接受一個參數:新的語言名字。這個存在session 變量里,它引用自Global.asax.cs 文件.
最后,我們要創建一個切換語言的鏈接。這應該是在每個頁面都要有的。所以我們把它放到Views/shared文件夾下的_Layout.cshtml(類似于模板頁):
[ @Html.ActionLink("English", "ChangeLanguage", "Home",new { language = "en" }, null) ]
[ @Html.ActionLink("Chinese", "ChangeLanguage", "Home",new { language = "cn" }, null) ]
我把它放在logon link 的邊上了。現在如果再有新的需求要求你的網站支持更多的語言,這將是很容易的事。你只需要添加一個新的資源文件并且添加一個新的鏈接讓用戶去選擇新的語言。
在最開始我們討論的問題:在加拿大、美國和英國中可能會存在很多方言。如果你愿意根據國家來分離語言。你可以添加一個連字符(-)鏈接語言和國家代碼。例如en-GB表示英國的英語。你也需要更新你的鏈接去支持新的語言。
另請參閱


浙公網安備 33010602011771號