ASP.NET Core Blazor 全球化和本地化
注意
此版本不是本文的最新版本。 若要切换到最新版本,请使用目录顶部的 ASP.NET Core 版本选择器。
如果选择器在较窄的浏览器窗口中不可见,请扩大窗口或选择垂直省略号 (⋮) >“目录”。
本文介绍如何在 Blazor Server 应用中向位于不同区域、使用不同语言的用户呈现全球化和本地化内容。 有关独立和托管的 Blazor WebAssembly 应用的指南,请参阅本文的 Blazor WebAssembly 版本。
本文介绍如何在独立或托管的(Client 项目)Blazor WebAssembly 应用中向位于不同区域、使用不同语言的用户呈现全球化和本地化内容。 有关 Blazor Server 应用的指南,请参阅本文的 Blazor Server 版本。
对于全球化,Blazor 提供数字和日期格式。 对于本地化,Blazor 使用 .NET 资源系统呈现内容。
支持一组有限的 ASP.NET Core 本地化功能:
支持:IStringLocalizer 和 IStringLocalizer<T> 在 Blazor 应用中受支持。
不支持:IHtmlLocalizer、IViewLocalizer 和数据注释本地化是 ASP.NET Core MVC 功能,在 Blazor 应用中不受支持。
本文介绍如何使用 Blazor 基于以下内容的全球化和本地化功能:
Accept-Language
标头,它由浏览器基于浏览器设置中的用户语言首选项进行设置。- 由应用设置的区域性(不基于
Accept-Language
标头的值)。 该设置可以是所有用户的静态设置,也可以是基于应用逻辑的动态设置。 如果设置基于用户的首选项,该设置通常会被保存,以便在未来访问时重载。
有关其他一般信息,请查看以下资源:
注意
通常,在处理全球化和本地化概念时,术语“语言”和“区域性”可以互换使用 。
在本文中,“语言”指的是用户在其浏览器设置中选择的语言。 用户的语言选择是在 Accept-Language
标头 的浏览器请求中提交的。 浏览器设置通常在 UI 中使用“语言”一词。
区域性适用于 .NET 和 Blazor API 成员。 例如,用户的请求可以包括从用户角度指定语言的 Accept-Language
标头,但应用最终会根据用户请求的语言设置 CurrentCulture(“区域性”)属性。 API 通常在其成员名称中使用“区域性”一词。
全球化
@bind
属性指令根据应用支持的用户第一首选语言来应用格式并分析显示的值。 @bind
支持 @bind:culture
参数,以提供用于分析值并设置值格式的 System.Globalization.CultureInfo。
可从 System.Globalization.CultureInfo.CurrentCulture 属性访问当前区域性。
CultureInfo.InvariantCulture 用于以下字段类型(<input type="{TYPE}" />
,其中 {TYPE}
占位符是类型):
date
number
上述字段类型:
- 使用其基于浏览器的相应格式规则进行显示。
- 不能包含自由格式的文本。
- 基于浏览器的实现提供用户交互特性。
使用 date
和 number
字段类型时,不建议指定区域性 @bind:culture
,因为 Blazor 提供内置支持来呈现当前区域性中的值。
以下字段类型具有特定的格式要求,并且当前不受 Blazor 支持,因为所有主流浏览器均不支持它们:
datetime-local
month
week
有关上述类型的当前浏览器支持,请参阅可否使用。
适用于 Unicode 的 .NET 全球化和国际组件 (ICU) 支持
Blazor WebAssembly 使用一个简化的全球化 API 和一组内置的 Unicode 国际组件 (ICU) 区域设置。 有关详细信息,请参阅 .NET 全球化和 ICU:WebAssembly 上的 ICU。
若要加载自定义 ICU 数据文件来控制应用的区域设置,请参阅 WASM 全球化 ICU。 目前,需要手动生成自定义的 ICU 数据文件。 .NET 工具计划在未来的 .NET 8.0 预览版中简化文件创建过程。
适用于 Unicode 的 .NET 全球化和国际组件 (ICU) 支持
Blazor WebAssembly 使用一个简化的全球化 API 和一组内置的 Unicode 国际组件 (ICU) 区域设置。 有关详细信息,请参阅 .NET 全球化和 ICU:WebAssembly 上的 ICU。
.NET 8 或更高版本支持在 Blazor WebAssembly 应用中加载区域设置的自定义子集。 有关详细信息,请访问本文的 8.0 或更高版本中的此部分。
固定全球化
如果应用不需要本地化,则将应用配置为支持固定区域性,这通常是基于美国英语 (en-US
) 的。 在应用的项目文件 (.csproj
) 中将 InvariantGlobalization
属性设置为 true
:
<PropertyGroup>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
或者,通过以下方法配置固定全球化:
在
runtimeconfig.json
中:{ "runtimeOptions": { "configProperties": { "System.Globalization.Invariant": true } } }
使用环境变量:
- 键:
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
- 值:
true
或1
- 键:
有关详细信息,请参阅全球化的运行时配置选项(.NET 文档)。
演示组件
以下 CultureExample1
组件可用于演示本文涵盖的 Blazor 全球化和本地化概念。
Pages/CultureExample1.razor
:
@page "/culture-example-1"
@using System.Globalization
<h1>Culture Example 1</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Rendered values</h2>
<ul>
<li><b>Date</b>: @dt</li>
<li><b>Number</b>: @number.ToString("N2")</li>
</ul>
<h2><code><input></code> elements that don't set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.CurrentCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input @bind="dt" /></label></li>
<li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>
<h2><code><input></code> elements that set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.InvariantCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
<li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>
@code {
private DateTime dt = DateTime.Now;
private double number = 1999.69;
}
前面的示例 (.ToString("N2")
) 中的数字字符串格式 (N2
) 是一个标准 .NET 数字格式说明符。 N2
格式支持用于所有数值类型,包括组分隔符,最多可呈现两个小数位。
(可选)将菜单项添加到 CultureExample1
组件的 Shared/NavMenu.razor
中的导航。
在 Accept-Language
标头中动态设置区域性
Accept-Language
标头由浏览器设置,在浏览器设置中由用户的语言首选项控制。 在浏览器设置中,用户按优先顺序设置一种或多种首选语言。 浏览器按优先顺序为标头中的每种语言设置质量值(q
,0-1)。 下面的示例指定美国英语、英语和智利西班牙语,优先选择美国英语或英语:
Accept-Language: en-US,en;q=0.9,es-CL;q=0.8
应用的区域性是通过匹配第一个请求的语言来设置的,该语言与应用支持的区域性相匹配。
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
注意
如果应用的规范要求将受支持的区域性限制为显式列表,请参阅本文的按用户首选项动态设置区域性部分。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Program.cs
中:
builder.Services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Program.cs
中指定应用支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性:
app.UseRequestLocalization(new RequestLocalizationOptions()
.AddSupportedCultures(new[] { "en-US", "es-CL" })
.AddSupportedUICultures(new[] { "en-US", "es-CL" }));
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。
注意
一些浏览器会强制你在请求和浏览器自身的用户界面设置中使用默认的语言设置。 这可能会导致难以将语言变更回你所能理解的语言,因为所有设置 UI 屏幕可能最终都使用你无法理解的语言。 像 Opera 这样的浏览器是一个很好的测试选择,因为它允许你为网页请求设置一个默认语言,但将浏览器的设置 UI 保留为你的语言。
当区域性为美国英语 (en-US
) 时,呈现的组件使用“月/日”日期格式 (6/7
)、12 小时制时间 (AM
/PM
),并在数值中使用逗号分隔符,在小数值中使用点 (1,999.69
):
- 日期:6/7/2021 6:45:22 AM
- 数值:1,999.69
当区域性为智利西班牙语 (es-CL
) 时,呈现的组件使用“日/月”日期格式 (7/6
)、24 小时制时间,并在数值中使用句点分隔符,在小数值中使用逗号(1.999,69
):
- 日期:7/6/2021 6:49:38
- 数值:1.999,69
静态设置区域性
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
当 Blazor 使用 applicationCulture
Blazor 启动选项启动时,可以在 JavaScript 中设置应用的区域性。 下面的示例使用美国英语 (en-US
) 区域性将应用配置为启动。
在
wwwroot/index.html
中,通过将autostart="false"
添加到 Blazor 的<script>
标记来阻止 Blazor 自动启动:<script src="_framework/blazor.webassembly.js" autostart="false"></script>
在 Blazor 的
<script>
标记后和结束标记</body>
前添加以下<script>
块:<script> Blazor.start({ applicationCulture: 'en-US' }); </script>
applicationCulture
的值必须符合 BCP-47 语言标记格式。 有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动。
设置区域性 Blazor 的启动选项的替代方法是在 C# 代码中设置区域性。 将 Program.cs
中的 CultureInfo.DefaultThreadCurrentCulture 和 CultureInfo.DefaultThreadCurrentUICulture 设置为相同的区域性。
将 System.Globalization 命名空间添加到 Program.cs
:
using System.Globalization;
在生成并运行 WebAssemblyHostBuilder (await builder.Build().RunAsync();
) 的行之前添加区域性设置:
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
重要
始终将 DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 设置为相同的区域性,以便使用 IStringLocalizer 和 IStringLocalizer<T>。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Program.cs
中:
builder.Services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Program.cs
中指定静态区域性。 下面的示例配置美国英语:
app.UseRequestLocalization("en-US");
UseRequestLocalization 的区域性值必须符合 BCP-47 语言标记格式。
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。 当请求的语言为智利西班牙语时,应用的区域性将保留为美国英语 (en-US
)。
按用户首选项动态设置区域性
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例演示如何使用浏览器本地存储。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
在项目文件中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
Blazor WebAssembly 应用中的应用区域性是使用 Blazor 框架的 API 设置的。 用户的区域性选择可以保留在浏览器本地存储中。
在 wwwroot/index.html
文件中,在 Blazor 的 <script>
标记后和结束标记 </body>
前,提供 JS 函数以使用浏览器本地存储获取和设置用户的区域性选择:
<script>
window.blazorCulture = {
get: () => window.localStorage['BlazorCulture'],
set: (value) => window.localStorage['BlazorCulture'] = value
};
</script>
注意
前面的示例使用全局方法来污染客户端。 若要在生产应用中获取更好的方法,请参阅 JavaScript 模块中的 JavaScript 隔离。
将 System.Globalization 和 Microsoft.JSInterop 的命名空间添加到 Program.cs
顶部:
using System.Globalization;
using Microsoft.JSInterop;
删除 Program.cs
中的以下行:
- await builder.Build().RunAsync();
用下面的代码替换前面的行。 该代码通过 AddLocalization 将 Blazor 的本地化服务添加到应用的服务集合,并使用 JS 互操作调入 JS,然后从本地存储中检索用户的区域性选择。 如果本地存储不包含用户的区域性,代码会设置默认值“美国英语”(en-US
)。
builder.Services.AddLocalization();
var host = builder.Build();
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
await host.RunAsync();
重要
始终将 DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 设置为相同的区域性,以便使用 IStringLocalizer 和 IStringLocalizer<T>。
以下 CultureSelector
组件显示了如何执行以下操作:
- 通过 JS 互操作将用户的区域性选择设置到浏览器本地存储中。
- 重载所请求的组件 (
forceLoad: true
),这将使用更新的区域性。
CultureSelector
组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var js = (IJSInProcessRuntime)JS;
js.InvokeVoid("blazorCulture.set", value.Name);
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
}
}
}
}
注意
有关 IJSInProcessRuntime 的详细信息,请参阅在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数。
在 Shared/MainLayout.razor
中的 </main>
元素的结束标记内,添加 CultureSelector
组件:
<article class="bottom-row px-4">
<CultureSelector />
</article>
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例展示了如何使用本地化 cookie。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Program.cs
中:
builder.Services.AddLocalization();
使用 RequestLocalizationOptions 设置应用的默认且受支持的区域性。
在将路由中间件添加到处理管道后,在 Program.cs
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
下面的示例演示如何在可由本地化中间件读取的 cookie 中设置当前区域性。
对 Pages/_Host.cshtml
文件所做的修改需要以下命名空间:
Pages/_Host.cshtml
:
+ @using System.Globalization
+ @using Microsoft.AspNetCore.Localization
+ @{
+ this.HttpContext.Response.Cookies.Append(
+ CookieRequestCultureProvider.DefaultCookieName,
+ CookieRequestCultureProvider.MakeCookieValue(
+ new RequestCulture(
+ CultureInfo.CurrentCulture,
+ CultureInfo.CurrentUICulture)));
+ }
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用未配置为处理控制器操作:
通过在
Program.cs
中对服务集合调用 AddControllers 来添加 MVC 服务:builder.Services.AddControllers();
通过对 IEndpointRouteBuilder 调用 MapControllers 在
Program.cs
中添加控制器终结点路由:app.MapControllers();
下面的示例演示如何在添加行后调用 UseEndpoints:
app.MapControllers(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host");
若要提供支持用户选择区域性的 UI,请将基于重定向的方法和本地化 cookie 结合使用。 应用通过重定向到控制器来保留用户的所选区域性。 控制器将用户选择的区域性设置为 cookie,然后将用户重定向回原始 URI。 此过程类似于用户尝试访问安全资源时在 Web 应用中发生的情况,用户会被重定向到登录页,然后重定向回原始资源。
Controllers/CultureController.cs
:
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
[Route("[controller]/[action]")]
public class CultureController : Controller
{
public IActionResult Set(string culture, string redirectUri)
{
if (culture != null)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture, culture)));
}
return LocalRedirect(redirectUri);
}
}
警告
使用 LocalRedirect 操作结果以阻止开放式重定向攻击。 有关详细信息,请参阅预防 ASP.NET Core 中的开放式重定向攻击。
以下 CultureSelector
组件演示了如何通过新的区域性调用 CultureController
的 Set
方法。 该组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
protected override void OnInitialized()
{
Culture = CultureInfo.CurrentCulture;
}
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var uri = new Uri(Navigation.Uri)
.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var cultureEscaped = Uri.EscapeDataString(value.Name);
var uriEscaped = Uri.EscapeDataString(uri);
Navigation.NavigateTo(
$"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
forceLoad: true);
}
}
}
}
在 Shared/MainLayout.razor
中的结束标记 </main>
内,添加 CultureSelector
组件:
<article class="bottom-row px-4">
<CultureSelector />
</article>
使用演示组件部分中显示的 CultureExample1
组件来研究前面示例的工作原理。
本地化
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请向应用添加 Microsoft.Extensions.Localization
包。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
在 Program.cs
中,将 System.Globalization 的命名空间添加到文件顶部:
using System.Globalization;
将 Blazor 的本地化服务添加到应用的服务集合中,其中 Program.cs
包含 AddLocalization:
builder.Services.AddLocalization();
使用本地化中间件设置应用的区域性。
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请执行以下操作:
- 使用 AddLocalization 将本地化服务添加到应用。
- 在
Program.cs
中指定应用的默认且受支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性。
在 Program.cs
中:
builder.Services.AddLocalization();
在将路由中间件添加到处理管道后,在 Program.cs
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用应基于存储用户的区域性设置来本地化资源,则使用本地化区域性 cookie。 使用 cookie 可确保 WebSocket 连接可以正确地传播区域性。 如果本地化方案基于 URL 路径或查询字符串,则该方案可能无法与 Websocket 协同使用,因而无法保留区域性。 因此,建议的方法是使用本地化区域性 cookie。 若要查看保留用户区域性选择的示例 Razor 表达式,请参阅本文的按用户首选项动态设置区域性部分。
本部分中的本地化资源示例与本文前面的示例一样,应用的受支持区域性是将英语 (en
) 作为默认区域设置,将西班牙语 (es
) 作为用户可选择的或浏览器指定的备用区域设置。
为每个区域设置创建资源。 在下面的示例中,为默认 Greeting
字符串创建了资源:
- 英语:
Hello, World!
- 西班牙语 (
es
):¡Hola, Mundo!
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 Hello, World!
。 保存文件。
Pages/CultureExample2.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>Hello, World!</value>
</data>
</root>
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.es.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 ¡Hola, Mundo!
。 保存文件。
Pages/CultureExample2.es.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>¡Hola, Mundo!</value>
</data>
</root>
以下组件演示如何将本地化 Greeting
字符串用于 IStringLocalizer<T>。 以下示例中的 Razor 标记 @Loc["Greeting"]
将键控为 Greeting
值的字符串本地化,该值在前面的资源文件中设置。
将 Microsoft.Extensions.Localization 的命名空间添加到应用的 _Imports.razor
文件中:
@using Microsoft.Extensions.Localization
Pages/CultureExample2.razor
:
@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc
<h1>Culture Example 2</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Greeting</h2>
<p>
@Loc["Greeting"]
</p>
<p>
@greeting
</p>
@code {
private string? greeting;
protected override void OnInitialized()
{
greeting = Loc["Greeting"];
}
}
(可选)将菜单项添加到 CultureExample2
组件的 Shared/NavMenu.razor
中的导航。
区域性提供程序参考源
若要进一步了解 Blazor 框架如何处理本地化,请参阅 ASP.NET Core 参考源中的 WebAssemblyCultureProvider
类。
注意
指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)。
共享资源
若要创建本地化共享资源,请采用以下方法。
创建具有任意类名的虚拟类。 如下示例中:
- 应用使用
BlazorSample
命名空间,本地化资产使用BlazorSample.Localization
命名空间。 - 虚拟类名为
SharedResource
。 - 类文件位于应用根目录的
Localization
文件夹中。
Localization/SharedResource.cs
:namespace BlazorSample.Localization; public class SharedResource { }
- 应用使用
使用
Embedded resource
的生成操作创建共享资源文件。 如下示例中:文件放置在具有虚拟
SharedResource
类 (Localization/SharedResource.cs
) 的Localization
文件夹中。将资源文件命名为与虚拟类的名称一致。 以下示例文件包括一个默认本地化文件和一个西班牙语 (
es
) 本地化文件。Localization/SharedResource.resx
Localization/SharedResource.es.resx
注意
Localization
是可以通过 LocalizationOptions 设置的资源路径。若要引用 Razor 组件中已注入 IStringLocalizer<T> 的虚拟类,请为本地化命名空间放置
@using
指令,或在虚拟类引用中包含本地化命名空间。 在以下示例中:- 第一个示例使用
Localization
指令声明SharedResource
虚拟类的@using
命名空间。 - 第二个示例显式声明
SharedResource
虚拟类的命名空间。
在 Razor 组件中,使用以下任一方法:
@using Localization @inject IStringLocalizer<SharedResource> Loc
@inject IStringLocalizer<Localization.SharedResource> Loc
- 第一个示例使用
有关其他指南,请参阅 ASP.NET Core 中的全球化和本地化。
其他资源
对于全球化,Blazor 提供数字和日期格式。 对于本地化,Blazor 使用 .NET 资源系统呈现内容。
支持一组有限的 ASP.NET Core 本地化功能:
支持:IStringLocalizer 和 IStringLocalizer<T> 在 Blazor 应用中受支持。
不支持:IHtmlLocalizer、IViewLocalizer 和数据注释本地化是 ASP.NET Core MVC 功能,在 Blazor 应用中不受支持。
本文介绍如何使用 Blazor 基于以下内容的全球化和本地化功能:
Accept-Language
标头,它由浏览器基于浏览器设置中的用户语言首选项进行设置。- 由应用设置的区域性(不基于
Accept-Language
标头的值)。 该设置可以是所有用户的静态设置,也可以是基于应用逻辑的动态设置。 如果设置基于用户的首选项,该设置通常会被保存,以便在未来访问时重载。
有关其他一般信息,请查看以下资源:
注意
通常,在处理全球化和本地化概念时,术语“语言”和“区域性”可以互换使用 。
在本文中,“语言”指的是用户在其浏览器设置中选择的语言。 用户的语言选择是在 Accept-Language
标头 的浏览器请求中提交的。 浏览器设置通常在 UI 中使用“语言”一词。
区域性适用于 .NET 和 Blazor API 成员。 例如,用户的请求可以包括从用户角度指定语言的 Accept-Language
标头,但应用最终会根据用户请求的语言设置 CurrentCulture(“区域性”)属性。 API 通常在其成员名称中使用“区域性”一词。
全球化
@bind
属性指令根据应用支持的用户第一首选语言来应用格式并分析显示的值。 @bind
支持 @bind:culture
参数,以提供用于分析值并设置值格式的 System.Globalization.CultureInfo。
可从 System.Globalization.CultureInfo.CurrentCulture 属性访问当前区域性。
CultureInfo.InvariantCulture 用于以下字段类型(<input type="{TYPE}" />
,其中 {TYPE}
占位符是类型):
date
number
上述字段类型:
- 使用其基于浏览器的相应格式规则进行显示。
- 不能包含自由格式的文本。
- 基于浏览器的实现提供用户交互特性。
使用 date
和 number
字段类型时,不建议指定区域性 @bind:culture
,因为 Blazor 提供内置支持来呈现当前区域性中的值。
以下字段类型具有特定的格式要求,并且当前不受 Blazor 支持,因为所有主流浏览器均不支持它们:
datetime-local
month
week
有关上述类型的当前浏览器支持,请参阅可否使用。
适用于 Unicode 的 .NET 全球化和国际组件 (ICU) 支持
Blazor WebAssembly 使用一个简化的全球化 API 和一组内置的 Unicode 国际组件 (ICU) 区域设置。 有关详细信息,请参阅 .NET 全球化和 ICU:WebAssembly 上的 ICU。
.NET 8 或更高版本支持在 Blazor WebAssembly 应用中加载区域设置的自定义子集。 有关详细信息,请访问本文的 8.0 或更高版本中的此部分。
固定全球化
如果应用不需要本地化,则将应用配置为支持固定区域性,这通常是基于美国英语 (en-US
) 的。 在应用的项目文件 (.csproj
) 中将 InvariantGlobalization
属性设置为 true
:
<PropertyGroup>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
或者,通过以下方法配置固定全球化:
在
runtimeconfig.json
中:{ "runtimeOptions": { "configProperties": { "System.Globalization.Invariant": true } } }
使用环境变量:
- 键:
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
- 值:
true
或1
- 键:
有关详细信息,请参阅全球化的运行时配置选项(.NET 文档)。
演示组件
以下 CultureExample1
组件可用于演示本文涵盖的 Blazor 全球化和本地化概念。
Pages/CultureExample1.razor
:
@page "/culture-example-1"
@using System.Globalization
<h1>Culture Example 1</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Rendered values</h2>
<ul>
<li><b>Date</b>: @dt</li>
<li><b>Number</b>: @number.ToString("N2")</li>
</ul>
<h2><code><input></code> elements that don't set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.CurrentCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input @bind="dt" /></label></li>
<li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>
<h2><code><input></code> elements that set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.InvariantCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
<li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>
@code {
private DateTime dt = DateTime.Now;
private double number = 1999.69;
}
前面的示例 (.ToString("N2")
) 中的数字字符串格式 (N2
) 是一个标准 .NET 数字格式说明符。 N2
格式支持用于所有数值类型,包括组分隔符,最多可呈现两个小数位。
(可选)将菜单项添加到 CultureExample1
组件的 Shared/NavMenu.razor
中的导航。
在 Accept-Language
标头中动态设置区域性
Accept-Language
标头由浏览器设置,在浏览器设置中由用户的语言首选项控制。 在浏览器设置中,用户按优先顺序设置一种或多种首选语言。 浏览器按优先顺序为标头中的每种语言设置质量值(q
,0-1)。 下面的示例指定美国英语、英语和智利西班牙语,优先选择美国英语或英语:
Accept-Language: en-US,en;q=0.9,es-CL;q=0.8
应用的区域性是通过匹配第一个请求的语言来设置的,该语言与应用支持的区域性相匹配。
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
注意
如果应用的规范要求将受支持的区域性限制为显式列表,请参阅本文的按用户首选项动态设置区域性部分。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Program.cs
中:
builder.Services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Program.cs
中指定应用支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性:
app.UseRequestLocalization(new RequestLocalizationOptions()
.AddSupportedCultures(new[] { "en-US", "es-CL" })
.AddSupportedUICultures(new[] { "en-US", "es-CL" }));
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。
注意
一些浏览器会强制你在请求和浏览器自身的用户界面设置中使用默认的语言设置。 这可能会导致难以将语言变更回你所能理解的语言,因为所有设置 UI 屏幕可能最终都使用你无法理解的语言。 像 Opera 这样的浏览器是一个很好的测试选择,因为它允许你为网页请求设置一个默认语言,但将浏览器的设置 UI 保留为你的语言。
当区域性为美国英语 (en-US
) 时,呈现的组件使用“月/日”日期格式 (6/7
)、12 小时制时间 (AM
/PM
),并在数值中使用逗号分隔符,在小数值中使用点 (1,999.69
):
- 日期:6/7/2021 6:45:22 AM
- 数值:1,999.69
当区域性为智利西班牙语 (es-CL
) 时,呈现的组件使用“日/月”日期格式 (7/6
)、24 小时制时间,并在数值中使用句点分隔符,在小数值中使用逗号(1.999,69
):
- 日期:7/6/2021 6:49:38
- 数值:1.999,69
静态设置区域性
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
当 Blazor 使用 applicationCulture
Blazor 启动选项启动时,可以在 JavaScript 中设置应用的区域性。 下面的示例使用美国英语 (en-US
) 区域性将应用配置为启动。
在
wwwroot/index.html
中,通过将autostart="false"
添加到 Blazor 的<script>
标记来阻止 Blazor 自动启动:<script src="_framework/blazor.webassembly.js" autostart="false"></script>
在 Blazor 的
<script>
标记后和结束标记</body>
前添加以下<script>
块:<script> Blazor.start({ applicationCulture: 'en-US' }); </script>
applicationCulture
的值必须符合 BCP-47 语言标记格式。 有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动。
设置区域性 Blazor 的启动选项的替代方法是在 C# 代码中设置区域性。 将 Program.cs
中的 CultureInfo.DefaultThreadCurrentCulture 和 CultureInfo.DefaultThreadCurrentUICulture 设置为相同的区域性。
将 System.Globalization 命名空间添加到 Program.cs
:
using System.Globalization;
在生成并运行 WebAssemblyHostBuilder (await builder.Build().RunAsync();
) 的行之前添加区域性设置:
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
重要
始终将 DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 设置为相同的区域性,以便使用 IStringLocalizer 和 IStringLocalizer<T>。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Program.cs
中:
builder.Services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Program.cs
中指定静态区域性。 下面的示例配置美国英语:
app.UseRequestLocalization("en-US");
UseRequestLocalization 的区域性值必须符合 BCP-47 语言标记格式。
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。 当请求的语言为智利西班牙语时,应用的区域性将保留为美国英语 (en-US
)。
按用户首选项动态设置区域性
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例演示如何使用浏览器本地存储。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
在项目文件中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
Blazor WebAssembly 应用中的应用区域性是使用 Blazor 框架的 API 设置的。 用户的区域性选择可以保留在浏览器本地存储中。
在 wwwroot/index.html
文件中,在 Blazor 的 <script>
标记后和结束标记 </body>
前,提供 JS 函数以使用浏览器本地存储获取和设置用户的区域性选择:
<script>
window.blazorCulture = {
get: () => window.localStorage['BlazorCulture'],
set: (value) => window.localStorage['BlazorCulture'] = value
};
</script>
注意
前面的示例使用全局方法来污染客户端。 若要在生产应用中获取更好的方法,请参阅 JavaScript 模块中的 JavaScript 隔离。
将 System.Globalization 和 Microsoft.JSInterop 的命名空间添加到 Program.cs
顶部:
using System.Globalization;
using Microsoft.JSInterop;
删除 Program.cs
中的以下行:
- await builder.Build().RunAsync();
用下面的代码替换前面的行。 该代码通过 AddLocalization 将 Blazor 的本地化服务添加到应用的服务集合,并使用 JS 互操作调入 JS,然后从本地存储中检索用户的区域性选择。 如果本地存储不包含用户的区域性,代码会设置默认值“美国英语”(en-US
)。
builder.Services.AddLocalization();
var host = builder.Build();
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
await host.RunAsync();
重要
始终将 DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 设置为相同的区域性,以便使用 IStringLocalizer 和 IStringLocalizer<T>。
以下 CultureSelector
组件显示了如何执行以下操作:
- 通过 JS 互操作将用户的区域性选择设置到浏览器本地存储中。
- 重载所请求的组件 (
forceLoad: true
),这将使用更新的区域性。
CultureSelector
组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var js = (IJSInProcessRuntime)JS;
js.InvokeVoid("blazorCulture.set", value.Name);
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
}
}
}
}
注意
有关 IJSInProcessRuntime 的详细信息,请参阅在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数。
在 Shared/MainLayout.razor
中的 <main>
元素的结束标记内,添加 CultureSelector
组件:
<div class="bottom-row px-4">
<CultureSelector />
</div>
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例展示了如何使用本地化 cookie。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Program.cs
中:
builder.Services.AddLocalization();
使用 RequestLocalizationOptions 设置应用的默认且受支持的区域性。
在将路由中间件添加到处理管道后,在 Program.cs
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
下面的示例演示如何在可由本地化中间件读取的 cookie 中设置当前区域性。
对 Pages/_Host.cshtml
文件所做的修改需要以下命名空间:
Pages/_Host.cshtml
:
@page "/"
@namespace {NAMESPACE}.Pages
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@using System.Globalization
@using Microsoft.AspNetCore.Localization
@{
Layout = "_Layout";
this.HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(
CultureInfo.CurrentCulture,
CultureInfo.CurrentUICulture)));
}
<component type="typeof(App)" render-mode="ServerPrerendered" />
在前面的示例中,占位符 {NAMESPACE}
是应用的程序集名称。
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用未配置为处理控制器操作:
通过在
Program.cs
中对服务集合调用 AddControllers 来添加 MVC 服务:builder.Services.AddControllers();
通过对 IEndpointRouteBuilder 调用 MapControllers 在
Program.cs
中添加控制器终结点路由:app.MapControllers();
下面的示例演示如何在添加行后调用 UseEndpoints:
app.MapControllers(); app.MapBlazorHub(); app.MapFallbackToPage("/_Host");
若要提供支持用户选择区域性的 UI,请将基于重定向的方法和本地化 cookie 结合使用。 应用通过重定向到控制器来保留用户的所选区域性。 控制器将用户选择的区域性设置为 cookie,然后将用户重定向回原始 URI。 此过程类似于用户尝试访问安全资源时在 Web 应用中发生的情况,用户会被重定向到登录页,然后重定向回原始资源。
Controllers/CultureController.cs
:
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
[Route("[controller]/[action]")]
public class CultureController : Controller
{
public IActionResult Set(string culture, string redirectUri)
{
if (culture != null)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture, culture)));
}
return LocalRedirect(redirectUri);
}
}
警告
使用 LocalRedirect 操作结果以阻止开放式重定向攻击。 有关详细信息,请参阅预防 ASP.NET Core 中的开放式重定向攻击。
以下 CultureSelector
组件演示了如何通过新的区域性调用 CultureController
的 Set
方法。 该组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
protected override void OnInitialized()
{
Culture = CultureInfo.CurrentCulture;
}
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var uri = new Uri(Navigation.Uri)
.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var cultureEscaped = Uri.EscapeDataString(value.Name);
var uriEscaped = Uri.EscapeDataString(uri);
Navigation.NavigateTo(
$"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
forceLoad: true);
}
}
}
}
在 Shared/MainLayout.razor
中的 <main>
元素的结束标记 </div>
内,添加 CultureSelector
组件:
<div class="bottom-row px-4">
<CultureSelector />
</div>
使用演示组件部分中显示的 CultureExample1
组件来研究前面示例的工作原理。
本地化
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请向应用添加 Microsoft.Extensions.Localization
包。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
在 Program.cs
中,将 System.Globalization 的命名空间添加到文件顶部:
using System.Globalization;
将 Blazor 的本地化服务添加到应用的服务集合中,其中 Program.cs
包含 AddLocalization:
builder.Services.AddLocalization();
使用本地化中间件设置应用的区域性。
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请执行以下操作:
- 使用 AddLocalization 将本地化服务添加到应用。
- 在
Program.cs
中指定应用的默认且受支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性。
在 Program.cs
中:
builder.Services.AddLocalization();
在将路由中间件添加到处理管道后,在 Program.cs
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Program.cs
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用应基于存储用户的区域性设置来本地化资源,则使用本地化区域性 cookie。 使用 cookie 可确保 WebSocket 连接可以正确地传播区域性。 如果本地化方案基于 URL 路径或查询字符串,则该方案可能无法与 Websocket 协同使用,因而无法保留区域性。 因此,建议的方法是使用本地化区域性 cookie。 若要查看保留用户区域性选择的示例 Razor 表达式,请参阅本文的按用户首选项动态设置区域性部分。
本部分中的本地化资源示例与本文前面的示例一样,应用的受支持区域性是将英语 (en
) 作为默认区域设置,将西班牙语 (es
) 作为用户可选择的或浏览器指定的备用区域设置。
为每个区域设置创建资源。 在下面的示例中,为默认 Greeting
字符串创建了资源:
- 英语:
Hello, World!
- 西班牙语 (
es
):¡Hola, Mundo!
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 Hello, World!
。 保存文件。
Pages/CultureExample2.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>Hello, World!</value>
</data>
</root>
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.es.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 ¡Hola, Mundo!
。 保存文件。
Pages/CultureExample2.es.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>¡Hola, Mundo!</value>
</data>
</root>
以下组件演示如何将本地化 Greeting
字符串用于 IStringLocalizer<T>。 以下示例中的 Razor 标记 @Loc["Greeting"]
将键控为 Greeting
值的字符串本地化,该值在前面的资源文件中设置。
将 Microsoft.Extensions.Localization 的命名空间添加到应用的 _Imports.razor
文件中:
@using Microsoft.Extensions.Localization
Pages/CultureExample2.razor
:
@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc
<h1>Culture Example 2</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Greeting</h2>
<p>
@Loc["Greeting"]
</p>
<p>
@greeting
</p>
@code {
private string? greeting;
protected override void OnInitialized()
{
greeting = Loc["Greeting"];
}
}
(可选)将菜单项添加到 CultureExample2
组件的 Shared/NavMenu.razor
中的导航。
区域性提供程序参考源
若要进一步了解 Blazor 框架如何处理本地化,请参阅 ASP.NET Core 参考源中的 WebAssemblyCultureProvider
类。
注意
指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)。
共享资源
若要创建本地化共享资源,请采用以下方法。
创建具有任意类名的虚拟类。 如下示例中:
- 应用使用
BlazorSample
命名空间,本地化资产使用BlazorSample.Localization
命名空间。 - 虚拟类名为
SharedResource
。 - 类文件位于应用根目录的
Localization
文件夹中。
Localization/SharedResource.cs
:namespace BlazorSample.Localization; public class SharedResource { }
- 应用使用
使用
Embedded resource
的生成操作创建共享资源文件。 如下示例中:文件放置在具有虚拟
SharedResource
类 (Localization/SharedResource.cs
) 的Localization
文件夹中。将资源文件命名为与虚拟类的名称一致。 以下示例文件包括一个默认本地化文件和一个西班牙语 (
es
) 本地化文件。Localization/SharedResource.resx
Localization/SharedResource.es.resx
注意
Localization
是可以通过 LocalizationOptions 设置的资源路径。若要引用 Razor 组件中已注入 IStringLocalizer<T> 的虚拟类,请为本地化命名空间放置
@using
指令,或在虚拟类引用中包含本地化命名空间。 在以下示例中:- 第一个示例使用
Localization
指令声明SharedResource
虚拟类的@using
命名空间。 - 第二个示例显式声明
SharedResource
虚拟类的命名空间。
在 Razor 组件中,使用以下任一方法:
@using Localization @inject IStringLocalizer<SharedResource> Loc
@inject IStringLocalizer<Localization.SharedResource> Loc
- 第一个示例使用
有关其他指南,请参阅 ASP.NET Core 中的全球化和本地化。
其他资源
对于全球化,Blazor 提供数字和日期格式。 对于本地化,Blazor 使用 .NET 资源系统呈现内容。
支持一组有限的 ASP.NET Core 本地化功能:
支持:IStringLocalizer 和 IStringLocalizer<T> 在 Blazor 应用中受支持。
不支持:IHtmlLocalizer、IViewLocalizer 和数据注释本地化是 ASP.NET Core MVC 功能,在 Blazor 应用中不受支持。
本文介绍如何使用 Blazor 基于以下内容的全球化和本地化功能:
Accept-Language
标头,它由浏览器基于浏览器设置中的用户语言首选项进行设置。- 由应用设置的区域性(不基于
Accept-Language
标头的值)。 该设置可以是所有用户的静态设置,也可以是基于应用逻辑的动态设置。 如果设置基于用户的首选项,该设置通常会被保存,以便在未来访问时重载。
有关其他一般信息,请查看以下资源:
注意
通常,在处理全球化和本地化概念时,术语“语言”和“区域性”可以互换使用 。
在本文中,“语言”指的是用户在其浏览器设置中选择的语言。 用户的语言选择是在 Accept-Language
标头 的浏览器请求中提交的。 浏览器设置通常在 UI 中使用“语言”一词。
区域性适用于 .NET 和 Blazor API 成员。 例如,用户的请求可以包括从用户角度指定语言的 Accept-Language
标头,但应用最终会根据用户请求的语言设置 CurrentCulture(“区域性”)属性。 API 通常在其成员名称中使用“区域性”一词。
全球化
@bind
属性指令根据应用支持的用户第一首选语言来应用格式并分析显示的值。 @bind
支持 @bind:culture
参数,以提供用于分析值并设置值格式的 System.Globalization.CultureInfo。
可从 System.Globalization.CultureInfo.CurrentCulture 属性访问当前区域性。
CultureInfo.InvariantCulture 用于以下字段类型(<input type="{TYPE}" />
,其中 {TYPE}
占位符是类型):
date
number
上述字段类型:
- 使用其基于浏览器的相应格式规则进行显示。
- 不能包含自由格式的文本。
- 基于浏览器的实现提供用户交互特性。
使用 date
和 number
字段类型时,不建议指定区域性 @bind:culture
,因为 Blazor 提供内置支持来呈现当前区域性中的值。
以下字段类型具有特定的格式要求,并且当前不受 Blazor 支持,因为所有主流浏览器均不支持它们:
datetime-local
month
week
有关上述类型的当前浏览器支持,请参阅可否使用。
适用于 Unicode 的 .NET 全球化和国际组件 (ICU) 支持
Blazor WebAssembly 使用一个简化的全球化 API 和一组内置的 Unicode 国际组件 (ICU) 区域设置。 有关详细信息,请参阅 .NET 全球化和 ICU:WebAssembly 上的 ICU。
.NET 8 或更高版本支持在 Blazor WebAssembly 应用中加载区域设置的自定义子集。 有关详细信息,请访问本文的 8.0 或更高版本中的此部分。
固定全球化
如果应用不需要本地化,则将应用配置为支持固定区域性,这通常是基于美国英语 (en-US
) 的。 在应用的项目文件 (.csproj
) 中将 InvariantGlobalization
属性设置为 true
:
<PropertyGroup>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
或者,通过以下方法配置固定全球化:
在
runtimeconfig.json
中:{ "runtimeOptions": { "configProperties": { "System.Globalization.Invariant": true } } }
使用环境变量:
- 键:
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
- 值:
true
或1
- 键:
有关详细信息,请参阅全球化的运行时配置选项(.NET 文档)。
演示组件
以下 CultureExample1
组件可用于演示本文涵盖的 Blazor 全球化和本地化概念。
Pages/CultureExample1.razor
:
@page "/culture-example-1"
@using System.Globalization
<h1>Culture Example 1</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Rendered values</h2>
<ul>
<li><b>Date</b>: @dt</li>
<li><b>Number</b>: @number.ToString("N2")</li>
</ul>
<h2><code><input></code> elements that don't set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.CurrentCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input @bind="dt" /></label></li>
<li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>
<h2><code><input></code> elements that set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.InvariantCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
<li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>
@code {
private DateTime dt = DateTime.Now;
private double number = 1999.69;
}
前面的示例 (.ToString("N2")
) 中的数字字符串格式 (N2
) 是一个标准 .NET 数字格式说明符。 N2
格式支持用于所有数值类型,包括组分隔符,最多可呈现两个小数位。
(可选)将菜单项添加到 CultureExample1
组件的 Shared/NavMenu.razor
中的导航。
在 Accept-Language
标头中动态设置区域性
Accept-Language
标头由浏览器设置,在浏览器设置中由用户的语言首选项控制。 在浏览器设置中,用户按优先顺序设置一种或多种首选语言。 浏览器按优先顺序为标头中的每种语言设置质量值(q
,0-1)。 下面的示例指定美国英语、英语和智利西班牙语,优先选择美国英语或英语:
Accept-Language: en-US,en;q=0.9,es-CL;q=0.8
应用的区域性是通过匹配第一个请求的语言来设置的,该语言与应用支持的区域性相匹配。
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
注意
如果应用的规范要求将受支持的区域性限制为显式列表,请参阅本文的按用户首选项动态设置区域性部分。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Startup.Configure
(Startup.cs
) 中指定应用支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性:
app.UseRequestLocalization(new RequestLocalizationOptions()
.AddSupportedCultures(new[] { "en-US", "es-CL" })
.AddSupportedUICultures(new[] { "en-US", "es-CL" }));
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。
注意
一些浏览器会强制你在请求和浏览器自身的用户界面设置中使用默认的语言设置。 这可能会导致难以将语言变更回你所能理解的语言,因为所有设置 UI 屏幕可能最终都使用你无法理解的语言。 像 Opera 这样的浏览器是一个很好的测试选择,因为它允许你为网页请求设置一个默认语言,但将浏览器的设置 UI 保留为你的语言。
当区域性为美国英语 (en-US
) 时,呈现的组件使用“月/日”日期格式 (6/7
)、12 小时制时间 (AM
/PM
),并在数值中使用逗号分隔符,在小数值中使用点 (1,999.69
):
- 日期:6/7/2021 6:45:22 AM
- 数值:1,999.69
当区域性为智利西班牙语 (es-CL
) 时,呈现的组件使用“日/月”日期格式 (7/6
)、24 小时制时间,并在数值中使用句点分隔符,在小数值中使用逗号(1.999,69
):
- 日期:7/6/2021 6:49:38
- 数值:1.999,69
静态设置区域性
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
当 Blazor 使用 applicationCulture
Blazor 启动选项启动时,可以在 JavaScript 中设置应用的区域性。 下面的示例使用美国英语 (en-US
) 区域性将应用配置为启动。
在
wwwroot/index.html
中,通过将autostart="false"
添加到 Blazor 的<script>
标记来阻止 Blazor 自动启动:<script src="_framework/blazor.webassembly.js" autostart="false"></script>
在 Blazor 的
<script>
标记后和结束标记</body>
前添加以下<script>
块:<script> Blazor.start({ applicationCulture: 'en-US' }); </script>
applicationCulture
的值必须符合 BCP-47 语言标记格式。 有关 Blazor 启动的详细信息,请参阅 ASP.NET Core Blazor 启动。
设置区域性 Blazor 的启动选项的替代方法是在 C# 代码中设置区域性。 将 Program.cs
中的 CultureInfo.DefaultThreadCurrentCulture 和 CultureInfo.DefaultThreadCurrentUICulture 设置为相同的区域性。
将 System.Globalization 命名空间添加到 Program.cs
:
using System.Globalization;
在生成并运行 WebAssemblyHostBuilder (await builder.Build().RunAsync();
) 的行之前添加区域性设置:
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo("en-US");
重要
始终将 DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 设置为相同的区域性,以便使用 IStringLocalizer 和 IStringLocalizer<T>。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Startup.Configure
(Startup.cs
) 中指定静态区域性。 下面的示例配置美国英语:
app.UseRequestLocalization("en-US");
UseRequestLocalization 的区域性值必须符合 BCP-47 语言标记格式。
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。 当请求的语言为智利西班牙语时,应用的区域性将保留为美国英语 (en-US
)。
按用户首选项动态设置区域性
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例演示如何使用浏览器本地存储。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
在项目文件中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
Blazor WebAssembly 应用中的应用区域性是使用 Blazor 框架的 API 设置的。 用户的区域性选择可以保留在浏览器本地存储中。
在 wwwroot/index.html
文件中,在 Blazor 的 <script>
标记后和结束标记 </body>
前,提供 JS 函数以使用浏览器本地存储获取和设置用户的区域性选择:
<script>
window.blazorCulture = {
get: () => window.localStorage['BlazorCulture'],
set: (value) => window.localStorage['BlazorCulture'] = value
};
</script>
注意
前面的示例使用全局方法来污染客户端。 若要在生产应用中获取更好的方法,请参阅 JavaScript 模块中的 JavaScript 隔离。
将 System.Globalization 和 Microsoft.JSInterop 的命名空间添加到 Program.cs
顶部:
using System.Globalization;
using Microsoft.JSInterop;
删除 Program.cs
中的以下行:
- await builder.Build().RunAsync();
用下面的代码替换前面的行。 该代码通过 AddLocalization 将 Blazor 的本地化服务添加到应用的服务集合,并使用 JS 互操作调入 JS,然后从本地存储中检索用户的区域性选择。 如果本地存储不包含用户的区域性,代码会设置默认值“美国英语”(en-US
)。
builder.Services.AddLocalization();
var host = builder.Build();
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
await host.RunAsync();
重要
始终将 DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 设置为相同的区域性,以便使用 IStringLocalizer 和 IStringLocalizer<T>。
以下 CultureSelector
组件显示如何通过 JS 互操作将用户的区域性选择设置到浏览器本地存储中。 该组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var js = (IJSInProcessRuntime)JS;
js.InvokeVoid("blazorCulture.set", value.Name);
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
}
}
}
}
注意
有关 IJSInProcessRuntime 的详细信息,请参阅在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数。
在 Shared/MainLayout.razor
中的 <div class="main">
元素的结束标记 </div>
内,添加 CultureSelector
组件:
<div class="bottom-row px-4">
<CultureSelector />
</div>
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例展示了如何使用本地化 cookie。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
使用 RequestLocalizationOptions 设置应用的默认且受支持的区域性。
在将路由中间件添加到处理管道后,在 Startup.Configure
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
下面的示例演示如何在可由本地化中间件读取的 cookie 中设置当前区域性。
将以下命名空间添加到 Pages/_Host.cshtml
文件顶部:
@using System.Globalization
@using Microsoft.AspNetCore.Localization
在 Pages/_Host.cshtml
的开始标记 <body>
后面,紧接着添加以下 Razor 表达式:
@{
this.HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(
CultureInfo.CurrentCulture,
CultureInfo.CurrentUICulture)));
}
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用未配置为处理控制器操作:
通过在
Startup.ConfigureServices
中对服务集合调用 AddControllers 来添加 MVC 服务:services.AddControllers();
通过对 IEndpointRouteBuilder 调用 MapControllers 在
Startup.Configure
中添加控制器终结点路由:endpoints.MapControllers();
下面的示例演示如何在添加行后调用 UseEndpoints:
app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); });
若要提供支持用户选择区域性的 UI,请将基于重定向的方法和本地化 cookie 结合使用。 应用通过重定向到控制器来保留用户的所选区域性。 控制器将用户选择的区域性设置为 cookie,然后将用户重定向回原始 URI。 此过程类似于用户尝试访问安全资源时在 Web 应用中发生的情况,用户会被重定向到登录页,然后重定向回原始资源。
Controllers/CultureController.cs
:
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
[Route("[controller]/[action]")]
public class CultureController : Controller
{
public IActionResult Set(string culture, string redirectUri)
{
if (culture != null)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture, culture)));
}
return LocalRedirect(redirectUri);
}
}
警告
使用 LocalRedirect 操作结果以阻止开放式重定向攻击。 有关详细信息,请参阅预防 ASP.NET Core 中的开放式重定向攻击。
以下 CultureSelector
组件显示了如何在用户选择区域性时执行初始重定向。 该组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
protected override void OnInitialized()
{
Culture = CultureInfo.CurrentCulture;
}
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var uri = new Uri(Navigation.Uri)
.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var cultureEscaped = Uri.EscapeDataString(value.Name);
var uriEscaped = Uri.EscapeDataString(uri);
Navigation.NavigateTo(
$"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
forceLoad: true);
}
}
}
}
在 Shared/MainLayout.razor
中的 <div class="main">
元素的结束标记 </div>
内,添加 CultureSelector
组件:
<div class="bottom-row px-4">
<CultureSelector />
</div>
使用演示组件部分中显示的 CultureExample1
组件来研究前面示例的工作原理。
本地化
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请向应用添加 Microsoft.Extensions.Localization
包。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
在应用的项目文件 (.csproj
) 中将 BlazorWebAssemblyLoadAllGlobalizationData
属性设置为 true
:
<PropertyGroup>
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
</PropertyGroup>
在 Program.cs
中,将 System.Globalization 的命名空间添加到文件顶部:
using System.Globalization;
将 Blazor 的本地化服务添加到应用的服务集合中,其中 Program.cs
包含 AddLocalization:
builder.Services.AddLocalization();
使用本地化中间件设置应用的区域性。
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请执行以下操作:
- 使用 AddLocalization 将本地化服务添加到应用。
- 在
Startup.Configure
(Startup.cs
) 中指定应用的默认且受支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
在将路由中间件添加到处理管道后,在 Startup.Configure
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用应基于存储用户的区域性设置来本地化资源,则使用本地化区域性 cookie。 使用 cookie 可确保 WebSocket 连接可以正确地传播区域性。 如果本地化方案基于 URL 路径或查询字符串,则该方案可能无法与 Websocket 协同使用,因而无法保留区域性。 因此,建议的方法是使用本地化区域性 cookie。 若要查看保留用户区域性选择的 Pages/_Host.cshtml
文件的示例 Razor 表达式,请参阅本文的按用户首选项动态设置区域性部分。
本部分中的本地化资源示例与本文前面的示例一样,应用的受支持区域性是将英语 (en
) 作为默认区域设置,将西班牙语 (es
) 作为用户可选择的或浏览器指定的备用区域设置。
为每个区域设置创建资源。 在下面的示例中,为默认 Greeting
字符串创建了资源:
- 英语:
Hello, World!
- 西班牙语 (
es
):¡Hola, Mundo!
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 Hello, World!
。 保存文件。
Pages/CultureExample2.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>Hello, World!</value>
</data>
</root>
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.es.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 ¡Hola, Mundo!
。 保存文件。
Pages/CultureExample2.es.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>¡Hola, Mundo!</value>
</data>
</root>
以下组件演示如何将本地化 Greeting
字符串用于 IStringLocalizer<T>。 以下示例中的 Razor 标记 @Loc["Greeting"]
将键控为 Greeting
值的字符串本地化,该值在前面的资源文件中设置。
将 Microsoft.Extensions.Localization 的命名空间添加到应用的 _Imports.razor
文件中:
@using Microsoft.Extensions.Localization
Pages/CultureExample2.razor
:
@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc
<h1>Culture Example 2</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Greeting</h2>
<p>
@Loc["Greeting"]
</p>
<p>
@greeting
</p>
@code {
private string greeting;
protected override void OnInitialized()
{
greeting = Loc["Greeting"];
}
}
(可选)将菜单项添加到 CultureExample2
组件的 Shared/NavMenu.razor
中的导航。
区域性提供程序参考源
若要进一步了解 Blazor 框架如何处理本地化,请参阅 ASP.NET Core 参考源中的 WebAssemblyCultureProvider
类。
注意
指向 .NET 参考源的文档链接通常会加载存储库的默认分支,该分支表示针对下一个 .NET 版本的当前开发。 若要为特定版本选择标记,请使用“切换分支或标记”下拉列表。 有关详细信息,请参阅如何选择 ASP.NET Core 源代码的版本标记 (dotnet/AspNetCore.Docs #26205)。
共享资源
若要创建本地化共享资源,请采用以下方法。
创建具有任意类名的虚拟类。 如下示例中:
- 应用使用
BlazorSample
命名空间,本地化资产使用BlazorSample.Localization
命名空间。 - 虚拟类名为
SharedResource
。 - 类文件位于应用根目录的
Localization
文件夹中。
Localization/SharedResource.cs
:namespace BlazorSample.Localization { public class SharedResource { } }
- 应用使用
使用
Embedded resource
的生成操作创建共享资源文件。 如下示例中:文件放置在具有虚拟
SharedResource
类 (Localization/SharedResource.cs
) 的Localization
文件夹中。将资源文件命名为与虚拟类的名称一致。 以下示例文件包括一个默认本地化文件和一个西班牙语 (
es
) 本地化文件。Localization/SharedResource.resx
Localization/SharedResource.es.resx
注意
Localization
是可以通过 LocalizationOptions 设置的资源路径。若要引用 Razor 组件中已注入 IStringLocalizer<T> 的虚拟类,请为本地化命名空间放置
@using
指令,或在虚拟类引用中包含本地化命名空间。 在以下示例中:- 第一个示例使用
Localization
指令声明SharedResource
虚拟类的@using
命名空间。 - 第二个示例显式声明
SharedResource
虚拟类的命名空间。
在 Razor 组件中,使用以下任一方法:
@using Localization @inject IStringLocalizer<SharedResource> Loc
@inject IStringLocalizer<Localization.SharedResource> Loc
- 第一个示例使用
有关其他指南,请参阅 ASP.NET Core 中的全球化和本地化。
其他资源
对于全球化,Blazor 提供数字和日期格式。 对于本地化,Blazor 使用 .NET 资源系统呈现内容。
支持一组有限的 ASP.NET Core 本地化功能:
支持:IStringLocalizer 和 IStringLocalizer<T> 在 Blazor 应用中受支持。
不支持:IHtmlLocalizer、IViewLocalizer 和数据注释本地化是 ASP.NET Core MVC 功能,在 Blazor 应用中不受支持。
本文介绍如何使用 Blazor 基于以下内容的全球化和本地化功能:
Accept-Language
标头,它由浏览器基于浏览器设置中的用户语言首选项进行设置。- 由应用设置的区域性(不基于
Accept-Language
标头的值)。 该设置可以是所有用户的静态设置,也可以是基于应用逻辑的动态设置。 如果设置基于用户的首选项,该设置通常会被保存,以便在未来访问时重载。
有关其他一般信息,请查看以下资源:
注意
通常,在处理全球化和本地化概念时,术语“语言”和“区域性”可以互换使用 。
在本文中,“语言”指的是用户在其浏览器设置中选择的语言。 用户的语言选择是在 Accept-Language
标头 的浏览器请求中提交的。 浏览器设置通常在 UI 中使用“语言”一词。
区域性适用于 .NET 和 Blazor API 成员。 例如,用户的请求可以包括从用户角度指定语言的 Accept-Language
标头,但应用最终会根据用户请求的语言设置 CurrentCulture(“区域性”)属性。 API 通常在其成员名称中使用“区域性”一词。
全球化
@bind
属性指令根据应用支持的用户第一首选语言来应用格式并分析显示的值。 @bind
支持 @bind:culture
参数,以提供用于分析值并设置值格式的 System.Globalization.CultureInfo。
可从 System.Globalization.CultureInfo.CurrentCulture 属性访问当前区域性。
CultureInfo.InvariantCulture 用于以下字段类型(<input type="{TYPE}" />
,其中 {TYPE}
占位符是类型):
date
number
上述字段类型:
- 使用其基于浏览器的相应格式规则进行显示。
- 不能包含自由格式的文本。
- 基于浏览器的实现提供用户交互特性。
使用 date
和 number
字段类型时,不建议指定区域性 @bind:culture
,因为 Blazor 提供内置支持来呈现当前区域性中的值。
以下字段类型具有特定的格式要求,并且当前不受 Blazor 支持,因为所有主流浏览器均不支持它们:
datetime-local
month
week
有关上述类型的当前浏览器支持,请参阅可否使用。
适用于 Unicode 的 .NET 全球化和国际组件 (ICU) 支持
Blazor WebAssembly 使用一个简化的全球化 API 和一组内置的 Unicode 国际组件 (ICU) 区域设置。 有关详细信息,请参阅 .NET 全球化和 ICU:WebAssembly 上的 ICU。
.NET 8 或更高版本支持在 Blazor WebAssembly 应用中加载区域设置的自定义子集。 有关详细信息,请访问本文的 8.0 或更高版本中的此部分。
固定全球化
如果应用不需要本地化,则将应用配置为支持固定区域性,这通常是基于美国英语 (en-US
) 的。 在应用的项目文件 (.csproj
) 中将 InvariantGlobalization
属性设置为 true
:
<PropertyGroup>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
或者,通过以下方法配置固定全球化:
在
runtimeconfig.json
中:{ "runtimeOptions": { "configProperties": { "System.Globalization.Invariant": true } } }
使用环境变量:
- 键:
DOTNET_SYSTEM_GLOBALIZATION_INVARIANT
- 值:
true
或1
- 键:
有关详细信息,请参阅全球化的运行时配置选项(.NET 文档)。
演示组件
以下 CultureExample1
组件可用于演示本文涵盖的 Blazor 全球化和本地化概念。
Pages/CultureExample1.razor
:
@page "/culture-example-1"
@using System.Globalization
<h1>Culture Example 1</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Rendered values</h2>
<ul>
<li><b>Date</b>: @dt</li>
<li><b>Number</b>: @number.ToString("N2")</li>
</ul>
<h2><code><input></code> elements that don't set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.CurrentCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input @bind="dt" /></label></li>
<li><label><b>Number:</b> <input @bind="number" /></label></li>
</ul>
<h2><code><input></code> elements that set a <code>type</code></h2>
<p>
The following <code><input></code> elements use
<code>CultureInfo.InvariantCulture</code>.
</p>
<ul>
<li><label><b>Date:</b> <input type="date" @bind="dt" /></label></li>
<li><label><b>Number:</b> <input type="number" @bind="number" /></label></li>
</ul>
@code {
private DateTime dt = DateTime.Now;
private double number = 1999.69;
}
前面的示例 (.ToString("N2")
) 中的数字字符串格式 (N2
) 是一个标准 .NET 数字格式说明符。 N2
格式支持用于所有数值类型,包括组分隔符,最多可呈现两个小数位。
(可选)将菜单项添加到 CultureExample1
组件的 Shared/NavMenu.razor
中的导航。
在 Accept-Language
标头中动态设置区域性
Accept-Language
标头由浏览器设置,在浏览器设置中由用户的语言首选项控制。 在浏览器设置中,用户按优先顺序设置一种或多种首选语言。 浏览器按优先顺序为标头中的每种语言设置质量值(q
,0-1)。 下面的示例指定美国英语、英语和智利西班牙语,优先选择美国英语或英语:
Accept-Language: en-US,en;q=0.9,es-CL;q=0.8
应用的区域性是通过匹配第一个请求的语言来设置的,该语言与应用支持的区域性相匹配。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Startup.Configure
(Startup.cs
) 中指定应用支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性:
app.UseRequestLocalization(new RequestLocalizationOptions()
.AddSupportedCultures(new[] { "en-US", "es-CL" })
.AddSupportedUICultures(new[] { "en-US", "es-CL" }));
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。
注意
一些浏览器会强制你在请求和浏览器自身的用户界面设置中使用默认的语言设置。 这可能会导致难以将语言变更回你所能理解的语言,因为所有设置 UI 屏幕可能最终都使用你无法理解的语言。 像 Opera 这样的浏览器是一个很好的测试选择,因为它允许你为网页请求设置一个默认语言,但将浏览器的设置 UI 保留为你的语言。
当区域性为美国英语 (en-US
) 时,呈现的组件使用“月/日”日期格式 (6/7
)、12 小时制时间 (AM
/PM
),并在数值中使用逗号分隔符,在小数值中使用点 (1,999.69
):
- 日期:6/7/2021 6:45:22 AM
- 数值:1,999.69
当区域性为智利西班牙语 (es-CL
) 时,呈现的组件使用“日/月”日期格式 (7/6
)、24 小时制时间,并在数值中使用句点分隔符,在小数值中使用逗号(1.999,69
):
- 日期:7/6/2021 6:49:38
- 数值:1.999,69
静态设置区域性
默认情况下,Blazor WebAssembly 应用的中间语言 (IL) 链接器配置去除国际化信息(显式请求的区域设置除外)。 有关详细信息,请参阅为 ASP.NET Core Blazor 配置链接器。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
在将路由中间件添加到处理管道后,立即在 Startup.Configure
(Startup.cs
) 中指定静态区域性。 下面的示例配置美国英语:
app.UseRequestLocalization("en-US");
UseRequestLocalization 的区域性值必须符合 BCP-47 语言标记格式。
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
使用演示组件部分中显示的 CultureExample1
组件来研究全球化的工作方式。 使用美国英语 (en-US
) 发出请求。 在浏览器的语言设置中切换到智利西班牙语 (es-CL
)。 再次请求该网页。 当请求的语言为智利西班牙语时,应用的区域性将保留为美国英语 (en-US
)。
按用户首选项动态设置区域性
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例演示如何使用浏览器本地存储。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
Blazor WebAssembly 应用中的应用区域性是使用 Blazor 框架的 API 设置的。 用户的区域性选择可以保留在浏览器本地存储中。
在 wwwroot/index.html
文件中,在 Blazor 的 <script>
标记后和结束标记 </body>
前,提供 JS 函数以使用浏览器本地存储获取和设置用户的区域性选择:
<script>
window.blazorCulture = {
get: () => window.localStorage['BlazorCulture'],
set: (value) => window.localStorage['BlazorCulture'] = value
};
</script>
将 System.Globalization 和 Microsoft.JSInterop 的命名空间添加到 Program.cs
顶部:
using System.Globalization;
using Microsoft.JSInterop;
删除 Program.cs
中的以下行:
- await builder.Build().RunAsync();
用下面的代码替换前面的行。 该代码通过 AddLocalization 将 Blazor 的本地化服务添加到应用的服务集合,并使用 JS 互操作调入 JS,然后从本地存储中检索用户的区域性选择。 如果本地存储不包含用户的区域性,代码会设置默认值“美国英语”(en-US
)。
builder.Services.AddLocalization();
var host = builder.Build();
CultureInfo culture;
var js = host.Services.GetRequiredService<IJSRuntime>();
var result = await js.InvokeAsync<string>("blazorCulture.get");
if (result != null)
{
culture = new CultureInfo(result);
}
else
{
culture = new CultureInfo("en-US");
await js.InvokeVoidAsync("blazorCulture.set", "en-US");
}
CultureInfo.DefaultThreadCurrentCulture = culture;
CultureInfo.DefaultThreadCurrentUICulture = culture;
await host.RunAsync();
重要
始终将 DefaultThreadCurrentCulture 和 DefaultThreadCurrentUICulture 设置为相同的区域性,以便使用 IStringLocalizer 和 IStringLocalizer<T>。
以下 CultureSelector
组件显示如何通过 JS 互操作将用户的区域性选择设置到浏览器本地存储中。 该组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject IJSRuntime JS
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var js = (IJSInProcessRuntime)JS;
js.InvokeVoid("blazorCulture.set", value.Name);
Navigation.NavigateTo(Navigation.Uri, forceLoad: true);
}
}
}
}
注意
有关 IJSInProcessRuntime 的详细信息,请参阅在 ASP.NET Core Blazor 中从 .NET 方法调用 JavaScript 函数。
在 Shared/MainLayout.razor
中的 <div class="main">
元素的结束标记 </div>
内,添加 CultureSelector
组件:
<div class="bottom-row px-4">
<CultureSelector />
</div>
应用可能存储用户首选项的位置的示例包括:在浏览器本地存储中(常见于 Blazor WebAssembly 应用)、本地化 cookie 或数据库中(常见于 Blazor Server 应用),或在附加到外部数据库并由 Web API 访问的外部服务中。 下面的示例展示了如何使用本地化 cookie。
将 Microsoft.Extensions.Localization
包添加到应用。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
Blazor Server 应用使用本地化中间件进行本地化。 使用 AddLocalization 将本地化服务添加到应用。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
使用 RequestLocalizationOptions 设置应用的默认且受支持的区域性。
在将路由中间件添加到处理管道后,在 Startup.Configure
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
下面的示例演示如何在可由本地化中间件读取的 cookie 中设置当前区域性。
将以下命名空间添加到 Pages/_Host.cshtml
文件顶部:
@using System.Globalization
@using Microsoft.AspNetCore.Localization
在 Pages/_Host.cshtml
的开始标记 <body>
后面,紧接着添加以下 Razor 表达式:
@{
this.HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(
CultureInfo.CurrentCulture,
CultureInfo.CurrentUICulture)));
}
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用未配置为处理控制器操作:
通过在
Startup.ConfigureServices
中对服务集合调用 AddControllers 来添加 MVC 服务:services.AddControllers();
通过对 IEndpointRouteBuilder 调用 MapControllers 在
Startup.Configure
中添加控制器终结点路由:endpoints.MapControllers();
下面的示例演示如何在添加行后调用 UseEndpoints:
app.UseEndpoints(endpoints => { endpoints.MapControllers(); endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); });
若要提供支持用户选择区域性的 UI,请将基于重定向的方法和本地化 cookie 结合使用。 应用通过重定向到控制器来保留用户的所选区域性。 控制器将用户选择的区域性设置为 cookie,然后将用户重定向回原始 URI。 此过程类似于用户尝试访问安全资源时在 Web 应用中发生的情况,用户会被重定向到登录页,然后重定向回原始资源。
Controllers/CultureController.cs
:
using Microsoft.AspNetCore.Localization;
using Microsoft.AspNetCore.Mvc;
[Route("[controller]/[action]")]
public class CultureController : Controller
{
public IActionResult Set(string culture, string redirectUri)
{
if (culture != null)
{
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture, culture)));
}
return LocalRedirect(redirectUri);
}
}
警告
使用 LocalRedirect 操作结果以阻止开放式重定向攻击。 有关详细信息,请参阅预防 ASP.NET Core 中的开放式重定向攻击。
以下 CultureSelector
组件显示了如何在用户选择区域性时执行初始重定向。 该组件位于 Shared
文件夹中,供整个应用使用。
Shared/CultureSelector.razor
:
@using System.Globalization
@inject NavigationManager Navigation
<p>
<label>
Select your locale:
<select @bind="Culture">
@foreach (var culture in supportedCultures)
{
<option value="@culture">@culture.DisplayName</option>
}
</select>
</label>
</p>
@code
{
private CultureInfo[] supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("es-CL"),
};
protected override void OnInitialized()
{
Culture = CultureInfo.CurrentCulture;
}
private CultureInfo Culture
{
get => CultureInfo.CurrentCulture;
set
{
if (CultureInfo.CurrentCulture != value)
{
var uri = new Uri(Navigation.Uri)
.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var cultureEscaped = Uri.EscapeDataString(value.Name);
var uriEscaped = Uri.EscapeDataString(uri);
Navigation.NavigateTo(
$"Culture/Set?culture={cultureEscaped}&redirectUri={uriEscaped}",
forceLoad: true);
}
}
}
}
在 Shared/MainLayout.razor
中的 <div class="main">
元素的结束标记 </div>
内,添加 CultureSelector
组件:
<div class="bottom-row px-4">
<CultureSelector />
</div>
使用演示组件部分中显示的 CultureExample1
组件来研究前面示例的工作原理。
本地化
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请向应用添加 Microsoft.Extensions.Localization
包。
注意
有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。
默认情况下,Blazor WebAssembly 应用的中间语言 (IL) 链接器配置去除国际化信息(显式请求的区域设置除外)。 有关详细信息,请参阅为 ASP.NET Core Blazor 配置链接器。
在 Program.cs
中,将 System.Globalization 的命名空间添加到文件顶部:
using System.Globalization;
将 Blazor 的本地化服务添加到应用的服务集合中,其中 Program.cs
包含 AddLocalization:
builder.Services.AddLocalization();
使用本地化中间件设置应用的区域性。
如果应用尚不支持按本文的按用户首选项动态设置区域性部分来选择区域性,请执行以下操作:
- 使用 AddLocalization 将本地化服务添加到应用。
- 在
Startup.Configure
(Startup.cs
) 中指定应用的默认且受支持的区域性。 下面的示例为美国英语和智利西班牙语配置支持的区域性。
在 Startup.ConfigureServices
(Startup.cs
) 中:
services.AddLocalization();
在将路由中间件添加到处理管道后,在 Startup.Configure
中会立即执行以下操作:
var supportedCultures = new[] { "en-US", "es-CL" };
var localizationOptions = new RequestLocalizationOptions()
.SetDefaultCulture(supportedCultures[0])
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
app.UseRequestLocalization(localizationOptions);
有关在 Startup.Configure
的中间件管道中对本地化中间件进行排序的信息,请参阅 ASP.NET Core 中间件。
如果应用应基于存储用户的区域性设置来本地化资源,则使用本地化区域性 cookie。 使用 cookie 可确保 WebSocket 连接可以正确地传播区域性。 如果本地化方案基于 URL 路径或查询字符串,则该方案可能无法与 Websocket 协同使用,因而无法保留区域性。 因此,建议的方法是使用本地化区域性 cookie。 若要查看保留用户区域性选择的 Pages/_Host.cshtml
文件的示例 Razor 表达式,请参阅本文的按用户首选项动态设置区域性部分。
本部分中的本地化资源示例与本文前面的示例一样,应用的受支持区域性是将英语 (en
) 作为默认区域设置,将西班牙语 (es
) 作为用户可选择的或浏览器指定的备用区域设置。
为每个区域设置创建资源。 在下面的示例中,为默认 Greeting
字符串创建了资源:
- 英语:
Hello, World!
- 西班牙语 (
es
):¡Hola, Mundo!
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 Hello, World!
。 保存文件。
Pages/CultureExample2.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>Hello, World!</value>
</data>
</root>
注意
在 Visual Studio 中,可以通过右键单击项目的 Pages
文件夹并选择“添加”>“新项”>“资源文件”,添加以下资源文件。 命名文件 CultureExample2.es.resx
。 出现编辑器时,为新项提供数据。 将“名称”设置为 Greeting
,并将“值”设置为 ¡Hola, Mundo!
。 保存文件。
Pages/CultureExample2.es.resx
:
<?xml version="1.0" encoding="utf-8"?>
<root>
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Greeting" xml:space="preserve">
<value>¡Hola, Mundo!</value>
</data>
</root>
以下组件演示如何将本地化 Greeting
字符串用于 IStringLocalizer<T>。 以下示例中的 Razor 标记 @Loc["Greeting"]
将键控为 Greeting
值的字符串本地化,该值在前面的资源文件中设置。
将 Microsoft.Extensions.Localization 的命名空间添加到应用的 _Imports.razor
文件中:
@using Microsoft.Extensions.Localization
Pages/CultureExample2.razor
:
@page "/culture-example-2"
@using System.Globalization
@inject IStringLocalizer<CultureExample2> Loc
<h1>Culture Example 2</h1>
<p>
<b>CurrentCulture</b>: @CultureInfo.CurrentCulture
</p>
<h2>Greeting</h2>
<p>
@Loc["Greeting"]
</p>
<p>
@greeting
</p>
@code {
private string greeting;
protected override void OnInitialized()
{
greeting = Loc["Greeting"];
}
}
(可选)将菜单项添加到 CultureExample2
组件的 Shared/NavMenu.razor
中的导航。
共享资源
若要创建本地化共享资源,请采用以下方法。
创建具有任意类名的虚拟类。 如下示例中:
- 应用使用
BlazorSample
命名空间,本地化资产使用BlazorSample.Localization
命名空间。 - 虚拟类名为
SharedResource
。 - 类文件位于应用根目录的
Localization
文件夹中。
Localization/SharedResource.cs
:namespace BlazorSample.Localization { public class SharedResource { } }
- 应用使用
使用
Embedded resource
的生成操作创建共享资源文件。 如下示例中:文件放置在具有虚拟
SharedResource
类 (Localization/SharedResource.cs
) 的Localization
文件夹中。将资源文件命名为与虚拟类的名称一致。 以下示例文件包括一个默认本地化文件和一个西班牙语 (
es
) 本地化文件。Localization/SharedResource.resx
Localization/SharedResource.es.resx
注意
Localization
是可以通过 LocalizationOptions 设置的资源路径。若要引用 Razor 组件中已注入 IStringLocalizer<T> 的虚拟类,请为本地化命名空间放置
@using
指令,或在虚拟类引用中包含本地化命名空间。 在以下示例中:- 第一个示例使用
Localization
指令声明SharedResource
虚拟类的@using
命名空间。 - 第二个示例显式声明
SharedResource
虚拟类的命名空间。
在 Razor 组件中,使用以下任一方法:
@using Localization @inject IStringLocalizer<SharedResource> Loc
@inject IStringLocalizer<Localization.SharedResource> Loc
- 第一个示例使用
有关其他指南,请参阅 ASP.NET Core 中的全球化和本地化。