如何使用IStringLocalizer从ASP.NET Core Controller获取本地化字符串?

时间:2018-01-30 19:12:32

标签: c# asp.net-core localization asp.net-core-2.0 asp.net-core-localization

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

  1. 从视图(使用IViewLocalizer
  2. 从代码(通过控制器使用IStringLocalizer<HomeController>
  3. 控制器中的代码拒绝正确获取loc字符串。这并不复杂,我错过了哪些明显的事情?

    About.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),@ Local将使用IViewLocalizer类。

    HomeController.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();
        }
    }
    

    Startup.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> 失败,意识到指定了lang,或者找不到明显可用的fr-CH.resx。

    为什么???

    同样顺便说一句,我也试过使用ShareResource示例(参见下面的链接),并将工厂传递给HomeController ctor IStringLocalizerFactory factory,也没有爱,仍然没有获得fr-CH资源。叹息。

    其他说明:

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

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

3 个答案:

答案 0 :(得分:2)

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

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

  • 注入IStringLocalizer<T>
  • 注入IStringLocalizerFactory

有关资源文件名的更多信息,请查看文档中的Resource file naming部分。

注入IStringLocalizer&lt; T&gt;

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

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

对于资源文件:

  • 确保您拥有YouControllerNameSpace.HomeController资源文件。 (YouControllerNameSpace只是一个占位符,使用您的控制器命名空间。)
  • 确保资源文件中包含指定的字符串。
  • 确保您拥有不同文化的资源文件。

注入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资源文件。
  • 确保资源文件中包含指定的字符串。
  • 确保您拥有不同文化的资源文件。

答案 1 :(得分:0)

尝试this answer中tmg描述的技术。

具体来说,尝试添加行

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

到您的ConfigureServices()函数

答案 2 :(得分:0)

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

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

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