2010-11-22 3 views
3

Я старался быть остроумным и использовать VirtualPathProvider для поиска локализованных представлений. Он принимает запрошенный путь просмотра и изменяет его при проверке после файла. Она возвращает локализованную виртуальный файл, если найдено:Локализованные виды с помощью Razor

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/Пользователь/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? Я делаю это для всех скандинавских стран и работает как шарм. В конце у меня есть один вид с текстом из папки «App_GlobalResources». – balexandre

+1

Потому что это делает просмотр нечитабельным по сравнению с одним видом на язык. – jgauffin

ответ

2

Вы можете написать пользовательский ViewEngine, который возвращает представления в зависимости от CurrentCulture. Приятным примером этого можно узнать по номеру Scott Hanselman's blog post, который возвращает мобильные изображения, если запрос сделан мобильным устройством

+0

В сообщении в блоге говорится, что реализация ** нарушена ** :) Но я думаю, что моя версия работает (хотя ничего не кэшируется). Ссылка помогла мне, следовательно, согласиться. – jgauffin

+0

Его первая реализация была сломана, читайте дальше, позже в сообщении он описывает, почему и предоставляет правильную версию. – marcind

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 не использует общий макет и поэтому не предоставляет его вообще? –

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()); 
    } 
Смежные вопросы