Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

ASP.NET MVC 共有する部分ビューにもローカルリソースを使いたい

More than 3 years have passed since last update.

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が目立ちすぎて少し不細工ですね。
やりようがあるのかもしれませんが、本日はここまで。

最後になりましたが、しばやんさんのソース、リンクのおかげで助かりました、ありがとうございます。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away