Pergunta

Eu estava tentando ser espirituoso e usar um VirtualPathProvider para encontrar visualizações localizadas. Ele toma o caminho da visualização solicitado e o modifica ao verificar após o arquivo. Ele retorna um arquivo virtual localizado se encontrado:

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
}

O problema é que recebo a seguinte exceção:

O VirtualPathProvider retornou um objeto VirtualFile com o VirtualPath definido como '/Views/shared/_layout.sv.cshtml' em vez do esperado '/views/shared/_layout.cshtml'.

Claro, eu poderia fingir o caminho do arquivo, mas isso produziria problemas com o cache e as diferentes localizações. Certo?

Alguém tem uma maneira melhor de poder criar visualizações localizadas? Não quero usar a mesma visão, mas com seqüências de recursos. Tais visões são tão horríveis que quase me fazem chorar porque são muito difíceis de ler.

Se você ainda não entendeu o que estou procurando:

/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.

Controlador

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

Quero poder alternar as visualizações (para uma localizada usando o CurrentCulture) sem ter que fazer nada manualmente a cada solicitação.

Foi útil?

Solução

Você pode escrever um ViewEngine personalizado que retorna visualizações, dependendo da cultura Current. Um bom exemplo disso pode ser encontrado em Postagem do blog de Scott Hanselman, que retorna visualizações móveis se a solicitação foi feita por um dispositivo móvel

Outras dicas

Aqui está minha implementação. Pode ser tornado mais genérico, mas atende a todos os meus requisitos.

Procuro a visualização mais especializada primeiro e tenta sem uma especificação de idioma por último.

Veja o processo de localização:

  1. Detalhe.sv-fi.cshtml
  2. Detalhe.sv.cshtml
  3. Detalhe.en.cshtml
  4. Detalhe.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;
        }



    }

Observe que o cache está desativado usando essa abordagem e pode ser necessário criar seu próprio cache (para obter o idioma correto)

Aqui está o exemplo mais simples que pode ser (eu acho) de alternar entre as visualizações usando a seguinte convenção:

  1. Myview.cshtml - padrão
  2. Myview.pl.cshtml - Local polonês

.. e assim por diante

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

e em global.asax:

   protected void Application_Start()
    {
        ViewEngines.Engines.Clear();
        ViewEngines.Engines.Add(new LocalizedRazor());
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top