議題
互連網上有數以百萬計來自數百個國家的人,同時也存在數百種不同的語言,甚至英國、美國、加拿大和英國之間也有多個不同的方言。不要讓你的網站因為只提供一種語言而被限制瀏覽。
解決方案
建立資源檔,並添加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設定。
參考資訊
CurrentUICulture 原書地址 書籍原始碼