使用 Razor 进行本地化视图
-
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.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.
控制器
public ActionResult Details()
{
return View(new User()); //should automagically use a swedish or english view
}
我希望能够切换视图(使用 CurrentCulture 切换到本地化视图),而无需根据每个请求手动执行任何操作。
解决方案
可以写取决于的CurrentCulture返回视图的定制视图引擎。 这方面的一个很好的例子可以在斯科特Hanselman的博客帖子,这确实返回移动浏览发现如果请求已经由移动设备制造
其他提示
这是我的实现。它可以变得更通用,但它满足我的所有要求。
我首先寻找最专业的视图,最后尝试没有语言规范。
查看查找过程:
- 详情.sv-fi.cshtml
- 详情.sv.cshtml
- 详情.en.cshtml
- 详情.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.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());
}
不隶属于 StackOverflow