2010-11-22 33 views
3

我試圖很聰明,並使用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設置爲「/查看/共享/ _layout。 sv.cshtml'而不是預期的'/Views/Shared/_Layout.cshtml'。

當然,我可以僞造文件路徑,但這會產生緩存和不同本地化的問題。對?

任何人都有更好的方式來創建本地化的意見?我不想使用相同的視圖,而是使用資源字符串。這種觀點非常可怕,幾乎讓我哭泣,因爲它們很難閱讀。

如果你還沒有明白我在尋找:

/Views/User/Details.sv.cshtml

Hejsan @Model.FirstName 

Detta är en lite rolig text på svenska. 

/瀏覽/用戶/ 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局部之一)。

+0

爲什麼不執行ASP.NET全球化?我爲所有斯堪的納維亞國家做到這一點,並且像魅力一樣工作。最後,我有一個View來自'App_GlobalResources'文件夾中的文本。 – balexandre 2010-11-22 13:12:33

+1

因爲與每種語言的一個視圖相比,它使視圖不可讀。 – jgauffin 2010-11-22 13:16:20

回答

2

您可以編寫一個自定義的ViewEngine,它根據CurrentCulture返回視圖。 一個很好的例子可以在Scott Hanselman's blog post找到,如果移動設備發出請求,返回移動視圖

+0

該博客文章說,實現** **破壞:)但我認爲我的版本工作(雖然沒有緩存)。鏈接幫助了我,因此接受了。 – jgauffin 2010-11-22 15:08:09

+0

他的第一個實現被打破了,繼續閱讀,後來在他描述了爲什麼並提供了正確的版本。 – marcind 2010-11-22 18:57:44

5

這是我的實現。它可以做得更通用,但它滿足了我所有的要求。

我首先尋找最專業的視圖,並且最後嘗試沒有語言規範。

查看發現過程:

  1. Details.sv-fi.cshtml
  2. Details.sv.cshtml
  3. Details.en.cshtml
  4. 詳細信息。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; 
     } 



    } 

注意,緩存使用這種方法無效,您可能需要創建自己的緩存(以獲得正確的語言)

+1

用代碼片段做的很好。如何檢測View是否不使用共享佈局,因此完全不提供它? – 2012-04-01 19:42:59

1

這是最簡單的可(我猜)使用以下約定在視圖之間切換的示例:

  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()); 
    }