Intro
最近有一个外国友人通过邮件联系我, 想用我的活动室预约, 但是还没支持多语言, 基本上都是写死的中文, 所以最近想支持一下更多语言, 于是有了多语言方面的一些实践
国际化 / 本地化介绍
国际化 (Globalization) 和本地化 (Localization) 是要实现的多语言支持的基础
- Globalization is the process of designing and developing applications that function for multiple cultures.
- Localization is the process of customizing your application for a given culture and locale.
国际化是要支持处理多种文化, 而本地化是要根据某一个文化和区域的来展示相应的处理.
更多关于国际化与本地化的不同可以参考 Stack Overflow 上的讨论
Localization In ASP.NET Core
微软官方的 Localization 的实现是基于资源文件实现的 (*.resx), 我们也可以扩展支持更多方式, 如 JSON / 数据库 都是可以的, 社区已经有实现的示例, 只要是可以提供一个文本源的都是可以的, 我们先使用默认的基于资源文件的, 下一篇再讲一个自定义实现一个 Localization Provider.
.NET Core Localization 的 核心是 IStringLocalizer,ASP.NET core 里扩展定义了 IViewLocalizer 和 IhtmlLocalizer,IViewLocalizer 和 IHtmlLocalizer 主要是为了处理包含 HTML 的资源, 他们不会对资源进行 HTML encode, 相当于 @HTML.Raw 的效果, 而 IStringLocalizer 则会被 HTML encode, 除此之外 IViewLocalizer 还会根据当前视图的路径寻找资源文件
来看一个示例:
Razor 页面
浏览器效果:
查看网页源代码:
实际案例
服务注册
注册 Localization 相关服务:
- var supportedCultures = new[]
- {
- new CultureInfo("zh"),
- new CultureInfo("en"),
- };
- services.Configure<RequestLocalizationOptions>(options =>
- {
- options.DefaultRequestCulture = new RequestCulture("zh");
- // Formatting numbers, dates, etc.
- options.SupportedCultures = supportedCultures;
- // UI strings that we have localized.
- options.SupportedUICultures = supportedCultures;
- });
- services.AddLocalization(options => options.ResourcesPath = Configuration.GetAppSetting("ResourcesPath"));
配置视图 Localization(根据需要如果是 webAPI 就不需要了)
- services.AddControllersWithViews()
- .AddNewtonsoftJson(options =>
- {
- options.SerializerSettings.ContractResolver = new DefaultContractResolver();
- options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc; // 设置时区为 UTC
- options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
- options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
- })
- .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix,
- opts => { opts.ResourcesPath = Configuration.GetAppSetting("ResourcesPath"); })
- .AddDataAnnotationsLocalization()
- .SetCompatibilityVersion(CompatibilityVersion.Latest);
中间件配置:
App.UseRequestLocalization();
在控制器中使用示例:
IStringLocalizer 和 IHtmlLocalizer /IViewLocalizer 都可以直接从依赖注入服务中获取, IStringLocalizer 和 IHtmlLocalizer 推荐使用强类型的方式, 也就是下面示例的使用方式, 使用方式和 ILogger 类似
- public async Task<ActionResult> MakeReservation(
- [FromBody]ReservationViewModel model,
- [FromHeader]string captcha,
- [FromHeader]string captchaType,
- [FromServices]IStringLocalizer<HomeController> localizer)
- {
- var result = new ResultModel<bool>();
- var isCodeValid = await HttpContext.RequestServices.GetService<CaptchaVerifyHelper>()
- .ValidateVerifyCodeAsync(captchaType, captcha);
- if (!isCodeValid)
- {
- result.Status = ResultStatus.RequestError;
- result.ErrorMsg = localizer["InvalidCaptchaInfo"];
- return JSON(result);
- }
在视图中使用示例:
localizer["data"] 返回的是一个 LocalizedString, 实现了隐式转换为 string, 有的时候可能需要强制转一下 string, 或者使用 Value 属性
- @inject IViewLocalizer viewLocalizer
- viewLocalizer["About"]
- @HTML.ActionLink((string)viewLocalizer["About"], "About", "Home")
- @HTML.ActionLink(viewLocalizer["About"].Value, "About", "Home")
资源文件配置:
资源文件的配置和文件的结构类似, 下面是一个示例
准备的来说是和类型的 FullName 有关系, 一般的项目名称就是程序集名称, 就是根命名空间, 文件名称就是类型名称, 所以一般情况下资源文件的位置和类型的位置是一致的, 但是如果文件和类型名称不符合, 那就要按照类型的 FullName 来找, 视图也是类似的, 如果根命名空间不是程序集名称, 也是可以配置的具体的参考文档
Controllers.HomeController => Controllers/HomeController.zh.resx/Controllers/HomeController.en.resx
Resource name | Dot or path naming |
---|---|
Resources/Controllers.HomeController.fr.resx | Dot |
Resources/Controllers/HomeController.fr.resx | Path |
- Resources/Views/Home/About.fr.resx
- Resources/Views.Home.About.fr.resx
实际项目中的资源文件示例:
实际访问效果: https://reservation.weihanli.xyz/
默认的中文界面:
英文界面:
只是做了几个前台的示例, 还有很多地方没改
More
.net core 的设计真的是很灵活, 很优美, 基于资源文件的本地化, 感觉不太方便, 使用资源文件的化可能就只能使用 VS 编辑了, 虽然也是纯文本的, 基于 xml 但是编辑起来不如界面看着编辑舒服, 如果使用 JSON 之类的, 就比较简单明了, 编辑起来也比较方便, 所以想把资源文件替换成 JSON 文件
下次分享一篇基于 JSON 的 Localization Provider 的实现
- Reference
- https://github.com/WeihanLi/ActivityReservation
来源: https://www.cnblogs.com/weihanli/p/implement-localization-in-asp-net-core.html