如何使用IStringLocalizer从 ASP.NET 核心控制器获取本地化字符串?



这里有点困惑,超级简单的 Hello-world ASP.Net Core 2.0 本地化示例。">我的关于">页面设置为呈现两个本地化字符串:

  1. 从视图中(使用IViewLocalizer)
  2. 从代码(通过控制器使用IStringLocalizer<HomeController>)

控制器中的代码拒绝正确获取 loc 字符串。这并不复杂,我错过了什么明显的东西?

关于.cshtml

@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@{
ViewData["Title"] = "About";
}
<h2>@ViewData["Title"]</h2>
<h3>@ViewData["Message"]</h3>
<p>@Localizer["Use this area to provide additional information."]</p>

^ 请注意这两个字符串:"Message"将使用IStringLocalizer从代码中本地化(请参阅下面的HomeController),@Localizer将使用IViewLocalizer类。

首页控制器.cs

public class HomeController : Controller
{
private readonly IStringLocalizer _localizer;
public HomeController(IStringLocalizer<HomeController> localizer)
{
_localizer = localizer;
}
public IActionResult Index()
{
return View();
}
public IActionResult About()
{
ViewData["Message"] = _localizer["Your application description page."];
return View();
}
}

启动.cs(相关部分)

public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("fr-CH"),
};
options.DefaultRequestCulture = new RequestCulture(culture: "en-US", uiCulture: "en-US");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}

资源:

Views.Home.About.fr-CH.resx

^ 包含两个值:

"使用此区域
  • 提供其他信息"="使用此区域 面积。。。FR-CH的成功!
  • "您的应用程序描述页面。" = "您的应用程序描述...FR-CH的成功!

我的结果:

本地主机:56073/首页/关于我们

^ 这会在 en-US 中按预期呈现字符串(默认未找到任何内容,使用实际硬编码的字符串)

本地主机:56073/首页/关于?文化=fr-CH

^ 这只呈现第二个字符串:"使用此区域...fr-CH!"的成功!",这显然意味着所有连接的代码都在工作并按预期找到fr-CH.resx。

但是,第一个字符串(在代码中设置为ViewData["Message"])不会获得 fr-CH 版本! 这就像IStringLocalizer<HomeController>没有意识到有一个指定的语言,或者没有找到明显可用的 fr-CH.resx。

为什么???

顺便说一句,我也尝试使用共享资源示例(见下面的链接),并在工厂中作为IStringLocalizerFactory factory传递给HomeController ctor,也没有爱,仍然没有得到fr-CH资源。 叹息。

其他注意事项:

以此作为我的主要参考: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization

使用VS 2017,最新更新,ASP.Net 核心2.0

问题是ASP .NET Core使用IStringLocalizer为本地化创建了错误的RESX命名空间。如果你在代码中有

services.AddLocalization(options => options.ResourcesPath = "Resources");

然后注入的服务IStringLocalizer的实例在命名空间中有两次"资源",命名空间看起来是"Resources.Resources"。这是找不到RESX的根本原因。

在控制器中使用IStringLocalizer<HomeController>作为本地化器来查找本地化字符串。本地化工具将在Resources文件夹中查找YouControllerNameSpace.HomeController资源文件,由于找不到它,它将返回您传递给本地化人员的原始密钥。

若要解决此问题,可以使用以下任一选项:

  • 注入IStringLocalizer<T>
  • 注入IStringLocalizerFactory

有关资源文件名的详细信息,请查看文档中的资源文件命名部分。

Inject IStringLocalizer

使用此选项,您应该有一个与 T 的全名同名的资源文件,在您的情况下,控制器代码应与原样相同:

IStringLocalizer _localizer;
public HomeController(IStringLocalizer<HomeController> localizer)
{
_localizer = localizer;
}

对于资源文件:

  • 确保您有YouControllerNameSpace.HomeController资源文件。(YouControllerNameSpace只是一个占位符,请使用控制器命名空间。
  • 请确保资源文件中具有指定的字符串。
  • 确保具有不同区域性的资源文件。

Inject IStringLocalizerFactory

使用此选项,您可以将任何文件用作资源文件。例如,如果要从资源文件中读取资源Views.Home.About则应将控制器代码更改为以下内容:

IStringLocalizer _localizer;
public HomeController(IStringLocalizerFactory factory)
{
_localizer = factory.Create("Views.Home.About", 
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
}

对于资源文件:

  • 确保您有Views.Home.About资源文件。
  • 请确保资源文件中具有指定的字符串。
  • 确保具有不同区域性的资源文件。

试试 tmg 在此答案中描述的技术。

具体来说,尝试添加行

options.RequestCultureProviders = new List<IRequestCultureProvider>
{
new QueryStringRequestCultureProvider(),
new CookieRequestCultureProvider()
};

到你的 ConfigureServices() 函数

最新更新