概念

作为一个普通开发者, 我们负责的项目的使用群体大多数是本国的人民, 但不可避免的也有一些做外贸的业务或者给外企做的项目, 这个时候就要求我们的项目有服务全球客户的能力, 而一个支持国际化能力的框架会让我们项目的体验变得更好.

关于本地化我们听到最多的是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%的本地化广告在点击率、转换率上超过未经过本地化的广告, 这些数字都说明了人们对自己母语显示的内容更加感兴趣, 通过本地化可以让你更精准的打动客户, 帮你迅速的进入市场, 但本地化不等于直接翻译, 本地化是基于对当地市场情况和文化精心策划的, 在习惯、习俗、日期和货币格式上是不相同的, 本地化的产品能节约沟通成本, 更容易被理解和接受.

举个通俗的例子: 相比找一个不认识的陌生人买东西, 我们更喜欢去找那个知根知底的本地人买东西, 这无关产品的质量, 只是熟悉的人更容易获得我们的认同感

虽然本地化包括很多模块, 但在此我们只考虑产品的本地化, 下面我们就说一下如何做使得自己的产品可以支持本地化

使用

  1. 新建ASP.NET Core 空项目Assignment.I18nDemo,并安装Masa.Contrib.Globalization.I18n.AspNetCore
dotnet add package Masa.Contrib.Globalization.I18n.AspNetCore --version 0.7.0-preview.16
  1. 注册I18n, 并修改Program.cs
builder.Services.AddI18n();
  1. 使用I18N
app.UseI18n();//启用本地化中间件
  1. 添加多语言资源文件, 文件夹结构如下:
- 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}"
}
]
  1. 使用I18n
app.Map("/test", (string key) => I18n.T(key));
  1. 测试多语言, 在浏览器访问"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, 我们可以这样做:

  1. 注册MasaConfiguration并使用Dcc, 修改Program.cs
builder.Services.AddMasaConfiguration(configurationBuilder =>
{
// configurationBuilder.UseDcc();//正确配置好Dcc配置后开启
});
  1. 配置Dcc配置信息, 修改appsettings.json
{
"DccOptions": {
"ManageServiceAddress": "{Replace-Your-DccManagerServiceHost}",
"RedisOptions": {
"Servers": [
{
"Host": "{Replace-Your-DccUseRedisHost}",
"Port": 6379
}
],
"DefaultDatabase": 0,
"Password": ""
}
}
}

对MasaConfiguration有疑问点这里

  1. 注册I18n
builder.Services.AddI18n(
Path.Combine("Resources", "I18n"),
"supportedCultures.json",
options => options.UseDcc());

我们仅需要在/Resources/I18n目录下存放支持语言的配置即可, 具体的语言配置将从Dcc读取 (读取Dcc语言的配置节点: 在Dcc配置下默认AppId下的"Culture.{语言}"), 例如:

