Localization in ASP.NET Core 1.0 and MVC 6

By Dawid on (tags: asp.net core 1.0, localization, mvc6, categories: code)

Previous ASP.NET localization approach was quite old. It was just based on resources and there was nothing wrong with this but lot of projects uses other sources of localized texts (for example database). In ASP.NET Core 1.0 it’s completely rewritten!

Configuring Localization middleware

The localization is configured in Startup class, where we need to enable Localization middleware inside our application. All we need to do is to call UserRequestLocalization() providing some basic options.

Take a look:

   1: public void ConfigureServices(IServiceCollection services)
   2: {
   3:     ...
   4:     services.AddLocalization(options => options.ResourcesPath = "Resources");
   5:     services.AddMvc()
   6:         .AddViewLocalization()
   7:         .AddDataAnnotationsLocalization();
   8: }
   9:  
  10:  
  11: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  12: {
  13:     ...
  14:     RequestLocalizationOptions localizationOptions = new RequestLocalizationOptions
  15:     {
  16:         SupportedCultures = new List<CultureInfo> {new CultureInfo("en-US"), new CultureInfo("de-DE")},
  17:         SupportedUICultures = new List<CultureInfo> {new CultureInfo("en-US"), new CultureInfo("de-DE")}
  18:     };    
  19:     app.UseRequestLocalization(localizationOptions, new RequestCulture("en-US"));
  20:     ...
  21: }

Ok, but how Localization middleware sets proper culture. The middleware first determines the default culture if all other methods fail. By default this is the culture settings of the current thread, but we can override that by in the UserRequestLocalization method (showed above). Then the middleware goes through the list of Request Culture Providers, and see whether any of them can determine the culture. If any of them can, then it uses that as the culture. If none of them can, then if uses the default culture which it determined at the beginning of the method.

Possible request culture providers are:

  • QueryStringRequestCultureProvider
  • CookieRequestCultureProvider
  • AcceptLanguageHeaderRequestCultureProvider

With all those information order in which correct culture is determined is:

  1. From the query string
  2. From cookie
  3. From Accept-Language HTTP header
  4. From default request culture specified in UserRequestLocalization method
  5. From the thread culture

The Factory and Provider

Everything described above really matters if our application can’t access the resources. ASP.NET 5 introduces two interfaces:

  • IStringLocalizerFactory
  • IStringLocalizer

 

   1: public interface IStringLocalizerFactory
   2: {
   3:     IStringLocalizer Create(Type resourceSource);
   4:     IStringLocalizer Create(string baseName, string location);
   5: }
   6:  
   7: public interface IStringLocalizer
   8: {
   9:     LocalizedString this[string name] { get; }
  10:     LocalizedString this[string name, params object[] arguments] { get; }
  11:     IEnumerable<LocalizedString> GetAllStrings(bool includeAncestorCultures);
  12:     IStringLocalizer WithCulture(CultureInfo culture);
  13: }

Factory known hot to create instance of localizer and is invoked by the framework itself and then passed to the components which requires it. Dependency injection framework requires the factory to be registered but not the localizer.

Of course we can override localizer and thanks to that we can access translations stored in different placed – for example in the database.

Usage

But how to use all those things on the frontend. By calling AddViewLocalization in the ConfigureServices method located in Startup class we are able to use couple of classes introduced in new framework. Those are IHtmlLocalizer and corresponding factory IHtmlLocalizerFactory.

Here is an example usage in controller:

   1: private IHtmlLocalizer<HomeController> _localizer;
   2:  
   3: public HomeController(IHtmlLocalizer<HomeController> localizer)
   4: {
   5:     _localizer = localizer;
   6: }
   7:  
   8: public ActionResult Index()
   9: {
  10:     ViewBag.SimpleMessage = _localizer["This is my message."];
  11:     return View();
  12: }

And we can use it directly in the view. With combination with dependency injection framework we can do really awesome things. Open _ViewImports.cshtml and add there following line:

   1: @inject IViewLocalizer Localization

This will give access to LocString in all of the views, so that we will be able to use something like this in our views:

   1: @Localization["Hello everyone!"]

Storing translations

MVC by the default is implemented to use the default resource providers, so it will look for resource files that are named like the view. For example, we can have Views.Home.Index.cshtml.en-US.resx . This will be picked up by default. So, this is the easiest way to try it out.

Another way is to implement your own IStringLocalizerFactory  and IStringLocalizer . We just have to remember to register the factory in the ConfigureServices  method:

   1: services.AddTransient<IStringLocalizerFactory, MyStringLocalizerFactory>();