viste localizzate con il rasoio
-
27-09-2019 - |
Domanda
stavo cercando di essere spiritoso e utilizzare un VirtualPathProvider per trovare viste localizzate. Prende il percorso vista richiesta e lo modifica durante il controllo dopo il file. Esso restituisce un file virtuale localizzato se trovato:
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
}
Il problema è che ottengo la seguente eccezione:
Il VirtualPathProvider restituito un oggetto VirtualFile con VirtualPath insieme a '/Views/Shared/_Layout.sv.cshtml' invece dei previsti '/Views/Shared/_Layout.cshtml'.
Certo, avrei potuto finto il percorso del file, ma che produrrebbe problemi con il caching e diverse localizzazioni. Giusto?
Chiunque ha un modo migliore per essere in grado di creare viste localizzate? Non voglio usare la stessa vista, ma con le stringhe di risorse, invece. Tali opinioni sono così orribili che quasi mi fa piangere perché sono così difficili da leggere.
Se ancora non hai capito quello che sto cercando:
/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.
Regolatore
public ActionResult Details()
{
return View(new User()); //should automagically use a swedish or english view
}
Voglio essere in grado di passare da una visualizzazione (ad un localizzato uno utilizzando CurrentCulture) senza dover fare nulla manualmente ad ogni richiesta.
Soluzione
È possibile scrivere un ViewEngine personalizzato che restituisce una vista a seconda del CurrentCulture. Un bel esempio di questo può essere trovato alla post sul blog di Scott Hanselman, che fa tornare mobili Visualizzazioni se la richiesta è stata fatta da un dispositivo mobile
Altri suggerimenti
Ecco la mia implementazione. Si potrebbe essere reso più generico, ma soddisfa tutte le mie esigenze.
I cerca la vista più specializzata prima e cerca senza un ultima lingua specfication.
Visualizza processo di ricerca:
- Details.sv-fi.cshtml
- Details.sv.cshtml
- Details.en.cshtml
- 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;
}
}
Si noti che la memorizzazione nella cache è disabilitato utilizzando questo approccio e potrebbe essere necessario per creare il proprio cache (per ottenere la lingua corretta)
Questa è la più semplice come può essere (credo) esempio di passare da una vista utilizzando la seguente convenzione:
- MyView.cshtml - di default
- MyView.pl.cshtml - locale polacca
.. e così via
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 in Global.asax:
protected void Application_Start()
{
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new LocalizedRazor());
}