ASP.NET MVC 共有する部分ビューにもローカルリソースを使いたい
ASP.NET MVC プロジェクトの多言語化の下ごしらえのために、「しばやん」さんの記事を参考にさせていただきました。
しばやん雑記 ASP.NET MVC 3 の Razor でも多言語対応を試してみる
ただ、プロジェクトには複数のビューで共有する部分ビュー ~/Views/Shared/_Navigation.cshtml
などがあり、それらに与えたローカルリソース ~/Views/Shared/App_LocalResources/_Navigation.cshtml.resx
を読み込むことができませんでした。
部分ビューは、その名のとおり、親ビューの一部分になるので、GetVirtualPath
は親ビューのパスを返すことが要因のようです。そりゃそうだ。
少し手を加えました、変更点は 2つです。
- Resource メソッドに virtualPath を指定できるようにした。
- ResourceRaw メソッドを追加。
ActionLink
などのヘルパに渡す文字列もリソースにしたかったのが理由です。
public static class LocalizationHelper
{
// 1. virtualPath を指定できるように
public static MvcHtmlString Resource(this HtmlHelper helper, string expression, string virtualPath = null, params object[] args)
{
return MvcHtmlString.Create(ResourceRaw(helper, expression, virtualPath, args));
}
// 2. string も返せるように
public static string ResourceRaw(this HtmlHelper helper, string expression, string virtualPath = null, params object[] args)
{
if (virtualPath == null)
{
virtualPath = GetVirtualPath(helper);
}
return GetResourceString(helper.ViewContext.HttpContext, expression, virtualPath, args);
}
public static string Resource(this Controller controller, string expression, params object[] args)
{
return GetResourceString(controller.HttpContext, expression, "~/", args);
}
private static string GetResourceString(HttpContextBase httpContext, string expression, string virtualPath, object[] args)
{
var context = new ExpressionBuilderContext(virtualPath);
var builder = new ResourceExpressionBuilder();
var fields = (ResourceExpressionFields)builder.ParseExpression(expression, typeof(string), context);
if (!string.IsNullOrEmpty(fields.ClassKey))
{
return string.Format((string)httpContext.GetGlobalResourceObject(fields.ClassKey, fields.ResourceKey, CultureInfo.CurrentUICulture), args);
}
return string.Format((string)httpContext.GetLocalResourceObject(virtualPath, fields.ResourceKey, CultureInfo.CurrentUICulture), args);
}
private static string GetVirtualPath(HtmlHelper helper)
{
// WebFormView 決め打ちではなくて基底クラスにキャストするように変更
var view = helper.ViewContext.View as BuildManagerCompiledView;
if (view != null)
{
return view.ViewPath;
}
return null;
}
}
呼び出し側はこんな感じでしょうか。
// ~/Views/Shared/App_LocalResources/_Navigation.cshtml.resx に定義したキー MyTitle を読み出す
@Html.Resource("MyTitle", "~/Views/Shared/_Navigation.cshtml")
呼び出し側からみると virtualPath
が目立ちすぎて少し不細工ですね。
やりようがあるのかもしれませんが、本日はここまで。
最後になりましたが、しばやんさんのソース、リンクのおかげで助かりました、ありがとうございます。