fdfv232 发表于 2025-2-6 23:46:42

为你的Blazor程序加入本地化多语言功能

本地化

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

简介
BootstrapBlazor 是一套基于 Bootstrap 和 Blazor 的企业级组件库,可以认为是 Bootstrap 项目的 Blazor 版实现。
小提示

阅读以下知识点前请先查看 微软官方文档
由于 wasm 模式无法获取系统语言文化信息,默认文化信息为 en
组件内置本地化资源文件为 en zh 由网友提供的其他本地化资源文件 de es pt zh-TW 放置在项目文件夹 localization 内,可自行下载通过注入服务引入到项目中
本地化在组件中的工作原理

BootstrapBlazor 组件额外支持使用 Json 类型的键值信息作为资源文件,将其解析为 UI 中呈现的字符串。BootstrapBlazor 包自带以下资源文件。

[*]中文(zh)
[*]英语(en)
额外本地化语言 json 文件

[*]德语(de)
[*]葡萄牙语(pu)
[*]西班牙语(es)
[*]中國台灣(zh-TW)
组件库本地化详细资讯链接

https://www.blazor.zone/localization
开始撸码

跟往常一样,CV福音

源码在此.
Bootstrap Blazor App 模板, 快速搭建项目


[*]新建bb模板工程
dotnet new install Bootstrap.Blazor.Templates::9.0.4dotnet new bbapp
[*]加入语言选择功能
右键新建blazor组件 CultureChooser.razor
新建组件步骤参考往期文章
加入如下代码
@inherits BootstrapComponentBase@namespace BootstrapBlazor.Server.Components.Components<div @attributes="@AdditionalAttributes" class="@ClassString">    <span>@Label</span>    <Select Value="@SelectedCulture" OnSelectedItemChanged="@SetCulture">      <Options>            @foreach (var kv in BootstrapOptions.CurrentValue.GetSupportedCultures())            {                <SelectOption Text="@GetDisplayName(kv)" Value="@kv.Name" />            }      </Options>    </Select></div>
新建代码后置文件 CultureChooser.razor.cs
新建代码后置文件步骤参考往期文章
using BootstrapBlazor.Components;using Microsoft.AspNetCore.Components;using Microsoft.Extensions.Localization;using Microsoft.Extensions.Options;using Microsoft.JSInterop;using System.Diagnostics.CodeAnalysis;using System.Globalization;namespace BootstrapBlazor.Server.Components.Components;/// <summary>/// /// </summary>public partial class CultureChooser{            private IOptionsMonitor<BootstrapBlazorOptions>? BootstrapOptions { get; set; }            private IStringLocalizer<CultureChooser>? Localizer { get; set; }            private NavigationManager? NavigationManager { get; set; }    private string? ClassString => CssBuilder.Default("culture-selector")      .AddClassFromAttributes(AdditionalAttributes)      .Build();    private string SelectedCulture { get; set; } = CultureInfo.CurrentCulture.Name;        private string? Label { get; set; }    /// <summary>    /// OnInitialized 方法    /// </summary>    protected override void OnInitialized()    {      base.OnInitialized();      Label ??= Localizer;    }    private async Task SetCulture(SelectedItem item)    {      if (RendererInfo.Name == "Server")      {            // 使用 api 方式 适用于 Server-Side 模式            if (SelectedCulture != item.Value)            {                var culture = item.Value;                var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.SafeUnescaped);                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      {            if (SelectedCulture != item.Value)            {                var culture = item.Value;                await JSRuntime.InvokeVoidAsync("bbCulture.set", culture);                NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);            }      }    }    private string GetDisplayName(CultureInfo culture)    {      string? ret;      if (RendererInfo.Name == "Server")      {            ret = culture.NativeName;      }      else      {            ret = culture.Name switch            {                "zh-CN" => "中文(中国)",                "en-US" => "English (United States)",                _ => ""            };      }      return ret;    }}

[*]布局文件添加语言选择
编辑 MainLayout.razor 在<Widget></Widget>后面加入一行
<BootstrapBlazor.Server.Components.Components.CultureChooser />

