我正在努力将本地化添加到我的Web应用程序中。我已经配置了IStringLocalizer
,并且它可以正确地从两个不同的resx文件读取字符串资源,具体取决于浏览器设置。然后,它将那些字符串资源映射到ViewData,我的View正在从ViewData以正确的语言获取文本(不确定这是否是最好的方法,但是现在我不想在此花费更多的时间)。
问题是,我的UI中还有一个下拉列表,允许用户手动切换语言。我正在读取用户在控制器操作中设置的值,并将其添加到cookie中,但现在我还想将应用程序的区域性设置为与cookie中的字符串匹配的区域。
是否可以通过MVC Core中的控制器操作设置应用程序区域性?如果是,那么如何正确执行此操作?
编辑:
我刚刚得知我可以做这样的事情:
<a class="nav-item nav-link" asp-route-culture="en-US">English</a>
,它会将?culture=en-US
添加到我的路线中,这将为我设置页面的区域性。有什么方法可以不必将其保存在地址栏中吗?
编辑2:
关于亚当·西蒙的回答:
CookieRequestCultureProvider
是我想在我的应用程序中使用的,但是问题是它没有产生任何cookie。文档说,.net核心将通过检查从QueryStringRequestCultureProvider
开始到CookieRequestCultureProvider
,再到其他提供者的解决方案,来确定要使用的提供者。
我当前的启动看起来像这样:
public class Startup
{
private const string defaultCulutreName = "en-US";
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization();
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo(defaultCulutreName),
new CultureInfo("pl-PL")
};
options.DefaultRequestCulture = new RequestCulture(defaultCulutreName, defaultCulutreName);
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
//TRIED PLACING IT BEFORE AND AFTER UseRequestLocalization
//CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("pl-PL", "pl-PL"));
app.UseRequestLocalization(app.ApplicationServices
.GetService<IOptions<RequestLocalizationOptions>>().Value);
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("pl-PL", "pl-PL"));
app.UseMvc(ConfigureRoutes);
}
private void ConfigureRoutes(IRouteBuilder routeBuilder)
{
routeBuilder.MapRoute("Default", "{controller=About}/{action=About}");
}
}
关于CookieRequestCultureProvider.MakeCookieValue(new RequestCulture("pl-PL", "pl-PL"))
,我尝试将其放在RequestLocalizationOptions
之前和之后的ConfigureServices
中的Configure
,UseRequestLocalization
中。所有结果都相同。
此解决方案出现以下“问题”:
MakeCookieValue
方法未生成任何.AspNetCore.Culture
cookie
已将语言设置为PL的Chrome浏览器使用pl-PL
文化
正确,但是Firefox使用en-US
区域性并将语言设置为PL
选项中(尽管将options.DefaultRequestCulture =
new RequestCulture(defaultCulutreName, defaultCulutreName)
行注释掉了)
在不使用查询的情况下,默认情况下我的本地化工作正常 字符串或cookie来提供应用文化,但这是 不是我希望它如何工作,因为我对此没有任何控制权
答案 0 :(得分:4)
您必须以某种方式将选定的区域性与用户联系起来,因此,如果您不想在URL中随身携带该区域性,则必须找到另一种方法来在请求之间保留此信息。您的选择:
在通常情况下使用cookie存储语言首选项是一个完美的选择。
在ASP.NET Core中,获取和设置当前请求区域性的最佳位置是中间件。幸运的是,该框架包括一个框架,可以通过在您的 Startup.Configure 方法中调用 app.UseRequestLocalization(...)将其放置在请求管道中。默认情况下,此中间件将尝试按此顺序从请求URL,cookie和Accept-Language HTTP标头中选择当前区域性。
因此,总结一下:您需要利用请求本地化中间件,将用户的区域性偏好设置存储在c=%LANGCODE%|uic=%LANGCODE%
(例如c=en-US|uic=en-US
)格式的Cookie中,就可以了。
您可以在this MSDN article中找到所有详细信息。
奖金:
然后将这些字符串资源映射到ViewData,我的View从中 以正确的语言获取文本(不确定这是否是最好的 方法,但现在我不想在此上花费更多的时间。
将本地化的文本传递给ViewData中的视图既麻烦又容易出错。在ASP.NET Core中,有view localization用于此目的。您只需将 IViewLocalizer 组件注入视图中,即可获得一种便捷的方法来访问本地化的文本资源。 (在 IViewLocalizer 内使用 IStringLocalizer 。)
关于EDIT 2
MakeCookieValue方法不会生成任何.AspNetCore.Culture cookie
CookieRequestCultureProvider.MakeCookieValue 方法只是一个以正确格式生成Cookie值的助手。它只返回一个字符串,仅此而已。但是,即使是将Cookie添加到响应中,在其中配置请求管道的情况下,在 Startup.Configure 中调用它也是完全错误的。 (在我看来,您对ASP.NET Core中的请求处理和中间件有点困惑,因此我建议学习this topic。)
因此正确的请求管道设置如下所示:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
#region Localization
// REMARK: you may refactor this into a separate method as it's better to avoid long methods with regions
var supportedCultures = new[]
{
new CultureInfo(defaultCultureName),
new CultureInfo("pl-PL")
};
var localizationOptions = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(defaultCultureName, defaultCultureName),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
// you can change the list of providers, if you don't want the default behavior
// e.g. the following line enables to pick up culture ONLY from cookies
RequestCultureProviders = new[] { new CookieRequestCultureProvider() }
};
app.UseRequestLocalization(localizationOptions);
#endregion
app.UseStaticFiles();
app.UseMvc(ConfigureRoutes);
}
(上面的说明:无需在DI容器中注册 RequestLocalizationOptions 。)
然后,您可以执行一些控制器操作来设置区域性Cookie:
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult SetCulture(string culture, string returnUrl)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
// making cookie valid for the actual app root path (which is not necessarily "/" e.g. if we're behind a reverse proxy)
new CookieOptions { Path = Url.Content("~/") });
return Redirect(returnUrl);
}
最后,是一个如何从视图调用该示例的示例:
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Http.Extensions
@{
var httpContext = ViewContext.HttpContext;
var currentCulture = httpContext.Features.Get<IRequestCultureFeature>().RequestCulture.UICulture;
var currentUrl = UriHelper.BuildRelative(httpContext.Request.PathBase, httpContext.Request.Path, httpContext.Request.QueryString);
}
<form asp-action="SetCulture" method="post">
Culture: <input type="text" name="culture" value="@currentCulture">
<input type="hidden" name="returnUrl" value="@currentUrl">
<input type="submit" value="Submit">
</form>
已将语言设置为PL的Chrome浏览器正确使用了PL-PL文化,但是Firefox使用了在选项中将语言设置为PL的美国文化(尽管注释了options.DefaultRequestCulture = 新的RequestCulture(defaultCulutreName,defaultCulutreName)行)
我怀疑Chrome浏览器在“接受语言”标头中发送了语言偏好设置,而FF则没有。
默认情况下,本地化在不使用查询字符串或cookie来为应用程序提供文化的情况下仍能正常工作,但这不是我希望它起作用的方式,因为我对此没有任何控制权
我重复:
默认情况下,该中间件将尝试按请求顺序从请求URL,Cookie和 Accept-Language HTTP标头中选取当前的区域性。
您可以通过更改或替换 RequestLocalizationOptions.RequestCultureProviders 列表来配置此行为。