如果支持语言为zh-CNen-US, 则默认读取Dcc配置下默认AppId下Culture.zh-CNCulture.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 (国际化)的更多相关文章

  1. Django1.9开发博客(12)- i18n国际化

    国际化与本地化的目的为了能为各个不同的用户以他们最熟悉的语言和格式来显示网页. Django能完美支持文本翻译.日期时间和数字的格式化.时区. 另外,Django还有两点优势: 允许开发者和模板作者指 ...

  2. Bootstrap-datepicker3官方文档中文翻译---I18N/国际化(原文链接 http://bootstrap-datepicker.readthedocs.io/en/latest/index.html)

    I18N/国际化 这个插件支持月份和星期名以及weekStart选项的国际化.默认是英语(“en”); 其他有效的译本语言在 js/locales/ 目录中, 只需在插件后包含您想要的地区. 想要添加 ...

  3. i18n(国际化) 和l18n(本地化)时的地域标识代码

    i18n(国际化) 和l18n(本地化)时的地域标识代码 格式如 zh-CN(语言-国家) i18n(国际化) 和l18n(本地化)时的地域标识代码 格式如 zh-CN(语言-国家) 国家说明 语言说 ...

  4. i18n,国际化翻译,excel与js互转

    背景 公司开发新产品时,要求适配多国语言,采用i18n国际化工具,但翻译字典(js的json)还是需要前端自己写的.字典最终需要转换成excel给专业人员翻译,翻译完成后再转换成js字典文件. 如果手 ...

  5. 【JavaWeb】i18n 国际化

    i18n 国际化 什么是 i18n 国际化(Internationalization)指的是同一个网站可以支持多种不同的语言,以方便不同国家,不同语种的用户访问. 希望相同的一个网站,不同人访问的时候 ...

  6. I18N 国际化

    http://blog.sina.com.cn/s/blog_6c7e59770101p7w9.html 一.I18N 在 J2EE 中的应用 [转载:http://blog.csdn.net/cha ...

  7. Web---JSTL(Java标准标签库)-Core核心标签库、I18N国际化、函数库

    前面为JSTL中的常用EL函数,后面的为具体演示实例! JSTL简介: JSTL(Java Standard Tag Library) –Java标准标签库. SUN公司制定的一套标准标签库的规范. ...

  8. Struts2 学习笔记17 I18N国际化

    讲解一下国际化的内容,比如书有些大的网站可以一键切换语言,例如中英切换,这时候就会用到国际化.但是由于struts2大多数是用来写后台,国际化并不是十分重要,而且用国际化开发会减慢开发的速度,大家只要 ...

  9. Struts2之i18N国际化

    对于i18n其实没有太多内容,一般的公司用不到这些内容,除非是跨国公司,但即便是跨国公司也不一定会使用i18n来进行国际化处理,所以本篇内容仅供大家了解,不做深入的探讨,希望通过本篇内容,可以帮助大家 ...

  10. SpringBoot系列——i18n国际化

    前言 国际化是项目中不可或缺的功能,本文将实现springboot + thymeleaf的HTML页面.js代码.java代码国际化过程记录下来. 代码编写 工程结构 每个文件里面的值(按工程结构循 ...

随机推荐

  1. 分布式存储系统之Ceph集群RBD基础使用

    前文我们了解了Ceph集群cephx认证和授权相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/16748149.html:今天我们来聊一聊ceph集群的 ...

  2. jsp页面中怎么利用a标签的href进行传递参数以及需要注意的地方

    jsp页面中: <a href="${pageContext.request.contextPath }/infoController/getProductInfo?productId ...

  3. 测试杂谈——一条SQL引发的思考(二)

    在前段时间,曾写过一篇关于SQL问题的文章,测试杂谈--一条SQL引发的思考(一). 今天这篇,算是个问题记录吧,问题并不复杂,但对于测试同学而言,确实是个需要关注的点. 问题分析 最近在日常工作中, ...

  4. tListener监听器

    1.概念 监听器:专门用于对其他对象身上发生的事件或状态改变进行监听和相应处理的对象,当被监视的对象发生情况时,立即采取相应的行动. Servlet监听器:Servlet规范中定义的一种特殊类,它用于 ...

  5. 同一台电脑安装两个不同版本的mysql。简单暴力有效

    1.先找到mysql的安装地址.找到my.ini 2.修改端口号(mysql默认端口是3306)我这里修改为3307 3.打开服务.找到刚刚修改的mysql版本 4.重新启动该服务(我已经安装了mys ...

  6. MasaFramework -- 缓存入门与规则配置

    概念 什么是缓存,在项目中,为了提高数据的读取速度,我们会对不经常变更但访问频繁的数据做缓存处理,我们常用的缓存有: 本地缓存 内存缓存:IMemoryCache 分布式缓存 Redis: Stack ...

  7. Cenots7 离线安装部署PostgreSQL

    1 PostgreSQL源码包下载并复制 1.1 PostgreSQL源码包下载: 访问PostgreSQL官网 选择所需版本进行下载,本次下载安装版本为v14.5 1.2 复制源码包至服务器 使用S ...

  8. 【JavaSE】面向对象三大特征——封装、继承、多态

    前言:本文主要介绍思想 封装 封装这一概念并不仅存在与面向对象中,甚至说封装这一概念不仅限于编程中,其实生活中的封装无处不在.比如 需求:你到银行取钱 参数:你只需要提供银行卡和密码 返回值:柜员会将 ...

  9. 事件循环Event Loop

    在 事件循环 期间的某个时刻,运行时会从最先进入队列的消息开始处理队列中的消息.被处理的消息会被移出队列,并作为输入参数来调用与之关联的函数.正如前面所提到的,调用一个函数总是会为其创造一个新的栈帧. ...

  10. Nginx实用配置-2

    Nginx配置-2 1.升级Openssl [root@rocky8 ~]# nginx -V #查看现在nginx的OpenSSL版本和编译情况 nginx version: nginx/1.22. ...