[*]增加多语言支持配置信息,启用本地化
编辑 Program.cs 在builder.Services.AddBootstrapBlazor();后加入这些代码
// 增加多语言支持配置信息builder.Services.AddRequestLocalization<IOptionsMonitor<BootstrapBlazorOptions>>((localizerOption, blazorOption) =>{    blazorOption.OnChange(Invoke);    Invoke(blazorOption.CurrentValue);    return;    void Invoke(BootstrapBlazorOptions option)    {      var supportedCultures = option.GetSupportedCultures();      localizerOption.SupportedCultures = supportedCultures;      localizerOption.SupportedUICultures = supportedCultures;    }});builder.Services.AddControllers();然后在var app = builder.Build();后加入这行代码
// 启用本地化var option = app.Services.GetService<IOptions<RequestLocalizationOptions>>();if (option != null){    app.UseRequestLocalization(option.Value);}最后在app.MapStaticAssets();后加入这行代码
app.MapDefaultControllerRoute();
[*]添加控制器
新建文件夹Controllers, 新建文件 CultureController.cs
using Microsoft.AspNetCore.Localization;using Microsoft.AspNetCore.Mvc;using RouteAttribute = Microsoft.AspNetCore.Mvc.RouteAttribute;namespace BootstrapBlazor.Controllers;/// <summary>/// 文化 Controller/// </summary>/")]public class CultureController : Controller{    /// <summary>    /// 设置文化方法    /// </summary>    /// <param name="culture"></param>    /// <param name="redirectUri"></param>    /// <returns></returns>    public IActionResult SetCulture(string culture, string redirectUri)    {      if (string.IsNullOrEmpty(culture))      {            HttpContext.Response.Cookies.Delete(CookieRequestCultureProvider.DefaultCookieName);      }      else      {            HttpContext.Response.Cookies.Append(                CookieRequestCultureProvider.DefaultCookieName,                CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture, culture)), new CookieOptions()                {                  Expires = DateTimeOffset.Now.AddYears(1)                });      }      return LocalRedirect(redirectUri);    }    /// <summary>    /// 重置文化方法    /// </summary>    /// <param name="redirectUri"></param>    /// <returns></returns>    public IActionResult ResetCulture(string redirectUri)    {      HttpContext.Response.Cookies.Delete(CookieRequestCultureProvider.DefaultCookieName);      return LocalRedirect(redirectUri);    }}
[*]运行工程

因为模板工程已经带了部分多语言配置, 我们点击Table或者花名册页面就可以看到效果


实践

通过主页面改变欢迎词来练习

代码<SurveyPrompt Title="How is Blazor working for you?" />改为
<SurveyPrompt Title="@Localizer["Wellcome"]" /><SurveyPrompt Title="@Localizer["How is Blazor working for you?"]" />@code{            private IStringLocalizer<Index>? Localizer { get; set; }}在这里我们写了两行@Localizer,先买个关子,运行时候看看是什么效果.

添加本地化资源
分别在Locales/zh.json和Locales/en.json添加对应的文字
"BootstrapBlazorApp.Server.Components.Pages.Index": {    "Wellcome": "Blazor 对你有什么帮助?"}"BootstrapBlazorApp.Server.Components.Pages.Index": {    "Wellcome": "How is Blazor working for you?"}

运行工程


现在可以看到效果了, 找到资源的已经正确显示对应文本, 未找到资源的,会回落显示为key.
TIPS


[*]格式化
资源文件
"Foo.Address2": "地球、中国、上海市普陀区金沙江路 {0} 弄 这里是超长单元格示例"c#
var i=1274;localizer["Foo.Address", i]效果
上海市普陀区金沙江路 1274 弄
[*]特性相关,例如必填项
字段定义
                public string? Name { get; set; }资源文件
"Name.Required": "{0}是必填项""Name.Required": "{0} is required."效果


组件库本地化详细资讯链接

https://www.blazor.zone/localization
TIPS

问:如果我想定制一下组件库的本地化资源,比如表格组件的添加按钮文本,该怎么做呢?
答:对应资源文件里加入对应组件类的字段就行
比如, 中文资源 Locales\zh.json
"BootstrapBlazor.Components.Table": {    "AddButtonText": "添了个加"}
英文资源 Locales\zh.json
"BootstrapBlazor.Components.Table": {    "AddButtonText": "Add a life"}
页: [1]
查看完整版本: 为你的Blazor程序加入本地化多语言功能