Localization file not effective rendering a Razor page in MVC ASP.NET Core 2.2
Asked Answered
B

1

7

My Razor page looks like this.

@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
<h1>@Localizer["Index"]</h1>
...

My Startup.cs contains the following.

public void ConfigureServices(IServiceCollection services)
{
  ...
  services.AddLocalization(a => a.ResourcesPath = "/");

  services.Configure<RequestLocalizationOptions>(a =>
  {
    CultureInfo[] supportedCultures = {
      new CultureInfo("sv-SE"),
      new CultureInfo("se")
    };
    a.DefaultRequestCulture = new RequestCulture("se");
    a.SupportedCultures = supportedCultures;
    a.SupportedUICultures = supportedCultures;
  });
  ...
}

I placed a file called Controllers.HomeController.se.resx directly in the project's root. The controller HomeController contains the injection.

public class HomeController : Controller
{
  private readonly Context _context;
  private readonly IStringLocalizer<HomeController> _localizer;

  public HomeController(Context context, IStringLocalizer<HomeController> localizer)
  {
    _context = context;
    _localizer = localizer;
  }
  ...
}

The application doesn't crash but the string renedered is Index and not the value from the RESX file. I've tried to follow the docs as closely as possible but apparently I've missed something. I need help finding what that would be.

I breakpointed and checked the value of _localizer["Index"] in the constructor. As expected, the flag for the file not being found is set to true. Checking the value of SearchedLocation gives me Web...Controllers.MemberController. I can't tell if those three dots is the correct one for the RESX file in the project's root. I was expecting se somewhere in the name too.

Breakthrough answered 13/2, 2019 at 21:10 Comment(0)
M
5

If you want to place you resources files in root of the project you should set ResourcesPath as following

services.AddLocalization(a => a.ResourcesPath = ""); //empty string

With this settings SearchedLocation will give you Web.Controllers.MemberController which points to Controllers.MemberController.resx file in the root of the project.

To use localization in view you have to follow Views.{ControllerName}.{ViewName}.resx pattern. For example if you have HomeController and About view in it you need to have Views.Home.About.resx file to use localization.

Another convention resource reader follows when searching for localization files is searching the files in respective folders rather than by dot separated names. For example if ResourcesPath is set to "Resources" the following variants are equal

Resources.Views.Home.About.resx
Resources\Views.Home.About.resx
Resources\Views\Home.About.resx
Resources\Views\Home\About.resx

So it's possible to structure your localization files by folders.

And you didn't specify you added app.UseRequestLocalization() in your Startup.cs. If you don't do this your application won't be able to determine request culture and it will always point to default resource file. Read more in the docs.

Note

There are 2 ways of configuring RequestLocalizationOptions for request localization, via services.Configure<RequestLocalizationOptions> or passing constructed options object (or delegate) to app.UseRequestLocalization. Effectively there is no difference between these approaches, they are totally equal in terms of localization middleware. But if at any point of an application you need to get RequestLocalizationOptions you won't be able to get value passed to app.UseRequestLocalization. But it is easy to accompish with services.Configure<RequestLocalizationOptions> (it's general approach described in the docs)

public class HomeController : Controller
{
    private readonly RequestLocalizationOptions _requestLocalizationOptions;

    public HomeController(IOptions<RequestLocalizationOptions> options)
    {
        _requestLocalizationOptions = options.Value;
    }

    //..
}
Mccune answered 14/2, 2019 at 18:28 Comment(5)
Your bounty comes in 23 hours 59 minutes, mate. The site won't let me provide it already now. Sorry.Breakthrough
Now, what is the default resource file, if nothing else is specified? If I inject IStringLocalization<Lang>, will that point to Lang.resx with no language code?Breakthrough
@Breakthrough Nope, it will point to Lang.resx with language code corresponding to request culture. You can test different cultures by adding ?culture=sv-SE in address barMccune
Your bounty has been awarded. I almost forgot. Good thing SO reminded. That being said, the question is answered, of course, but I wonder if you have a quick tip on a good approach to switching between the lingos. At the moment, I have the default languages set to sv and it works sufficiently. However, sooner or later, I'd like to advance and be able to choose the language. In the menu, I can add a switcher, so the GUI part isn't an issue. But the business logic of changing the RESX being used and storying the selected lingo etc. are areas where I fear I'm going to make poor choices.Breakthrough
@Breakthrough The easiest is using cookie localization. Create action accepting culture as string, create RequestCulture from it then set response cookie by making cookie value using CookieRequestCultureProvider.MakeCookieValue and key CookieRequestCultureProvider.DefaultCookieName. When you set a cookie it will be used in subsequent requests so it will be "stored" so to speak. If you actually want to store user culture in datase then you need to implement own RequestCultureProvider to fetch culture from database by current user. Hope it helps.Mccune

© 2022 - 2024 — McMap. All rights reserved.