本地化
本地化是为给定语言和地区定制应用程序的过程. 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.4 dotnet 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 { [Inject] [NotNull] private IOptionsMonitor<BootstrapBlazorOptions>? BootstrapOptions { get; set; } [Inject] [NotNull] private IStringLocalizer<CultureChooser>? Localizer { get; set; } [Inject] [NotNull] private NavigationManager? NavigationManager { get; set; } private string? ClassString => CssBuilder.Default("culture-selector") .AddClassFromAttributes(AdditionalAttributes) .Build(); private string SelectedCulture { get; set; } = CultureInfo.CurrentCulture.Name; [NotNull] private string? Label { get; set; } /// <summary> /// OnInitialized 方法 /// </summary> protected override void OnInitialized() { base.OnInitialized(); Label ??= Localizer[nameof(Label)]; } 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> [Route("[controller]/[action]")] 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{ [Inject] [NotNull] 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 弄
- 特性相关,例如必填项
字段定义
[Required(ErrorMessage = "{0}不能为空")] [AutoGenerateColumn(Order = 10, Filterable = true, Searchable = true)] [Display(Name = "姓名")] public string? Name { get; set; }
资源文件
"Name.Required": "{0}是必填项" "Name.Required": "{0} is required."
效果