MasaFramework -- i18n (国际化)
概念
作为一个普通开发者, 我们负责的项目的使用群体大多数是本国的人民, 但不可避免的也有一些做外贸的业务或者给外企做的项目, 这个时候就要求我们的项目有服务全球客户的能力, 而一个支持国际化能力的框架会让我们项目的体验变得更好.
关于本地化我们听到最多的是I18N、L10N、G11N, 那它们分别代表了什么意思呢?
- I18N: 是"Internationalization" 的缩写, 由于I到N之间间隔了18个字母, 也被简称为"i18n". 使产品或软件具有不同国际市场的普遍适应性, 从而无需重新设计就可适应多种语言和文化习俗的过程. 真正的国际化要在软件设计和文档开发过程中, 使产品或软件的功能和代码设计能处理多种语言和文化习俗, 具有良好的本地化能力. 它让程序具备了支持多种语言的能力
- L10N: 是"Localization"的缩写, 由于L到N之间间隔了10个字母, 也被简称为"L10N". 是将产品或软件针对特定国际语言和文化进行加工, 使之符合特定区域市场的过程. 真正的本地化要考虑目标区域市场的语言、文化、习俗、特征和标准. 通常包括改变软件的书写系统(输入法)、键盘使用、字体、日期、时间和货币格式等
- G11N: 是"Globalization"的缩写, 由于G到N之间间隔了11个字母, 也被简称为"G11n", 是指在全球范围内推出产品的业务方面, 可以简单理解为 "I18N" + "L10N"
本地化的意义
本地化包括:
- 产品本地化
- 技术研发本地化
- 原材料本地化
- 人才本地化
- 企业文化本地化
经过研究表明, 本地化后的产品的销量会比未经过本地化的更好, 75%的人偏好用母语购买产品, 86%的本地化广告在点击率、转换率上超过未经过本地化的广告, 这些数字都说明了人们对自己母语显示的内容更加感兴趣, 通过本地化可以让你更精准的打动客户, 帮你迅速的进入市场, 但本地化不等于直接翻译, 本地化是基于对当地市场情况和文化精心策划的, 在习惯、习俗、日期和货币格式上是不相同的, 本地化的产品能节约沟通成本, 更容易被理解和接受.
举个通俗的例子: 相比找一个不认识的陌生人买东西, 我们更喜欢去找那个知根知底的本地人买东西, 这无关产品的质量, 只是熟悉的人更容易获得我们的认同感
虽然本地化包括很多模块, 但在此我们只考虑产品的本地化, 下面我们就说一下如何做使得自己的产品可以支持本地化
使用
- 安装.NET 6.0
- 新建ASP.NET Core 空项目
Assignment.I18nDemo,并安装Masa.Contrib.Globalization.I18n.AspNetCore
dotnet add package Masa.Contrib.Globalization.I18n.AspNetCore --version 0.7.0-preview.16
- 注册
I18n, 并修改Program.cs
builder.Services.AddI18n();
- 使用
I18N
app.UseI18n();//启用本地化中间件
- 添加多语言资源文件, 文件夹结构如下:
- Resources
- I18n
- en-US.json
- zh-CN.json
- supportedCultures.json
- en-US.json
{
"Home":"Home"
}
- zh-CN.json
{
"Home":"首页"
}
- supportedCultures.json
[
{
"Culture":"zh-CN",
"DisplayName":"中文简体",
"Icon": "{Replace-Your-Icon}"
},
{
"Culture":"en-US",
"DisplayName":"English (United States)",
"Icon": "{Replace-Your-Icon}"
}
]
- 使用
I18n
app.Map("/test", (string key) => I18n.T(key));
- 测试多语言, 在浏览器访问"https://localhost:7082/get?key=Home"即可得到对应语言下键名为
Home的值
是不是感觉用起来十分简单呢, 但这究竟是如何做的呢
进阶
国内的小伙伴根据上面的例子操作下来, 会发现请求响应的内容是中文, 那什么情况下它会变成英文呢?
本地化中间件
由于.NET 提供了本地化的能力, 它提供了本地化的中间件, 通过它使得我们的项目具备解析当前语言的能力
目前它支持了以下三种方式进行语言切换:
- URL 参数 方式: ?culture=en-US,此方式优先级最高,格式为:culture=区域码
- Cookies 方式:cookie 格式为 c=%LANGCODE%|uic=%LANGCODE%,其中 c 是 Culture,uic 是 UICulture, 例如:
c=en-UK|uic=en-US
- 客户端浏览器语言自动匹配:如果前面两种方式都没有设置,支持自动根据客户端浏览器语言进行匹配
语言优先级:
URL 参数 方式 > Cookies方式 > 客户端语言 > 默认语言
默认语言
默认语言有两种配置方式, 它们分别是:
- 约定配置
supportedCultures.json文件中的第一个语言
- 手动指定默认语言
- 通过
app.UseI18n("{Replace-Your-DefaultCulture}")
- 通过
它们的优先级是:
手动指定默认语言 > 约定配置
修改默认资源路径
builder.Services.AddI18n(options =>
{
options.ResourcesDirectory = Path.Combine("Resources", "I18n");//修改默认资源路径
options.SupportedCultures = new List<CultureModel>() //支持语言
{
new("zh-CN"),
new("en-US")
};
});
支持资源文件
如果你希望将配置文件嵌入到dll文件中, 不希望被看到修改, 那么你需要将资源json文件的生成操作改为嵌入的资源, 并修改I18N注册代码为:
builder.Services.AddI18nByEmbedded();
嵌套配置
相信了解前端开发的小伙伴也见到过嵌套的资源配置, 那对于Masa提供的多语言方案而言, 我们也支持这种格式的配置, 例如:
{
"Home":"首页",
"User":{
"Name":"名称"
}
}
我们希望拿到User节点下的Name属性的值, 则可以通过:
var result = I18N.T("User.Name");//其中key的值不区分大小写
当然除此之外, 我们也可以将不同资源的文件分开存放到不同的json文件, 然后通过添加多个资源目录的文件, 最终实现, 但在使用时稍微有区别:
app.Map("/test2", (string key, II18n<CustomResource> i18n) => i18n.T(key));//通过DI获取到自定义资源下Key对应内容
如何对接远程资源配置
多语言的远程资源配置目前仅支持Dcc, 我们可以这样做:
- 注册
MasaConfiguration并使用Dcc, 修改Program.cs
builder.Services.AddMasaConfiguration(configurationBuilder =>
{
// configurationBuilder.UseDcc();//正确配置好Dcc配置后开启
});
- 配置Dcc配置信息, 修改
appsettings.json
{
"DccOptions": {
"ManageServiceAddress": "{Replace-Your-DccManagerServiceHost}",
"RedisOptions": {
"Servers": [
{
"Host": "{Replace-Your-DccUseRedisHost}",
"Port": 6379
}
],
"DefaultDatabase": 0,
"Password": ""
}
}
}
对MasaConfiguration有疑问点这里
- 注册I18n
builder.Services.AddI18n(
Path.Combine("Resources", "I18n"),
"supportedCultures.json",
options => options.UseDcc());
我们仅需要在/Resources/I18n目录下存放支持语言的配置即可, 具体的语言配置将从Dcc读取 (读取Dcc语言的配置节点: 在Dcc配置下默认AppId下的"Culture.{语言}"), 例如:
如果支持语言为zh-CN、en-US, 则默认读取Dcc配置下默认AppId下Culture.zh-CN、Culture.en-Us两个配置对象的值, 我们仅需要修改它们的值即可, 并且如果对应的内容发生更改, 项目无需重启即可完成自动更新
源码解读
在MasaFramework中, 抽象了多语言的能力, 它提供了
- string this[string name]: 获取指定
name的值 (如果name不存在, 则返回name的值) - string? this[string name, bool returnKey]: 获取指定
name的值 (如果returnKey为false, 且name不存在, 则返回null) - string this[string name, params object[] arguments]: 获取指定
name的值, 并根据文化、输入参数格式化响应信息返回 (如果name不存在, 则返回name的值) - string? this[string name, bool returnKey, params object[] arguments]: 获取指定
name的值, 并根据文化、输入参数格式化响应信息返回 (如果returnKey为false, 且name不存在, 则返回null) - string T(string name): 获取指定
name的值, 如果name不存在, 则返回name的值 - string? T(string name, bool returnKey): 获取指定
name的值 (如果returnKey为false, 且name不存在, 则返回null) - string T(string name, params object[] arguments): 获取指定
name的值, 并根据文化、输入参数格式化响应信息返回 (如果name不存在, 则返回name的值) - string? T(string name, bool returnKey, params object[] arguments): 获取指定
name的值, 并根据文化、输入参数格式化响应信息返回 (如果returnKey为false, 且name不存在, 则返回null) - CultureInfo GetCultureInfo(): 获取当前线程的区域性 (被用于需要格式化响应信息的方法)
- void SetCulture(string cultureName, bool useUserOverride = true): 设置当前线程的区域性
- void SetCulture(CultureInfo culture): 设置当前线程的区域性
- CultureInfo GetUiCultureInfo(): 获取资源管理器使用的当前区域性以便在运行时查找区域性特定的资源
- void SetUiCulture(string cultureName, bool useUserOverride = true): 设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源
- void SetUiCulture(CultureInfo culture): 设置资源管理器使用的当前区域性以便在运行时查找区域性特定的资源
我们可以通过DI获取到II18n进而来使用它提供的这些能力, 当然它使用的是资源类型为DefaultResource的资源 (在服务注册时所指向的资源 services.AddI18n()), 除此之外, 我们也可以通过DI获取到II18n<DefaultResource>来使用, 也可以通过I18n(全局静态类)来使用它提供的能力, 但是如果你使用了自定义资源类型, 则只能通过DI获取II18n<{Replace-Your-ResourceType}>来使用.
除此之外, 我们还提供了支持的语言列表的能力, 它被抽象在ILanguageProvider
- IReadOnlyList GetLanguages(): 获取支持语言集合
我们可以通过DI获取ILanguageProvider来使用, 也可以通过I18n.GetLanguages()来使用
总结
当然, MasaFramework绝不仅仅只是提供了这么简单的多语言的能力, 目前全局异常、Caller也已经支持了多语言, 其他模块也在逐步完善多语言支持, 等之后框架的错误信息也将会支持多语言, 我们的开发体验也将会变得更加友好
参考
本章源码
Assignment18
https://github.com/zhenlei520/MasaFramework.Practice
开源地址
MASA.Framework:https://github.com/masastack/MASA.Framework
MASA.EShop:https://github.com/masalabs/MASA.EShop
MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor
如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们

