ASP.NET应用程序的本地化实践

在全球化的今天,软件产品需要支持多种语言以满足不同地区用户的需求。本地化是软件开发中的一个重要环节,它涉及到将应用程序的界面、文档和帮助等内容翻译成目标语言。本文将介绍如何使用Blazor模板应用程序对ASP.NET应用程序进行本地化处理,包括本地化的益处、从全局到局部的本地化策略、构建本地化类、设置文化、提供本地化器、使用本地化器以及运行时语言切换。

本地化的益处

本地化不仅仅是简单的翻译工作,它还包括对目标语言和文化的理解。通过本地化,可以为不同地区的用户提供更加友好和亲切的用户体验。以下是本地化带来的一些主要益处:

1. 本地化文本按主题分组,便于管理和维护。

2. 本地化参数具有类型安全性,减少了错误和混淆。

3. 枚举类型的本地化,使得枚举值也能被正确翻译。

4. 清晰的翻译模板,方便翻译人员理解和翻译。

从全局到局部的本地化策略

要实现本地化,应用程序必须设计得尽可能文化中立,即作为一个全球应用程序。然后,通过本地化相应的文化来扩展全局应用程序。这种分离是通过将本地化文本放置在资源文件中实现的。

资源文件的类型通常是.resx。以下是一个示例应用程序的本地化概览:

在Visual Studio中,本地化表示如下:

  • Localizations.csproj - 类库
  • LocalizerBase.cs - 所有本地化器的基类
  • Localizer.cs - 本地化的起始类
  • Resources\Localizations.resx - 英文(默认)本地化资源
  • Resources\Localizations.de.resx - 德语本地化资源
  • GlobalApp.csproj -Blazor服务器应用程序
  • Shared\*.razor - 共享组件
  • Pages\*.razor - 应用程序页面

构建本地化类

所有本地化文本都按主题划分到本地化类中,这些类继承自基类LocalizerBase。通过根类Localizer访问本地化文本:

public class Localizer : LocalizerBase { public Localizer(IStringLocalizerFactory factory) : base(factory, nameof(Localizer)) { App = new AppLocalizer(factory); Home = new HomeLocalizer(factory); Survey = new SurveyLocalizer(factory); Counter = new CounterLocalizer(factory); Forecast = new ForecastLocalizer(factory); } public AppLocalizer App { get; } public HomeLocalizer Home { get; } public SurveyLocalizer Survey { get; } public CounterLocalizer Counter { get; } public ForecastLocalizer Forecast { get; } }

对于每个主题,实现一个本地化器以提供对翻译资源的访问,例如CounterLocalizer:

public class CounterLocalizer : LocalizerBase { public CounterLocalizer(IStringLocalizerFactory factory) : base(factory) { } public string Title => Localization(); public string Click => Localization(); public string CurrentCount(int currentCount) => ApplyParameter(Localization(), nameof(currentCount), currentCount); }

固定的翻译数据是通过Localization()方法确定的。翻译键Counter.Title、Counter.Click和Counter.CurrentCount是从类名和属性生成的。带有变量参数的翻译会生成带有参数名占位符的格式化文本,例如“当前计数:{currentCount}”。

设置文化

Culture类管理翻译文化:

  • 可用语言
  • 默认语言
  • 访问翻译资源的路径
  • 获取和更改运行时语言

对于ASP.NET应用程序,结构不是在应用程序级别(CultureInfo.CurrentCulture和CultureInfo.CurrentUICulture)设置的,而是在web请求线程级别(CultureInfo.DefaultThreadCurrentCulture和CultureInfo.DefaultThreadCurrentUICulture)设置的。

提供本地化

Localizer通过依赖注入访问,在应用程序启动时设置。

public class Program { private static void SetupLocalization(IServiceCollection services) { services.AddLocalization(o => { o.ResourcesPath = Cultures.ResourcesPath; }); services.AddTransient<Localizer>(); Cultures.ApplyCulture(); } public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorPages(); builder.Services.AddServerSideBlazor(); builder.Services.AddSingleton<WeatherForecastService>(); // localizations SetupLocalization(builder.Services); var app = builder.Build(); // app setup ... app.Run(); } }

SetupLocalization方法执行以下步骤:

  • 注册Microsoft Localization Extensions
  • 在依赖注入中注册'Localizer'
  • 为当前线程设置默认语言

使用本地化器

Localizer通过Inject插入到页面中,并用可读的属性或方法访问替换硬编码文本。

<ml-basic> @page "/counter" @using Localization <PageTitle>Counter</PageTitle> <h1>@Localizer?.Counter.Title</h1> <p role="status">@Localizer?.Counter.CurrentCount(currentCount)</p> <button class="btn btn-primary" @onclick="IncrementCount"> @Localizer?.Counter.Click </button> @code { private int currentCount; [Inject] private Localizer? Localizer { get; set; } private void IncrementCount() { currentCount++; } } </ml-basic>

值@Localizer?.Counter.Title返回本地化的标题,@Localizer?.Counter.CurrentCount(currentCount)提供类型安全性(int)。

本地化枚举

另一种场景是翻译枚举,其本地化存储按照Enum.<EnumTypeName>.<EnumValue>约定。可以使用Localizer.Enum<T>(T value)查询本地化的枚举。

<ml-basic> @page "/" @using Localization <PageTitle>@Localizer?.Home.Title</PageTitle> <h1>@Localizer?.Home.Header</h1> @Localizer?.Home.Welcome <SurveyPrompt Title="@Localizer?.Home.SurveyTitle"/> @Localizer?.Home.EnumLocalization <InputSelect @bind-Value="CurrentColor"> @foreach (var value in Enum.GetValues(typeof(Color))) { <option>@Localizer?.Enum((Color)value)</option> } </InputSelect> @code { [Inject] private Localizer? Localizer { get; set; } private string? CurrentColor { get; set; } protected override Task OnInitializedAsync() { CurrentColor = Localizer?.Enum(Color.Red); return base.OnInitializedAsync(); } } </ml-basic>
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485