I was trying to be witty and use a VirtualPathProvider to find localized views. It takes the requested view path and modifies it when checking after the file. It returns a localized virtual file if found:
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
}
The problem is that I get the following exception:
The VirtualPathProvider returned a VirtualFile object with VirtualPath set to '/Views/Shared/_Layout.sv.cshtml' instead of the expected '/Views/Shared/_Layout.cshtml'.
Sure, I could fake the file path, but that would produce problems with caching and different localizations. Right?
Anyone got a better way to be able to create localized views? I do not want to use the same view but with resource strings instead. Such views are so horrible that they almost makes me cry because they are so hard to read.
If you still haven't understood what I'm looking for:
/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.
Controller
public ActionResult Details()
{
return View(new User()); //should automagically use a swedish or english view
}
I want to be able to switch views (to a localized one using CurrentCulture) without having to do anything manually at each request.
Here is my implementation. It could be made more generic, but it fulfills all my requirements.
I looks for the most specialized view first and tries without a language specfication last.
View finding process:
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;
}
}
Note that the caching is disabled using this approach and you may need to create your own cache (to get the correct language)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With