Blazor Server App 實作多國語系紀錄

Localization, Globalization, NET5, NET6

補充 on 2024-4-18

先總結成果

需安裝套件

Install-Package Microsoft.Extensions.Localization

調整相關檔案清單

未完事項

DataAnnotations 之 Form Validation 在地中文化試不出來。

appsettings.json

appsettings.json
{
  "AllowedHosts": "*",
  "Cultures": {  ///--- 決定要支援的語系
    "en-US": "USA",
    "es-ES": "Spain",
    "es-MX": "Mexico",
    "zh-TW": "台灣"  
  }
}

Startup.cs

Startup.cs
public class Startup
{
	...
	
	public void ConfigureServices(IServiceCollection services)
	{
		///# for 多國語系
		services.AddLocalization(options => options.ResourcesPath = "Resources");
		services.Configure<RequestLocalizationOptions>(options =>
		{
		  // 自 appsettings 取得要支援的語系
			var cultures = Configuration.GetSection("Cultures").GetChildren().ToDictionary(x => x.Key, x => x.Value);
			var supoortedCultures = cultures.Keys.ToArray();

			// 加入組態
			options.AddSupportedCultures(supoortedCultures);
			options.AddSupportedUICultures(supoortedCultures);
			options.SetDefaultCulture("zh-TW");
			options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("zh-TW");
		});

		services.AddRazorPages();
		services.AddServerSideBlazor();
		...
	}

	public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
	{
		...
		app.UseStaticFiles();

		///# for 多國語系 - 啟用
		app.UseRequestLocalization();

		app.UseRouting();
		...
	}
}

Language.cshtml.cs

Pages/Language.cshtml
@page
@model BlazorServerApp.Pages.LanguageModel

@* 這是虛畫面 *@
<h2>Language</h2>
<p>用於多國語系切換。</p>
Pages/Language.cshtml.cs
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace BlazorServerApp.Pages
{
    public class LanguageModel : PageModel
    {
        /// 切換語系
        public IActionResult OnGet(string culture, string redirectUrl)
        {
            if (culture != null)
            {
                /// 設定多國語系到 Cookie 指定的位置與編碼。
                HttpContext.Response.Cookies.Append(
                    CookieRequestCultureProvider.DefaultCookieName,
                    CookieRequestCultureProvider.MakeCookieValue(
                        new RequestCulture(culture)));
            }

            /// 將依選取語系刷新回原畫面。
            return LocalRedirect(redirectUrl);
        }
    }
}

ChooseLanguage.razor

Shared/ChooseLanguage.razor
@inject NavigationManager navMan
@inject IConfiguration cfgSvc 

@if (cultures != null)
{
    @* 語系切換介面 *@
    <form class="form-inline">
        <select class="form-control mr-2" @bind="selectedCulture">
            <option>選取…</option>
            @foreach (var culture in cultures)
            {
                <option value="@culture.Key">@culture.Value</option>
            }
        </select>
        <button class="btn btn-outline-primary" @onclick="RequestCultureChange">Change</button>
    </form>
}

@code{
    string selectedCulture;
    Dictionary<string, string> cultures;

    protected override void OnInitialized()
    {
        selectedCulture = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
        cultures = cfgSvc.GetSection("Cultures").GetChildren().ToDictionary(x => x.Key, x => x.Value);
    }

    void RequestCultureChange()
    {
        if (String.IsNullOrWhiteSpace(selectedCulture)) 
            return;

        var redirectUrl = new Uri(navMan.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);

        var queryString = $"?culture={Uri.EscapeDataString(selectedCulture)}&redirectUrl={Uri.EscapeDataString(redirectUrl)}";

        navMan.NavigateTo($"/Language{queryString}", forceLoad: true);
    }
}

Resource 目錄

放置各語系資料,最主要的工作內容之一。如圖例:

Blazor App 多國語言組態

應用

可以用 CultureInfo 類別取得現在的語系。 使用 IStringLocalizer<T>拿取目標語系資料,可以一次拿多份語系資料。 其他日期、時間的預設顯示格式也會依語系文化不同而不同。

FooPage.razor
@using Microsoft.Extensions.Localization
@using System.Globalization
@page "/culture"
@inject IStringLocalizer<Pages.A04Culture._PageCtx> localizer
@inject IStringLocalizer<App> locCommon

<h1>語系與文化資訊</h1>

@* === 測試語系是否成功切換, 日期時間格式是否依語系不同而改變 === *@

<h2>@localizer["您好"]</h2>
<h2>@DateTime.Now.ToShortDateString() @DateTime.Now.ToShortTimeString()</h2>
<h2>@DateTime.Now.ToLongDateString() @DateTime.Now.ToLongTimeString()</h2>

@* === 測試參數化訊息的語系切換 === *@
<p>@String.Format(localizer["模擬錯誤訊息:{0}"], simsErrMsg)</p>

@* === 可以用 CultureInfo 類別取得現在的語系 === *@
<table>
    <tr>
        <th>Current Culture</th>
        <td>@CultureInfo.CurrentCulture</td>
    </tr>
    <tr>
        <th>Current UI-Culture</th>
        <td>@CultureInfo.CurrentUICulture</td>
    </tr>
    <tr>
        <th>Default Thread Current Culture</th>
        <td>@CultureInfo.DefaultThreadCurrentCulture</td>
    </tr>
    <tr>
        <th>Default Thread Current UI-Culture</th>
        <td>@CultureInfo.DefaultThreadCurrentUICulture</td>
    </tr>
</table>


@code{
    string simsErrMsg = "老婆永遠是對的。";

    protected override void OnAfterRender(bool firstRender)
    {
        base.OnAfterRender(firstRender);
    }
}

參考資料

EOF

Last updated