Blazor Webassembly本地化的实现
如果要支持Blazor WebAssembly的本地化,应该如何实现呢?下面,我们就按照本地化问题操作中所涉及的所有主要问题以提问的方式进行说明。
1.本地化的核心原理是什么?
答:就是显式地在Program.Main方法中设置 CultureInfo.DefaultThreadCurrentCulture和CultureInfo.DefaultThreadCurrentUICulture这两个属性。
2. 用户选择的本地化语言设置的值存放在哪里?
有三种主要方式,第一种是存放在本地,这种优点是不涉及与服务器的网络交互,能节省一点的服务器端和网络的资源消耗,缺点是,换了客户端就要重新设置。
第二种是存放在服务器端。这种方式优点是语言本地化设置不随着客户端的变更而变更,客户体验好,缺点就是与服务器有资源消化,在服务端不但要写Api接口,还要存储,还要考虑负载等一系列问题。
第三种,就是将前面两种方式都结合起来,服务端和客户端都存储,如果换了客户端,客户端没有存储,就去服务端查找相应设置。客户端有,就不去查询服务器设置。这种方式结合了前面两种的优点,算是比较完美的方案。
因为第一种方式的影响甚微,相对一直使用一种客户端的用户来说,用户换客户端的机会相对较少。通常对于用户来说,也是可以接受的,我在这里采取第一种方式首先予以说明。
3. 那么我们要将本地化设置要存放在本地浏览器的什么地方,如何实现呢?
答案是localStorage,我们只需要在wwwroot/index.html文件中加入一段js代码,就可以搞定这一步。
<script> window.blazorCulture = { get: () => window.localStorage['BlazorCulture'], set: (value) => window.localStorage['BlazorCulture'] = value }; </script>
4. 如何将第三个问题存放的设置取出来,赋给第一步说到的两个属性,以便本地化起作用?
通过在Program.Main方法中,可以通过C#与js的交互来获取到相应设置。只要在host.RunAsync()之前调用下面定义的这个方法就完成了相关操作:
static async Task GetCulture(WebAssemblyHost host) { var jsInterop = host.Services.GetRequiredService<IJSRuntime>(); var result = await jsInterop.InvokeAsync<string>("blazorCulture.get"); if (result != null) { var culture = new CultureInfo(result); CultureInfo.DefaultThreadCurrentCulture = culture; CultureInfo.DefaultThreadCurrentUICulture = culture; } }
调用上段方法具体为:
builder.Services.AddApiAuthorization(); var host = builder.Build(); await GetCulture(host); await host.RunAsync();
5.第四个问题说到了本地化设置的获取,没有提到设置并保存,那么应该怎样设置和保存?
要选择和设置本地化语言,当然就要给用户提供交互UI界面,要提供这样的界面,可以定义一个Blazor组件,如命名为CultureSelector.razor,将其添加到Shared文件夹中。
首先,这个组件要选择语言选项,那么肯定需要一个选择列表来列出相关语言以便供选择,这就用到了html中的<select>标签。
再者,还要将用户所选选项值保存,又要调用第三个问题中js代码,这就涉及到了C#与js的交互。
最后,设置完了,并保持了,你需要刷新你的页面,以便你的本地化设置生效,并呈现给用户,这就需要强制刷新。
上面所涉及到的,都需要在CultureSelector.razor这个组件中完成,具体的代码如下所示。最后,将组件的标签<CultureSelector />写在你的目标页面的具体位置以给用户呈现。
@using System.Globalization @inject IJSRuntime JSRuntime @inject NavigationManager Nav <select @bind="Culture"> @foreach (var culture in supportedCultures) { <option value="@culture">@culture.Name.Split()[0]</option> } </select> @code { CultureInfo[] supportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("zh-CN"), }; CultureInfo Culture { get => CultureInfo.CurrentCulture; set { if (CultureInfo.CurrentCulture != value) { var js = (IJSInProcessRuntime)JSRuntime; js.InvokeVoid("blazorCulture.set", value.Name); Nav.NavigateTo(Nav.Uri, forceLoad: true); } } } }
6. 页面的内容的本地化资源如何存放?
内容的本地化资源,只需要你添加与你要本地化的razor页面同名的.resx资源文件,并在其中定义你的本地化内容即可。例如:我要本地化Pages文件夹中BranchPage.razor页面,默认内容是英文的,我现在要将其支持可以本地化为中文,那我就添加资源文件名BranchPage.zh-CN.resx。并在里面将英文作为键,中文作为值进行存放即可。如果作为键,英文太长的话,可以定义关键字作为键,并且需要你再添加默认的BranchPage.resx资源文件作为英文资源文件。
7. 内容本地化资源信息存好了,如何在页面中调用?
还是以上面的BranchPage.razor为例,要在其中调用资源文件中的信息,就需要以下几步:
(1)在Program.Main中添加本地化服务
builder.Services.AddLocalization();
(2)在BranchPage.razor中进行下列本地化注入。
@inject IStringLocalizer<BranchPage> localizer
(3)用上面定义的localizer来进行调用
<tr> <th>@localizer["ID"]</th> <th>@localizer["Code"]</th> <th>@localizer["Name"]</th> <th>@localizer["Description"]</th> </tr>
至此,涉及本地化的主要步骤和关键点就完成了,你就可以测试您的代码了。