asp.net core 实现支持多语言

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 上的讨论 https://stackoverflow.com/questions/2074869/globalization-vs-localization

Localization In Asp.NET Core

微软官方的 Localization 的实现是基于资源文件实现的 (*.resx),我们也可以扩展支持更多方式,如 JSON/数据库 都是可以的,社区已经有实现的示例,只要是可以提供一个文本源的都是可以的,我们先使用默认的基于资源文件的,下一篇再讲一个自定义实现一个 Localization Provider。

.NET Core Localization 的 核心是 IStringLocalizer,asp.net core 里扩展定义了 IViewLocalizerIHtmlLocalizerIViewLocalizerIHtmlLocalizer 主要是为了处理包含 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();

逻辑代码中使用示例:

IStringLocalizerIHtmlLocalizer /IViewLocalizer 都可以直接从依赖注入服务中获取,IStringLocalizerIHtmlLocalizer 推荐使用强类型的方式,也就是下面示例的使用方式,使用方式和 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/

默认的中文界面:

英文界面:

只是做了几个前台的示例,还有很多地方没改

Docker 部署

现在的项目是基于 docker + k8s 部署的,所以支持 docker 部署很重要

要支持多语言,需要安装 ICU 相关的包,(这个可不是 996.icu 的 icu 哈,如果不装真的有可能导致 996.icu)

RUN apk add --no-cache icu-libs # 安装 icu-libs
ENV DOTNET_SYSTEM_GLOBALIZATION_INVARIANT false # 配置 Globalization

完整的 dockerfile 可以参考:

https://github.com/dotnet/dotnet-docker/blob/cb7a9c35dacf6d34fcf7bab7995e60faef55f61f/samples/dotnetapp/Dockerfile.alpine-x64-globalization

More

.net core 的设计真的是很灵活,很优美,基于资源文件的本地化,感觉不太方便,使用资源文件的化可能就只能使用 VS 编辑了,虽然也是纯文本的,基于 xml 但是编辑起来不如界面看着编辑舒服,如果使用 json 之类的,就比较简单明了,编辑起来也比较方便,所以想把资源文件替换成 JSON 文件

下次分享一篇基于 JSON 的 Localization Provider 的实现

Reference

asp.net core 实现支持多语言的更多相关文章

  1. 使Asp.net Core同时支持输出Json/Xml

    我们知道Asp.net Core是支持输出为Json格式的.同时也支持输出为xml格式.只要我们正确的配置.并在Request时指定正确的Accept,即可根据不同的Header来输出不同的格式. 前 ...

  2. asp.net core 实现支持自定义 Content-Type

    asp.net core 实现支持自定义 Content-Type Intro 我们最近有一个原本是内网的服务要上公网,在公网上有一层 Cloudflare 作为网站的公网流量提供者,CloudFla ...

  3. 体验 ASP.NET Core 中的多语言支持(Localization)

    首先在 Startup 的 ConfigureServices 中添加 AddLocalization 与 AddViewLocalization 以及配置 RequestLocalizationOp ...

  4. 快速搭建CentOS+ASP.NET Core环境支持WebSocket

    环境:CentOS 7.x,.net core 2 以下.net core 2安装操作为官方方法.如果你使用Docker,那么更简单了,只需要docker pull microsoft/dotnet就 ...

  5. Asp.Net Core 已支持 gRPC-Web !!

    grpc-dotnet 项目在 PR #695 完成了 ASP.NET Core 服务与 .NET Core gRPC 客户端的 gRPC-Web 实现. 虽然目前还是实验性项目,但是并不阻碍我们为之 ...

  6. Asp.net Core WebApi 支持json/xml格式的数据返回

    Asp.net core 在做webapi项目的时候,默认是只返回json格式的数据的,如果想要开启xml数据返回,需要在startup里配置如下: public void ConfigureServ ...

  7. 部署asp.net core Kestrel 支持https 使用openssl自签ssl证书

    通过openssl生成证书 openssl req -newkey rsa:2048 -nodes -keyout my.key -x509 -days 365 -out my.cer openssl ...

  8. ASP.NET Core多语言 (转载)

    ASP.NET Core中提供了一些本地化服务和中间件,可将网站本地化为不同的语言文化.ASP.NET Core中我们可以使用Microsoft.AspNetCore.Localization库来实现 ...

  9. asp.net core 之多语言国际化自定义资源文件

    先说说 asp.net core 默认的多语言和国际化. 官方文档 一:基本使用方法 先要安装 包 Microsoft.AspNetCore.Mvc.Localization (依赖 Microsof ...

随机推荐

  1. python2和python3一些不同

    文件写法: #python2fp=file(filepath,'wb')#python3# fp = open(filepath, 'wb') 关于乱码问题: #python2 #coding=utf ...

  2. selenium webdriver学习(八)------------如何操作select下拉框(转)

    selenium webdriver学习(八)------------如何操作select下拉框 博客分类: Selenium-webdriver   下面我们来看一下selenium webdriv ...

  3. oracle函数 round(x[,y])

    [功能]返回四舍五入后的值 [参数]x,y,数字型表达式,如果y不为整数则截取y整数部分,如果y>0则四舍五入为y位小数,如果y小于0则四舍五入到小数点向左第y位. [返回]数字 [示例] se ...

  4. behavior planning——15.cost function design weightTweaking

    Designing cost functions is difficult and getting them all to cooperate to produce reasionable vehic ...

  5. python项目管理

    Python 通常没有对应 Java 的 Ant / Maven 这样的 build tool,有一个用于打包的 setuptools / distutils 但也并不完全等价.如果是用来管理依赖包, ...

  6. 全面理解Python中的类型提示(Type Hints)

    众所周知,Python 是动态类型语言,运行时不需要指定变量类型.这一点是不会改变的,但是2015年9月创始人 Guido van Rossum 在 Python 3.5 引入了一个类型系统,允许开发 ...

  7. 【CSS3】使用CSS3制作全屏切换效果

    在线演示: DEMO DEMO中及以下代码并没有写兼容代码,请使用高级浏览器打开,IE版本对CSS3支持并不太友好,IE11打开没有滚屏效果. 兼容代码前缀: -webkit- -moz- -o- - ...

  8. jQuery中的siblings()的用法

    siblings  英文翻译    兄; 弟; 姐; 妹;   的意思 siblings()用于查找当前元素的同胞元素,就是拿到当前元素的兄弟节点(不包括自己). 给当前元素设置新的样式,并删除当前元 ...

  9. pip安装python包时报字符编码错

    比如安装scikit-learn时报错: django ascii’ codec can’t encode character 原因是用户目录或用户名存在中文,ascii不能解码,解决办法是在Pyth ...

  10. js基础-原型

    1.定义:我们创建的函数都有一个prototype(原型)属性,该属性是一个对象,          原型模式声明中多了两个属性(自动生成). 构造函数:       function Box(nam ...