Как получить локализованную строку из ASP.NET Core Controller с помощью IStringLocalizer?

Вроде запутался здесь, супер простой привет-пример локализации в ASP.Net Core 2.0. Страница My About настроена для отображения двух локализованных строк:

  1. С точки зрения (используя IViewLocalizer)
  2. Из кода (используя IStringLocalizer<HomeController> через контроллер)

Код в контроллере отказывается получить строку 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>

^ Обратите внимание на две строки: "Сообщение" будет локализовано из кода с использованием IStringLocalizer (см. HomeController ниже), и @Localizer будет использовать 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/ Главная / О культуре = фр-CH

^ Это выводит ТОЛЬКО 2-ую строку: "Использовать эту область... успех для fr-CH!", Что ясно означает, что весь код, который работает, работает и находит fr-CH.resx, как и ожидалось.

НО, первая строка (устанавливается в коде как ViewData["Message"]) НЕ получает версию fr-CH! Это как IStringLocalizer<HomeController> не смог понять, был ли указан lang, или не смог найти явно доступный fr-CH.resx.

Зачем???

Кроме того, кстати, я попытался использовать пример ShareResource (см. Ссылку ниже), и передал на заводе ctor HomeController как IStringLocalizerFactory factoryтакже без любви, все еще не получая ресурс fr-CH. Вздох.

Другие заметки:

Используя это в качестве моей основной ссылки: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization

Использование VS 2017, последние обновления, с ASP.Net Core 2.0

2 ответа

Проблема в том, что ASP .NET Core создает неправильное пространство имен RESX для локализации с помощью IStringLocalizer. Если у вас в коде

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

тогда экземпляр внедренной службы IStringLocalizer имеет в пространстве имен дважды "Ресурсы", а пространство имен - "Ресурсы.Ресурсы". Это основная причина, по которой невозможно найти RESX.

Ты используешь IStringLocalizer<HomeController> в качестве локализатора в контроллере для поиска локализованной строки. Локализатор будет искать в Resources папка для поиска YouControllerNameSpace.HomeController файл ресурсов и, поскольку он не находит его, он вернет исходный ключ, который вы передали в локализатор.

Чтобы решить проблему, вы можете использовать любой из следующих вариантов:

  • впрыскивать IStringLocalizer<T>
  • впрыскивать IStringLocalizerFactory

Для получения дополнительной информации об именах файлов ресурсов, посмотрите раздел именования файлов ресурсов в документации.

Внедрить IStringLocalizer

Используя эту опцию, вы должны иметь файл ресурсов с тем же именем, что и полное имя 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 файл ресурсов.
  • Убедитесь, что у вас есть указанная строка в файле ресурсов.
  • Убедитесь, что у вас есть файлы ресурсов для разных культур.

Попробуйте методику, описанную в этом ответе tmg.

В частности, попробуйте добавить строки

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

к вашей функции ConfigureServices()

Другие вопросы по тегам