ASP.NET multi-lingual switching with core MVC built-in features

Page update date :
Page creation date :

Environment

Visual Studio
  • Visual Studio 2019
ASP.NET Core
  • 3.0
  • 3.1

At first

ASP.NET use core MVC localization features to switch between multiple languages to display them.

Create a resource file for translated text

Create a folder to store the resource files (Resx) that manage the text. The location is anywhere, but leave it directly below the route. This path also affects later settings.

Right-click the project and select Add or New Folder.

image

Leave the folder name resources. You can also set this folder name arbitrarily, but you can specify this folder name in later settings.

image

Then create a resource file to enter text for each language.

Right-click the Resources folder and select Add or New Item.

image

Select the resource file (.resx). The file name can be arbitrary, but it must match the name you specify later. For now, let's say SharedResource.resx.

image

After you create the .resx file, double-click to open it, and then type the name that identifies the text and the text that you want to actually display. The SharedResource.resx file is the file to be used if the language does not exist. I entered it in Japanese here. If you want other languages, such as English, to be the default, enter them in that language.

Here we enter Hello and Goodbye as samples. Note that it is case sensitive.

image

Continue to create resource files for other languages. To identify the language, specify the file name, such as SharedResource.<Culture Code>.resx. You can specify one or both combinations of ISO 639 and ISO 3166 for the culture code. Support code is subject to change from time to time, so the CultureInfo class on the Microsoft site Please refer to the page.

This time, en (English) and es (Spanish) are prepared. Japanese is not available because it is the default.

image

Enter the translated text with the keys in the same state for each file.

image

image

Next, you'll have a file that defines only the classes. You create this with the same name as the resource file you just created.

In fact, i don't care what the name of the code file itself is because you only have to match the name of the class inside, but leave it the same so that it is easy to understand. It doesn't matter where you want to write the code.

image

Make the namespace the root of the project and create an empty class.

namespace LocalizationText
{
  // クラス名は作成した .resx のファイル名と同じにする必要がある
  public class SharedResource { }
}

Fix each program

Startup.cs

Fix Startup.cs. Describe the ConfigureServices method as follows:

Services. AddMvc(). If there is an AddViewLocalization method, the text translated by both the view side and the controller side is I'm sure i can get it, but As is also on the official website services. There is no problem with calling the AddLocalization method together.

Options. ResourcesPath specifies the path of the folder where the Resx file is located. If both are specified, services. AddMvc(). The AddViewLocalization method takes precedence.

public void ConfigureServices(IServiceCollection services)
{
  services.AddControllersWithViews();

  // Resx ファイルのあるフォルダを指定する。
  // コントローラー側でしか使用しないならこちらでもよい。AddViewLocalization を使用するならこちらはなくても動作する。
  //services.AddLocalization(options => options.ResourcesPath = "Resources");

  services.AddMvc()
    // ローカライズに必要。Resx ファイルのフォルダパスを指定
    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix, opts => { opts.ResourcesPath = "Resources"; });
}

Then modify the Configure method for Startup.cs. If you just want to read the resource file, you don't need it. Code that is required to allow the user to specify a language arbitrarily.

We're using the features built in ASP.NET Core MVC as standard. The following code describes the "query string", "cookie", and "Accept-Language HTTP header" depending on the user's environment. You can switch between display languages in one of them. We'll see you later how to check the actual operation.

The switchable language is specified here in the array (supportedCultures). I specified ja as the default language, but I haven't created the ja file this time. SharedResource.resx is used if a language other than en, es is specified.

You can separate the UI from the languages you support, but there's not much benefit to separating it. You have the same language.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
  if (env.IsDevelopment())
  {
    // 省略
  }

  // 標準の機能で切り替えたい言語を定義します。
  var supportedCultures = new[]
  {
    new CultureInfo("ja"),
    new CultureInfo("en"),
    new CultureInfo("es"),
  };

  // 標準の言語切り替え機能を有効にします。対応しているのは「クエリ文字列」「Cookie」「Accept-Language HTTP ヘッダー」です。
  app.UseRequestLocalization(new RequestLocalizationOptions
  {
    DefaultRequestCulture = new RequestCulture("ja"),
    SupportedCultures = supportedCultures,
    SupportedUICultures = supportedCultures
  });

  app.UseHttpsRedirection();
  app.UseStaticFiles();

  // 省略
}

Controllers\HomeController.cs

