本地化

本地化是为给定语言和地区定制应用程序的过程。BootstrapBlazor 组件允许您将其 UI 元素转换为所需的语言。这包括按钮、过滤器操作符属性等文本。组件内部默认使用当前请求 UI 文化语言,本文将向您展示如何在应用程序中使用此功能:

本地化在组件中的工作原理

BootstrapBlazor 组件额外支持使用 Json 类型的键值信息作为资源文件,将其解析为 UI 中呈现的字符串。BootstrapBalzor 包自带中文(zh)、英语(en)两种资源文件。组件内置本地化语言回退机制,如请求文化为 zh-CN 时,如未提供相对应的文化资源文件时,内置逻辑通过父级文化进行尝试本地化,以 zh-CN 为例回退机制如下:
zh-CNzh
如果设置的本地化语言未提供资源文件回落后仍无法找到资源文件后,使用 FallbackCulture 参数设置的文化信息进行本地化,默认为 en

开启本地化功能

Server-Side App

1. 配置文件

通过 FallbackCultureName 设置回退文化信息,即未找到当前请求的文化信息时使用此配置文化,通过 SupportedCultures 设置支持的文化集合

{
  "BootstrapBlazorOptions": {
    "FallbackCultureName": "en",
    "SupportedCultures": [
      "zh-CN",
      "en-US"
    ]
  }
}

2. 启用 .NET 核心本地化服务

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // 增加 BootstrapBlazor 组件
        services.AddBootstrapBlazor();

        // 增加本地化服务配置信息
        services.AddRequestLocalization<IOptions<BootstrapBlazorOptions>>((localizerOption, blazorOption) =>
        {
            var supportedCultures = blazorOption.Value.GetSupportedCultures();

            localizerOption.SupportedCultures = supportedCultures;
            localizerOption.SupportedUICultures = supportedCultures;
        });
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        // 启用本地化中间件并设置支持的文化信息
        app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>()!.Value);
    }
}

3. 实现 UI 本地化信息存储(例如,cookie)

[Route("[controller]/[action]")]
public class CultureController : Controller
{
    public IActionResult SetCulture(string culture, string redirectUri)
    {
        if (!string.IsNullOrEmpty(culture))
        {
            HttpContext.Response.Cookies.Append(
                CookieRequestCultureProvider.DefaultCookieName,
                CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture, culture)));
        }

        return LocalRedirect(redirectUri);
    }

    public IActionResult ResetCulture(string redirectUri)
    {
        HttpContext.Response.Cookies.Delete(CookieRequestCultureProvider.DefaultCookieName);

        return LocalRedirect(redirectUri);
    }
}

3. 添加允许用户更改本地化的 UI

@inherits BootstrapComponentBase
@inject IOptions<BootstrapBlazorOptions> BootstrapOptions
@inject NavigationManager NavigationManager
@inject ICultureStorage CultureStorage

<div @attributes="@AdditionalAttributes" class="@ClassString">
    <label>请选择语言:</label>
    <Select Value="@SelectedCulture" OnSelectedItemChanged="@SetCulture">
        <Options>
            @foreach (var kv in Configuration.GetSupportCultures())
            {
                <SelectOption Text="@kv.Key" Value="@kv.Value" />
            }
        </Options>
    </Select>
</div>

@code {
    private string? ClassString => CssBuilder.Default("culture-selector")
        .AddClassFromAttributes(AdditionalAttributes)
        .Build();

    private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;

    private async Task SetCulture(SelectedItem item)
    {
        if (CultureStorage.Mode == CultureStorageMode.Webapi)
        {
            // 使用 api 方式 适用于 Server-Side 模式
            if (SelectedCulture != item.Value)
            {
                var culture = item.Value;
                var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
                var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";

                // use a path that matches your culture redirect controller from the previous steps
                NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
            }
        }
        else
        {
            var cultureName = item.Value;
            if (cultureName != CultureInfo.CurrentCulture.Name)
            {
                await JSRuntime.InvokeAsync<string>(identifier: "$.blazorCulture.set", cultureName);
                var culture = new CultureInfo(cultureName);
                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;

                NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
            }
        }
    }
}

4. 附加 Json 资源文件

BootstrapBlazor 组件库即支持微软默认的 resx 格式资源,也支持嵌入式 json 格式资源,以及特定物理 json 文件

资源文件为合并关系,寻址规则优先级为
  • 微软 resx 嵌入式资源文件
  • 外置 json 物理文件
  • json 嵌入式资源文件
  • 内置 json 资源文件

public void ConfigureServices(IServiceCollection services)
{
    services.AddBootstrapBlazor(setupAction: options =>
    {
        // 设置 RESX 格式多语言资源文件 如 Program.{CultureName}.resx
        options.ResourceManagerStringLocalizerType = typeof(Program);

        // 设置 Json 格式嵌入式资源文件
        options.AdditionalAssemblies = new[] { typeof(BootstrapBlazor.Shared.App).Assembly };

        // 设置 Json 物理路径文件
        options.AdditionalJsonFiles = new string[]
        {
            @"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-TW.json",
            @"D:\Argo\src\BootstrapBlazor\src\BootstrapBlazor.Server\Locales\zh-CN.json"
        };
    });
}

Web Assembly

1. 启用 .NET 核心本地化服务

public static async Task Main(string[] args)
{
    var builder = WebAssemblyHostBuilder.CreateDefault(args);

    builder.RootComponents.Add<App>("app");

    builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

    // 增加 BootstrapBlazor 组件
    builder.Services.AddBootstrapBlazor();

    builder.Services.AddSingleton<ICultureStorage, DefaultCultureStorage>();

    // 增加本地化
    builder.Services.Configure<BootstrapBlazorOptions>(op =>
    {
        op.ToastDelay = 4000;
        op.SupportedCultures = new List<string> { "zh-CN", "en-US" };
    });

    var host = builder.Build();

    await GetCultureAsync(host);

    await host.RunAsync();
}

private static async Task GetCultureAsync(WebAssemblyHost host)
{
    var jsRuntime = host.Services.GetRequiredService<IJSRuntime>();
    var cultureName = await jsRuntime.InvokeAsync<string>("$.blazorCulture.get") ?? "zh-CN";
    var culture = new CultureInfo(cultureName);
    CultureInfo.DefaultThreadCurrentCulture = culture;
    CultureInfo.DefaultThreadCurrentUICulture = culture;
}

internal class DefaultCultureStorage : ICultureStorage
{
    public CultureStorageMode Mode { get; set; } = CultureStorageMode.LocalStorage;
}

2. 实现 UI 本地化信息存储(例如,localStorage)

与 Server-Side 一致

更改默认语言设置

public static async Task Main(string[] args)
{
    // 设置默认文化为 zh-CN
    CultureInfo.CurrentCulture = new CultureInfo("zh-CN");
    CultureInfo.CurrentUICulture = new CultureInfo("zh-CN");

    // ...

    var host = builder.Build();

    await GetCultureAsync(host);

    await host.RunAsync();
}

B 站相关视频链接

[传送门]
Themes
Bootstrap
Ant Design (完善中)
Bluma (完善中)
LayUI (完善中)
An error has occurred. This application may no longer respond until reloaded. Reload