プログラムを中心とした個人的なメモ用のブログです。 タイトルは迷走中。
内容の保証はできませんのであしからずご了承ください。

2018/12/27

ASP.NET Core のアプリケーションから言語を切り替える

event_note2018/12/27 8:35

ASP.NET Core で作成した Web アプリケーションにおいて、ユーザーが Web サイト上で言語を切り替えられるようにする方法です。

基本的には以下に書いてあります。

んで、サンプルコードが GitHub にあります。

若干説明不足な気もするので、メモとして書いておきます。

環境

  • Visual Studio 2017
  • ASP.NET Core 2.1

カルチャーの登録

Startup.csConfigureServices メソッドで RequestLocalizationOptions の設定を行います。

services.Configure<RequestLocalizationOptions>(options =>
{
    var supportedCultures = new[]
    {
        new CultureInfo("en"),
        new CultureInfo("ja"),
    };

    // State what the default culture for your application is. This will be used if no specific culture
    // can be determined for a given request.
    options.DefaultRequestCulture = new RequestCulture(culture: "en", uiCulture: "en");

    // You must explicitly state which cultures your application supports.
    // These are the cultures the app supports for formatting numbers, dates, etc.
    options.SupportedCultures = supportedCultures;

    // These are the cultures the app supports for UI strings, i.e. we have localized resources for.
    options.SupportedUICultures = supportedCultures;
});

Configure メソッドで設定を適用します。

var locOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>();
app.UseRequestLocalization(locOptions.Value);

View

言語を切り替える UI を部分ビューとして Views/Shared/_SelectLanguagePartial.cshtml に作成します。
以下はサンプルコードそのままです。

@using Microsoft.AspNetCore.Builder
@using Microsoft.AspNetCore.Http.Features
@using Microsoft.AspNetCore.Localization
@using Microsoft.AspNetCore.Mvc.Localization
@using Microsoft.Extensions.Options

@inject IViewLocalizer Localizer
@inject IOptions<RequestLocalizationOptions> LocOptions

@{
    var requestCulture = Context.Features.Get<IRequestCultureFeature>();
    var cultureItems = LocOptions.Value.SupportedUICultures
        .Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })
        .ToList();
    var returnUrl = string.IsNullOrEmpty(Context.Request.Path) ? "~/" : $"~{Context.Request.Path.Value}";
}

<div title="@Localizer["Request culture provider:"] @requestCulture?.Provider?.GetType().Name">
    <form id="selectLanguage" asp-controller="Home" 
          asp-action="SetLanguage" asp-route-returnUrl="@returnUrl" 
          method="post" class="form-horizontal" role="form">
        <label asp-for="@requestCulture.RequestCulture.UICulture.Name">@Localizer["Language:"]</label> <select name="culture"
          onchange="this.form.submit();"
          asp-for="@requestCulture.RequestCulture.UICulture.Name" asp-items="cultureItems">
        </select>
    </form>
</div>

ただ、このコードでは、コンボボックスの選択肢が常に日本語で表示されました。
英語に変更するには、以下の行

.Select(c => new SelectListItem { Value = c.Name, Text = c.DisplayName })

DisplayNameEnglishName に変更します。

そして、この部分ビューを Views/Shared/_Layout.cshtmlfooter で呼び出し、画面下部に常に表示されるようにします。
これもサンプルコードそのままです。

<div class="container body-content" style="margin-top:60px">
    @RenderBody()
    <hr>
    <footer>
        <div class="row">
            <div class="col-md-6">
                <p>© @System.DateTime.Now.Year - Localization</p>
            </div>
            <div class="col-md-6 text-right">
                @await Html.PartialAsync("_SelectLanguagePartial")
            </div>
        </div>
    </footer>
</div>

コンボボックスで言語を変更したときの処理を site.js に書きます。

(function () {
    $("#selectLanguage select").change(function () {
        $(this).parent().submit();
    });
}());

Controller

前述の View では、コンボボックスを切り替えた際に HomeControllerSetLanguage というアクションメソッドがコールされるようになっているので、それを実装します。
これもサンプルコードそのままです。

[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) }
    );

    return LocalRedirect(returnUrl);
}

以上で完了です。