Как получить локализованную строку из ASP.NET Core Controller с помощью IStringLocalizer?
Вроде запутался здесь, супер простой привет-пример локализации в ASP.Net Core 2.0. Страница My About настроена для отображения двух локализованных строк:
- С точки зрения (используя
IViewLocalizer
) - Из кода (используя
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()