Kinda confused here, super simple hello-world example of localization in ASP.Net Core 2.0. My About page is set up to render two localized strings:
IViewLocalizer
)IStringLocalizer<HomeController>
via the controller)The code in the controller refuses to get the loc string appropriately. This is not complicated, what obvious things am I missing?
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>
^ Note the two strings: "Message" will be localized from code using IStringLocalizer
(see HomeController below), and the @Localizer will use the IViewLocalizer
class.
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 (relevant parts)
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?}");
});
}
Resources:
Views.Home.About.fr-CH.resx
^ with two values in it:
My Results:
localhost:56073/Home/About
^ This renders the strings as expected in en-US (default finds nothing, uses the strings actually hard coded)
localhost:56073/Home/About?culture=fr-CH
^ This renders ONLY the 2nd string: "Use this area... success for fr-CH!", which clearly means all the code wired up is working and finding the fr-CH.resx as expected.
BUT, the first string (set in code as ViewData["Message"]
) does NOT get the fr-CH version! It's like the IStringLocalizer<HomeController>
failed to realize there was a lang specified, or failed to find the fr-CH.resx that is clearly available.
Why???
Also BTW, I tried using the ShareResource example too (see link below), and passed in the factory to the HomeController ctor as IStringLocalizerFactory factory
, also with no love, still not getting the fr-CH resource. Sigh.
Other notes:
Using this as my primary reference: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization
Using VS 2017, latest updates, with ASP.Net Core 2.0
The issue is that ASP .NET Core creates wrong RESX namespace for localization using IStringLocalizer. If you have in the code
services.AddLocalization(options => options.ResourcesPath = "Resources");
then the instance of injected service IStringLocalizer has in the namespace twice "Resources", namespace looking "Resources.Resources" . This is the root cause why the RESX cannot be found.
You are using IStringLocalizer<HomeController>
as localizer in the controller to find the localized string. The localizer will look in Resources
folder to find YouControllerNameSpace.HomeController
resource file and since it doesn't find it, it will return the original key which you passed to the localizer.
To solve the problem, you can use either of following options:
IStringLocalizer<T>
IStringLocalizerFactory
For more information about resource file names, take a look at Resource file naming section in documentations.
Using this option, you should have a resource file with the same name as full name of T, in your case, the controller code should be the same as it is:
IStringLocalizer _localizer;
public HomeController(IStringLocalizer<HomeController> localizer)
{
_localizer = localizer;
}
For the resource file:
YouControllerNameSpace.HomeController
resource file. (YouControllerNameSpace
is just a placeholder, use your controller namespace.)Using this option you can use any file as resource file. For example if you want to read resources from Views.Home.About
resource file, you should change the controller code to this:
IStringLocalizer _localizer;
public HomeController(IStringLocalizerFactory factory)
{
_localizer = factory.Create("Views.Home.About",
System.Reflection.Assembly.GetExecutingAssembly().GetName().Name);
}
For the resource file:
Views.Home.About
resource file.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With