asp.net core 实现支持多语言
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 上的讨论
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
实际项目中的资源文件示例:
实际访问效果:
默认的中文界面:
英文界面:
只是做了几个前台的示例,还有很多地方没改
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
推荐阅读
-
Android编程实现动态支持多语言的方法
-
Jexus 5.8.2正式发布! 为Asp.Net Core生产环境提供平台支持
-
在ASP.NET Core中使用托管启动(hosting startup)程序集,实现批量注册service
-
ASP.NET Core 3.0 原生DI拓展实现IocManager
-
.net core 实现基于 JSON 的多语言
-
ASP.NET Core 3.0 使用AspectCore-Framework实现AOP
-
在ASP.NET Core中实现自动注入、批量注入
-
asp.net core IdentityServer4 实现 implicit(隐式许可)实现第三方登录
-
Asp.Net Core基于Cookie实现同域单点登录(SSO)
-
ASP.NET Core 2.0集成Office Online Server(OWAS)实现办公文档的在线预览与编辑(支持word\excel\ppt\pdf等格式)