Controllers\HomeController.cs file. To get a localized language on the controller side, iStringLocalizer is received in the constructor. SharedResource must have the same name as the class that you created earlier. The text is passed to the importer of the received localizer by passing the key string entered in the resource file. can be retrieved. The language of the text is determined based on the culture being requested.

By the way, in addition to IStringLocalizer, there is also an IHtmlLocalizer that can get HTML as it is.

public class HomeController : Controller
{
  private readonly ILogger<HomeController> _logger;
  private readonly IStringLocalizer<SharedResource> _localizer;

  // DI でローカライザーを取得します。
  public HomeController(ILogger<HomeController> logger, IStringLocalizer<SharedResource> localizer)
  {
    _logger = logger;
    _localizer = localizer;
  }

  public IActionResult Index()
  {
    // ローカライザーを使用して設定されている言語のリソースファイルからテキストを取得します。
    ViewData["Message"] = _localizer["Goodbye"];

    return View();
  }

  // 省略
}

Views\_ViewImports.cshtml

Views\_ViewImports.cshtml file. To use a localizer on the view side, you must inject IHtmlLocalizer. If you describe it as follows for now, it is OK. Also, SharedResource must have the same name as the resource file and class you created earlier.

IHtmlLocalizer is in the Microsoft.AspNetCore.Mvc.Localization namespace, so i'll define this as using.

If you only want to use the localizer at a certain point, you can include the following code in a separate view file. If you write it in a _ViewImports.cshtml file, you will automatically be able to use it in all view files.

@using LocalizationText
@using LocalizationText.Models
@using Microsoft.AspNetCore.Mvc.Localization
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@* ビュー側でローカライザーを使用できるように定義します *@
@inject IHtmlLocalizer<SharedResource> Localizer

Views\Home\Index.cshtml

Views\Home\Index.cshtml file. The text obtained on the controller side and the text obtained directly on the view side are displayed respectively. The view-side localizer also gets the text by specifying a key string for the indexer.

@{
    ViewData["Title"] = "Home Page";
}

<div class="text-center">
  <h1 class="display-4">Welcome</h1>
  <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

@* ローカライザーから取得したテキストを表示します。 *@
<p>@Localizer["Hello"]</p>
<p>@ViewData["Message"]</p>

Check operation

Query string

You can switch the display language by specifying a culture code in the query string of the URL. The format is ?culture=<culture code>. If you want to separate it from the UI, it will be ?culture=<culture code>&ui-culture=<culture code>.

If you do not specify anything: If not specified, SharedResource.resx is used. (In fact, another judgment has been applied...)

image

The pattern specified for ?culture=en. The display language is English.

image

The pattern specified for ?culture=es. The display language is Spanish.

image

The pattern specified for ?culture=ja. Originally, the SharedResource.ja.resx file is used. SharedResource.resx is used because it does not exist.

image

Try to specify a language that doesn't exist. SharedResource.resx is used because there is no corresponding file here.

image

Cookies

Cookies can switch the display language. Normally published from the server side, but this time i'll try to register cookies directly in the browser function.

Because each Web browser has a developer tool, you use it to register cookies. In the figure below, you can press F12 on Edge to display the developer tools.

The name of the corresponding cookie is . AspNetCore.Culture, and the value that specifies the language is Enter in the form of c=<culture code>|uic=<culture code>. For cookies, you must also enter the ui code. Once you have registered your cookie, refresh your web browser page to refresh it. A cookie is sent to the server so that the server will retrieve the specified language.

In the figure below, you can enter c=en|uic=en to display English.

image

type c=es|uic=es to display Spanish.

image

Accept-Language HTTP header

The Accept-Language HTTP header checks the header information requested from the Web browser to the server. It is the ability to switch languages accordingly.

You can send any Accept-Language in your Web browser settings, but by default you can match the os language settings. Accept-Language is now sent. (Whether or not it is actually sent depends on the OS and web browser.) The language is initialized in the Web browser for the language of the OS, but it may be correct.)

So, for example, as shown in the figure below, you can open the page in the Web browser of the English-language OS and send en information, so you can automatically SharedResource.en.resx is selected to display English.

image

If you try to specify a language that does not exist in the query string, you should originally use SharedResource.resx. Accept-Language displays English because en exists.

image

If ja is specified in the query string, the query string takes precedence and japanese is displayed.

image

Summary

Here i tried to implement the multilingual switching in the easiest way. To switch languages to match the user's environment, use the Accept-Language HTTP header as the default display language. If the user chooses any language, it is a good idea to add cookies or add (or enter directly) of the query string.