之前幾篇文章有講過 ASP.NET MVC 事實上共用許多 ASP.NET 原本就有的東西,這當然連 ASP.NET 全球化和當地語系化的支援也包含在內,在建置多國語言網站時我們通常會利用 App_GlobalResources 儲存全域資源檔,與頁面有關的本地資源檔會放在每一個 *.aspx 所在目錄下的 App_LocalResources 目錄下,這樣的架構在 ASP.NET MVC 之中也一樣可以利用,只是需要一些小技巧才能方便在 View 中使用,今天會分享一個 HtmlHelper 幫助我們在 View 中取用資源檔的資料。
首先我要感謝 Matt Hawley 寫了一個超好用的 HtmlHelper 幫助大家在 ASP.NET MVC 中讀取資源檔,我們可以來看看程式碼,一共分成三個部分:
1. 自訂 WebFormViewEngine 與 WebFormView 讓在 View 中可以取得 View 的實際所在路徑
LocalizationWebFormView.cs
using System.IO;
using System.Web.Mvc;
namespace MvcApplication
{
public class LocalizationWebFormView : WebFormView
{
internal const string ViewPathKey = "__ViewPath__";
public LocalizationWebFormView(string viewPath) : base(viewPath)
{
}
public LocalizationWebFormView(string viewPath, string masterPath) : base(viewPath, masterPath)
{
}
public override void Render(ViewContext viewContext, TextWriter writer)
{
// there seems to be a bug with RenderPartial tainting the page's view data
// so we should capture the current view path, and revert back after rendering
string originalViewPath = (string) viewContext.ViewData[ViewPathKey];
viewContext.ViewData[ViewPathKey] = ViewPath;
base.Render(viewContext, writer);
viewContext.ViewData[ViewPathKey] = originalViewPath;
}
}
}
LocalizationWebFormViewEngine.cs
using System.Web.Mvc;
namespace MvcApplication
{
public class LocalizationWebFormViewEngine : WebFormViewEngine
{
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
return new LocalizationWebFormView(viewPath, masterPath);
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return new LocalizationWebFormView(partialPath, null);
}
}
}
2. 建立一個 Resource HtmlHelper ,方便在 View 中直接以 Html Helper 的方式取用資源檔
ResourceExtensions.cs
using System.Globalization;
using System.Web;
using System.Web.Compilation;
using System.Web.Mvc;
namespace MvcApplication
{
public static class ResourceExtensions
{
public static string Resource(this Controller controller, string expression, params object[] args)
{
ResourceExpressionFields fields = GetResourceFields(expression, "~/");
return GetGlobalResource(fields, args);
}
public static string Resource(this HtmlHelper htmlHelper, string expression, params object[] args)
{
string path = (string)htmlHelper.ViewData[LocalizationWebFormView.ViewPathKey];
if (string.IsNullOrEmpty(path))
path = "~/";
ResourceExpressionFields fields = GetResourceFields(expression, path);
if (!string.IsNullOrEmpty(fields.ClassKey))
return GetGlobalResource(fields, args);
return GetLocalResource(path, fields, args);
}
static string GetLocalResource(string path, ResourceExpressionFields fields, object[] args)
{
return string.Format((string)HttpContext.GetLocalResourceObject(path, fields.ResourceKey, CultureInfo.CurrentUICulture), args);
}
static string GetGlobalResource(ResourceExpressionFields fields, object[] args)
{
return string.Format((string)HttpContext.GetGlobalResourceObject(fields.ClassKey, fields.ResourceKey, CultureInfo.CurrentUICulture), args);
}
static ResourceExpressionFields GetResourceFields(string expression, string virtualPath)
{
var context = new ExpressionBuilderContext(virtualPath);
var builder = new ResourceExpressionBuilder();
return (ResourceExpressionFields)builder.ParseExpression(expression, typeof(string), context);
}
}
}
3. 修改 Global.asax.cs 將預設的 WebFormViewEngine 換成 LocalizationWebFormViewEngine
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterRoutes(RouteTable.Routes);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new LocalizationWebFormViewEngine());
}
這樣就大功告成了!接著我們看看如何在 View 中運用這個 Html Helper,如下圖示是我寫的一個範例:
專案內容包括:
- 由上述新增的三個檔案
- 修改過的 Global.asax.cs
- 新增的 App_GlobalResources 目錄與一個 Resource.resx 資源檔
- 在 Views\Home 下新增一個 App_LocalResources 目錄與三個本地資源檔 (Index.aspx.resx , Index.aspx.zh-TW.resx , Index.aspx.en-US.resx )
在 Views\Home\Index.aspx 中取用資源的範例如下:
其中有三點必須注意:
- 由於 ASP.NET MVC 的 Html Helper 透過擴充方法(Extension Method),所以必須要載入命名空間才能取用自訂的擴充方法,如果不希望每個 View 都匯入命名空間可以參考我的另一篇文章:ASP.NET 如何預設匯入指定的命名空間(Namespace)
- 讀取「全域資源檔」的格式與之前在寫 ASP.NET 的時候一樣:
資源檔的檔名 + 逗號 + 資源名稱
- 讀取「本地資源檔」的時候可以直接輸入「資源名稱」就好
若想要測試不同語系的資料,可以參考下圖或我另外兩篇文章:
本文範例可以從這裡下載:
ASP.NET MVC Globalization and Localization Sample.zip (314.66 kb)
相關連結