【问题标题】:Localized views with Razor使用 Razor 的本地化视图
【发布时间】:2010-11-22 12:52:49
【问题描述】:

我试图机智地使用 VirtualPathProvider 来查找本地化视图。它采用请求的视图路径并在文件后检查时对其进行修改。如果找到它会返回一个本地化的虚拟文件:

public pseudoclass MyFileProvider : VirtualPathProvider
{

    bool FileExists(string requestedPath)
    {
        if (IsLocalizedView(requestedPath))
          return true;
       return base.FileExists(requestedPath);
    }

    bool IsLocalizedView(string requestedPath)
    {
        var uri = requestedUri.AddLocaleByMagic("sv");
        if (FileExistsInternal(uri))
          return true;
    }

    //some more stuff to return the actual file
}

问题是我得到以下异常:

VirtualPathProvider 返回了一个 VirtualFile 对象,其中 VirtualPath 设置为“/Views/Shared/_Layout.sv.cshtml”,而不是预期的“/Views/Shared/_Layout.cshtml”。

当然,我可以伪造文件路径,但这会产生缓存问题和不同的本地化问题。对吧?

谁有更好的方法来创建本地化视图?我不想使用相同的视图,而是使用资源字符串。这样的观点太可怕了,几乎让我哭了,因为它们太难读了。

如果你还不明白我在找什么:

/Views/User/Details.sv.cshtml

Hejsan @Model.FirstName

Detta är en lite rolig text på svenska.

/Views/User/Details.en.cshtml

Hello @Model.FirstName

This is a test on english.

控制器

public ActionResult Details()
{
  return View(new User()); //should automagically use a swedish or english view
}

我希望能够切换视图(使用 CurrentCulture 切换到本地化视图),而无需在每次请求时手动执行任何操作。

【问题讨论】:

  • 为什么不直接实现 ASP.NET 全球化?我为所有斯堪的纳维亚国家都这样做,并且像魅力一样工作。最后我有一个来自App_GlobalResources 文件夹的文本视图。
  • 因为与每种语言一个视图相比,它使视图不可读。

标签: asp.net-mvc localization razor


【解决方案1】:

这是我的实现。它可以变得更通用,但它满足我的所有要求。

我首先寻找最专业的视图,然后在没有语言规范的情况下尝试。

查看查找过程:

  1. Details.sv-fi.cshtml
  2. Details.sv.cshtml
  3. Details.en.cshtml
  4. Details.cshtml

    public class LocalizedRazorViewEngine : RazorViewEngine
    {
        public LocalizedRazorViewEngine()
        {
            DefaultLanguageCode = "en";
        }
        public string DefaultLanguageCode { get; set; }

        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            var controllerName = (string)controllerContext.RouteData.Values["controller"];
            var language = GetLanguage(controllerName, viewName);
            if (language != "") language = "." + language;

            var masterPath = string.Format("~/Views/Shared/_Layout{0}.cshtml", language);
            var uri = string.Format("~/Views/{0}/{1}{2}.cshtml", controllerName, viewName, language);
            if (VirtualPathProvider.FileExists(uri))
                return new ViewEngineResult(CreateView(controllerContext, uri, masterPath), this);


            return base.FindView(controllerContext, viewName, masterName, useCache);
        }

        private string GetLanguage(string controllerName, string actionName)
        {
            string format = "~/Views/{0}/{1}.{2}.cshtml";
            if (VirtualPathProvider.FileExists(string.Format(format, controllerName, actionName, Thread.CurrentThread.CurrentCulture.Name)))
                return Thread.CurrentThread.CurrentCulture.Name;
            if (VirtualPathProvider.FileExists(string.Format(format, controllerName, actionName, Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName)))
                return Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
            if (VirtualPathProvider.FileExists(string.Format(format, controllerName, actionName, DefaultLanguageCode)))
                return DefaultLanguageCode;
            return string.Empty;
        }



    }

请注意,使用此方法会禁用缓存,您可能需要创建自己的缓存(以获得正确的语言)

【讨论】:

  • 代码 sn-p 做得很好。您如何检测 View 是否不使用共享布局,因此根本不提供它?
【解决方案2】:

您可以编写一个自定义 ViewEngine,它根据 CurrentCulture 返回视图。 一个很好的例子可以在Scott Hanselman's blog post 找到,如果移动设备发出请求,它会返回移动视图

【讨论】:

  • 博客文章说实现是损坏 :) 但我认为我的版本有效(尽管没有缓存任何内容)。该链接帮助了我,因此接受了。
  • 他的第一个实现被破坏了,请继续阅读,稍后在帖子中他描述了原因并提供了正确的版本。
【解决方案3】:

这是使用以下约定在视图之间切换的最简单的示例(我猜):

  1. MyView.cshtml - 默认一个
  2. MyView.pl.cshtml - 波兰语语言环境

..等等

    public class LocalizedRazor : RazorViewEngine
    {
    public LocalizedRazor()
        : base()
    {
    }

    public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
    {
        var controllerName = (string)controllerContext.RouteData.Values["controller"];
        var format = "~/Views/{0}/{1}.{2}.cshtml";
        var lang = Thread.CurrentThread.CurrentCulture.TwoLetterISOLanguageName;
        if (VirtualPathProvider.FileExists(string.Format(format, controllerName, viewName, lang)))
            return base.FindView(controllerContext, viewName + "." + lang, masterName, useCache);

        return base.FindView(controllerContext, viewName, masterName, useCache);
    }
    }

在 Global.asax 中:

   protected void Application_Start()
    {
        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(new LocalizedRazor());
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-18
    相关资源
    最近更新 更多