views 多文件夹 netcore_asp.net core 实现支持多语言

news/2024/7/5 19:29:25 标签: views 多文件夹 netcore

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 页面

49586abce69328df6058c89c703fd467.png

浏览器效果:

4844694f99e207b089425361ee914af3.png

查看网页源代码:

9c1d9e67dacf4c3224da35f982b16196.png

实际案例

服务注册

注册 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();

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 nameDot or path naming
Resources/Controllers.HomeController.fr.resxDot
Resources/Controllers/HomeController.fr.resxPath
  • Resources/Views/Home/About.fr.resx

  • Resources/Views.Home.About.fr.resx

实际项目中的资源文件示例:

23d2def52570b7fae91574fe33aef45d.png

实际访问效果:https://reservation.weihanli.xyz/

默认的中文界面:

8b4e330997e6a2747821a8fa297a4dfe.png

英文界面:

a2a7284e62a9402fffa3c9018de06cf8.png

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

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

  • https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1

  • https://github.com/dotnet/extensions/tree/master/src/Localization

  • https://github.com/dotnet/aspnetcore/tree/master/src/Middleware/Localization

  • https://stackoverflow.com/questions/2074869/globalization-vs-localization

  • https://github.com/WeihanLi/ActivityReservation


http://www.niftyadmin.cn/n/873633.html

相关文章

java list的tostring_关于java的容器类 list,map等的toString()方法

展开全部1.List 中常用的ArrayList的toString() 继承于abstract class AbstractCollection 这个类public String toString(){Iterator iterator1 iterator();if(!636f707962616964757a686964616f31333337616630iterator1.hasNext())return "[]";StringBuilder stri…

java 备份sqlserver数据库_Java实现SQLserver数据的备份与还原

由于项目需求&#xff0c;最近用到了在系统中给用户提供数据备份与还原功能&#xff0c;数据库为SQLserver2005&#xff0c;第一次遇到这种需求&#xff0c;做的过程也遇到了不少问题&#xff0c;特此记录下来&#xff0c;以备不时之需&#xff0c;同时也供有类似需求的童鞋借鉴…

一位软件工程师的6年总结(转)

“又是一年毕业时 ”&#xff0c;看到一批批学子离开人生的象牙塔&#xff0c;走上各自的工作岗位&#xff1b;想想自己也曾经意气风发、踌躇满志&#xff0c;不觉感叹万千…… 本文是自己工作6年的经历沉淀或者经验提炼&#xff0c;希望对所有的软件工程师们有所帮助&#xff…

python 服务注册_EasyService

软件简介介绍如果你的 Windows 程序需要在开机后用户登录之前就开始运行、且在用户注销之后也不停止&#xff0c;那么你需要将程序注册为一个系统服务。然而&#xff0c;在 Windows下编写一个可注册为系统服务的程序并不是一件简单的事情。首先&#xff0c;程序必须是二进制的可…

java 多个resultset_java.sql.resultSet接口中有很多方法的实现

接口是很重要的面向对象方式&#xff0c;继承接口的类不用全部实现定义的接口&#xff0c;可以这么说&#xff0c;我定义了好多接口&#xff0c;某个类可以这么实现这个接口&#xff0c;到另一个类你又想那么实现接口&#xff0c;都是可以的。或者定义完接口不想管他都可以&…

思考的哲理

1. 人之所以痛苦&#xff0c;在于追求错误的东西。2. 如果你不给自己烦恼&#xff0c;别人也永远不可能给你烦恼。因为你自己的内心&#xff0c;你放不下。 3. 你永远要感谢给你逆境的众生。4. 你永远要宽恕众生&#xff0c;不论他有多坏&#xff0c;甚至他伤害过你&#xff0c…

浅淡《高效能人士的七个习惯》

[url]http://poson.iteye.com/blog/427358[/url]《高效能人士的七个习惯》是一本畅销书&#xff0c;很多管理人员必看的经典教程之一。最近公司也是特意组织培训了这里面的几个习惯。我印象深刻的有以下几点&#xff1a;积极主动&#xff1a;核心就是你要主动去做&#xff0c;你…

三级流域空间分布图_新版白话空间统计(26)标准距离

前文再续&#xff0c;书接上一回。上次我们讲了方向分布工具&#xff0c;这个工具会生成一个标准差椭圆&#xff0c;其中有这样的一句话描述&#xff1a;“短半轴表示数据分布的范围&#xff0c;短半轴越短&#xff0c;表示数据呈现的向心力越明显&#xff1b;反之&#xff0c;…