探尋ASP.NET MVC鮮為人知的奧祕(3):尋找多語言的最佳實踐方式
如果你的網站需要被世界各地的人訪問,訪問者會使用各種不同的語言和文字書寫習慣,那麼建立一個支援多語言的網站就是十分必要的了,這一篇文章就講述怎麼快速合理的建立網站對多語言的支援。接下來通過一個例項來講述實踐方式。
首先建立一個ASP.NET MVC5應用程式,命名為Internationalization:
然後在Models中新增一個示例的模型類:
public class Employee { [Display(Name = "Name", ResourceType = typeof(Resources.Resource))] [Required(ErrorMessageResourceType = typeof(Resources.Resource), ErrorMessageResourceName = "NameRequired")] public string Name { get; set; } }
這裡提到了Resources.Resource名稱空間,接下來就建立它:
這是一個單獨的專案,用來存放各種語言的資原始檔,我們建立了三個資原始檔,分別存放了中文(預設)、英文和阿拉伯文,資原始檔中存放了如下資源項:
注意:這裡的資源因為需要在專案外部使用,所以需要將訪問修飾符修改為Public
接下來就是如何來確定訪問者要使用的語言了,在每個請求中,都會有一個Accept-language的頭,其中定義了可接受的語言型別,但是我們僅可以從它來判斷瀏覽器中設定的語言,而這個語言型別可能並不是訪問者實際需要的語言型別,所以,我們將設計一個可供選擇的語言列表,然後在伺服器端使用發回Cookie的方式儲存瀏覽器端實際需要的語言。
首先需要建立一個CultureHelper類,這個類的功能就是來判斷訪問者實際需要的語言型別:
public class CultureHelper { private static readonly List<string> validCultures = new List<string>() { "zh-cn", "en-us","ar" }; private static readonly List<string> cultures = new List<string>() { "zh-cn", "en-us","ar" }; public static bool IsRightToLeft() { return Thread.CurrentThread.CurrentCulture.TextInfo.IsRightToLeft; } public static string GetImplementedCulture(string name) { if (string.IsNullOrEmpty(name)) { return GetDefaultCulture(); } if (!validCultures.Where(c => c.Equals(name, StringComparison.InvariantCultureIgnoreCase)).Any()) { return GetDefaultCulture(); } if (cultures.Where(c => c.Equals(name, StringComparison.InvariantCultureIgnoreCase)).Any()) { return name; } var n = GetNeutralCulture(name); foreach (var c in cultures) { if (c.StartsWith(n)) { return c; } } return GetDefaultCulture(); } public static string GetDefaultCulture() { return cultures[0]; } public static string GetCurrentCulture() { return Thread.CurrentThread.CurrentCulture.Name; } public static string GetCurrentNeutralCulture() { return GetNeutralCulture(Thread.CurrentThread.CurrentCulture.Name); } public static string GetNeutralCulture(string name) { if (!name.Contains("-")) { return name; } else { return name.Split('-')[0]; } } }
接下來建立一個BaseController類,並且確保之後建立的所有控制器繼承自它:
public class BaseController : Controller
{
protected override IAsyncResult BeginExecuteCore(AsyncCallback callback, object state)
{
string cultureName = string.Empty;
HttpCookie cultureCookie = Request.Cookies["_culture"];
if (cultureCookie != null)
{
cultureName = cultureCookie.Value;
}
else
{
cultureName = Request.UserLanguages != null && Request.UserLanguages.Length > 0 ?
Request.UserLanguages[0] : null;
}
cultureName = CultureHelper.GetImplementedCulture(cultureName);
Thread.CurrentThread.CurrentCulture = new CultureInfo(cultureName);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
return base.BeginExecuteCore(callback,state);
}
}
建立一個EmployeeController,作為多語言實踐的一個示例:
public class EmployeeController : BaseController
{
//
// GET: /User/
public ActionResult Index()
{
return View();
}
public ActionResult SetCulture(string culture)
{
culture = CultureHelper.GetImplementedCulture(culture);
HttpCookie cookie = Request.Cookies["_culture"];
if (cookie != null)
{
cookie.Value = culture;
}
else
{
cookie = new HttpCookie("_culture");
cookie.Value = culture;
cookie.Expires = DateTime.Now.AddDays(1);
}
Response.Cookies.Add(cookie);
return RedirectToAction("Index");
}
}
在程式包管理控制檯中,使用PS命令,安裝Bootstrap對RightToLeft文字習慣的支援:
Install-Package Twitter.Bootstrap.RTL
然後在App_Start中的BundleConfig.cs中新增兩個資源文字的虛擬捆綁路徑:
bundles.Add(new ScriptBundle("~/bundles/bootstrap-rtl").Include(
"~/Scripts/bootstrap-rtl.js",
"~/Scripts/respond.js"));
bundles.Add(new StyleBundle("~/Content/css-rtl").Include(
"~/Content/css/bootstrap-rtl.css",
"~/Content/site.css"));
最後,建立Index檢視:
@model Internationalization.Models.Employee
@{
ViewBag.Title = "Index";
var culture = System.Threading.Thread.CurrentThread.CurrentCulture.Name.ToLowerInvariant();
}
@helper selected(string c, string culture)
{
if (c == culture)
{
@:checked="checked"
}
}
@*選擇語言列表*@
@using (Html.BeginForm("SetCulture", "Employee"))
{
<fieldset>
<legend></legend>
<div class="control-group">
<div class="
">
<label for="zh-cn">
<input name="culture" id="zh-cn" value="zh-cn" type="radio" @selected("zh-cn", culture) /> 中文
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label for="en-us">
<input name="culture" id="en-us" value="en-us" type="radio" @selected("en-us", culture) /> English
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label for="en-us">
<input name="culture" id="ar" value="ar" type="radio" @selected("ar", culture) /> عربي
</label>
</div>
</div>
</fieldset>
}
@*建立員工表單*@
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h2>@Resources.Resource.AddEmployee</h2>
<hr />
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Name)
@Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
@*在選擇語言後,自動提交*@
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
<script type="text/javascript">
(function ($) {
$("input[type = 'radio']").click(function () {
$(this).parents("form").submit(); // post form
});
})(jQuery);
</script>
}
還需要更改_Layout.cshtml檔案,當文字習慣為右到左時,需要切換bootstrap的樣式檔案:
<!DOCTYPE html>
<html lang="@Internationalization.Helpers.CultureHelper.GetCurrentNeutralCulture()" dir="@(Internationalization.Helpers.CultureHelper.IsRightToLeft() ? "rtl" : "ltr")">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>@ViewBag.Title - 我的 ASP.NET 應用程式</title>
@Styles.Render("~/Content/css" + (Internationalization.Helpers.CultureHelper.IsRightToLeft() ? "-rtl" : ""))
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
@Html.ActionLink("應用程式名稱", "Index", "Home", null, new { @class = "navbar-brand" })
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li>@Html.ActionLink("主頁", "Index", "Home")</li>
<li>@Html.ActionLink("關於", "About", "Home")</li>
<li>@Html.ActionLink("聯絡方式", "Contact", "Home")</li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - 我的 ASP.NET 應用程式</p>
</footer>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap" + (Internationalization.Helpers.CultureHelper.IsRightToLeft() ? "-rtl" : ""))
@RenderSection("scripts", required: false)
</body>
</html>
演示效果:
最終DEMO地址:點選這裡,感謝園友支援,這一期會一直進行下去的
如果您覺得這篇文章對您有用,勞煩給個贊!
如果您覺得這篇文章可能對別人游泳,勞煩您推薦一個!
如果您覺得這篇文章真扯淡,那麼你又給我刷了個訪問量!