Локализованные виды с бритвой
-
27-09-2019 - |
Вопрос
Я пытался быть остроумным и использовать 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, установленным на «/Views/shared/_layout.sv.cshtml» вместо ожидаемых «/views/shared/_layout.cshtml».
Конечно, я мог бы подделать путь к файлу, но это будет производить проблемы с кэшированием и различными локализациями. Верно?
Кто-нибудь получил лучший способ, чтобы иметь возможность создавать локализованные виды? Я не хочу использовать один и тот же вид, но вместо этого с строками ресурсов. Такие взгляды настолько ужасны, что они почти заставляют меня плакать, потому что им так трудно читать.
Если вы все еще не поняли, что я ищу:
/Views/user/details.sv.chtml.
Hejsan @Model.FirstName
Detta är en lite rolig text på svenska.
/Views/user/details.en.chtml.
Hello @Model.FirstName
This is a test on english.
Контроллер
public ActionResult Details()
{
return View(new User()); //should automagically use a swedish or english view
}
Я хочу иметь возможность переключать представления (на локализованный с использованием текущейCulture) без необходимости делать ничего вручную при каждом запросе.
Решение
Вы можете написать пользовательский ViewEdIne, который возвращает представления в зависимости от текущейCulture. Приятный пример этого можно найти в Сообщение блога Скотта Хансельмана, который возвращает мобильные представления, если запрос был сделан мобильным устройством
Другие советы
Вот моя реализация. Может быть сделано более общедоступным, но он выполняет все мои требования.
Я ищу самую специальное представление сначала и пытается без языкового спецификации последнего.
Просмотр процесса поиска:
- Детали .sv-fi.cshtml.
- Детали .sv.chtml.
- Детали. Den.chtml.
- Детали .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;
}
}
Обратите внимание, что кэширование отключено с использованием этого подхода, и вам может потребоваться создать свой собственный кэш (чтобы получить правильный язык)
Вот самый простой, как можно (я думаю) Пример переключения между представлениями, используя следующую конвенцию:
- Myview.cshtml - по умолчанию один
- Myview.pl.chtml - польский язык
.. и так далее
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());
}