MasaFramework -- i18n (国际化)的更多相关文章
- Django1.9开发博客(12)- i18n国际化
国际化与本地化的目的为了能为各个不同的用户以他们最熟悉的语言和格式来显示网页. Django能完美支持文本翻译.日期时间和数字的格式化.时区. 另外,Django还有两点优势: 允许开发者和模板作者指 ...
- Bootstrap-datepicker3官方文档中文翻译---I18N/国际化(原文链接 http://bootstrap-datepicker.readthedocs.io/en/latest/index.html)
I18N/国际化 这个插件支持月份和星期名以及weekStart选项的国际化.默认是英语(“en”); 其他有效的译本语言在 js/locales/ 目录中, 只需在插件后包含您想要的地区. 想要添加 ...
- i18n(国际化) 和l18n(本地化)时的地域标识代码
i18n(国际化) 和l18n(本地化)时的地域标识代码 格式如 zh-CN(语言-国家) i18n(国际化) 和l18n(本地化)时的地域标识代码 格式如 zh-CN(语言-国家) 国家说明 语言说 ...
- i18n,国际化翻译,excel与js互转
背景 公司开发新产品时,要求适配多国语言,采用i18n国际化工具,但翻译字典(js的json)还是需要前端自己写的.字典最终需要转换成excel给专业人员翻译,翻译完成后再转换成js字典文件. 如果手 ...
- 【JavaWeb】i18n 国际化
i18n 国际化 什么是 i18n 国际化(Internationalization)指的是同一个网站可以支持多种不同的语言,以方便不同国家,不同语种的用户访问. 希望相同的一个网站,不同人访问的时候 ...
- I18N 国际化
http://blog.sina.com.cn/s/blog_6c7e59770101p7w9.html 一.I18N 在 J2EE 中的应用 [转载:http://blog.csdn.net/cha ...
- Web---JSTL(Java标准标签库)-Core核心标签库、I18N国际化、函数库
前面为JSTL中的常用EL函数,后面的为具体演示实例! JSTL简介: JSTL(Java Standard Tag Library) –Java标准标签库. SUN公司制定的一套标准标签库的规范. ...
- Struts2 学习笔记17 I18N国际化
讲解一下国际化的内容,比如书有些大的网站可以一键切换语言,例如中英切换,这时候就会用到国际化.但是由于struts2大多数是用来写后台,国际化并不是十分重要,而且用国际化开发会减慢开发的速度,大家只要 ...
- Struts2之i18N国际化
对于i18n其实没有太多内容,一般的公司用不到这些内容,除非是跨国公司,但即便是跨国公司也不一定会使用i18n来进行国际化处理,所以本篇内容仅供大家了解,不做深入的探讨,希望通过本篇内容,可以帮助大家 ...
- SpringBoot系列——i18n国际化
前言 国际化是项目中不可或缺的功能,本文将实现springboot + thymeleaf的HTML页面.js代码.java代码国际化过程记录下来. 代码编写 工程结构 每个文件里面的值(按工程结构循 ...
随机推荐
- Spring bean装配流程和三级缓存
马士兵 源码方法论 不要忽略源码中的注释 先梳理脉络,再深入细节 大胆猜测.小心求证 见名知意 hold on 对源码有兴趣的都是变态 为了钱! Spring IoC Spring容器帮助管理对象,不 ...
- day09-1存储引擎
存储引擎 1.基本介绍 基本介绍 MySQL的表类型由存储引擎(Storage Engines)决定,主要包括MyISAM.innoDB.Memory等 MySQL数据表主要支持六种类型,分别是:CS ...
- MatrixOne从入门到实践02——源码编译
MatrixOne从入门到实践--源码编译 在部署MatrixOne前,我们可能会比较纠结使用哪个版本合适,MatrixOne在github上有各个版本的Releases,包含源码包和适用于Lin ...
- vue+element-ui后台管理系统模板
vue+element-ui后台管理系统模板 前端:基于vue2.0+或3.0+加上element-ui组件框架 后端:springboot+mybatis-plus写接口 通过Axios调用接口完成 ...
- java中list集合怎么判断是否为空
首先看下面代码 @RequestMapping("/getCatlist") public String getCatlist(HttpSession session,HttpSe ...
- markdown第一天学习
Markdown学习 标题: 空格+标题名字后回车 二级标题 空格+标题名字后回车 三级标题 空格+标题名字后回车 四级标题 空格+标题名字后回车 字体 粗体 hello,world!------两边 ...
- html中可以写php代码,但是文件后缀名需要是.php而不是.html。否则php程序不会被解析执行。
html中可以写php代码,但是文件后缀名需要是.php而不是.html.否则php程序不会被解析执行. <div class="goods_title"><?p ...
- Cypher 笔记
添加 // 创建节点 CREATE (n:MOVIE{name:"电影"}) // 创建节点 create (n:Test) set n.name="Test" ...
- Unity坐标系入门
一.坐标系的概念 Unity 世界坐标系采用左手坐标系,大拇指指向X轴(红色),食指指向Y轴(黄色),中指向手心方向歪曲90度表示Z轴(蓝色),同时Z轴也是物体前进方向,下图表示Unity的四种坐标系 ...
- docker使用代理(in home)
docker 使用 http http_proxy https://docs.docker.com/config/daemon/systemd/ # 代理 和 国内 镜像源 不要 同时使用,... # ...