关于java:干货-用JAVA实现多语言翻译组件升级

55次阅读

共计 3400 个字符,预计需要花费 9 分钟才能阅读完成。

不同畛域对国际化的定义各不相同,这里议论的是 W3C 国际化流动资料的高级工作定义。有些人应用其余术语(例如全球化)来指代同一概念。

国际化是产品、应用程序或文档内容的设计和开发,它能够为不同文化、地区或语言的指标受众轻松实现本地化。国际化(Internationalization)通常用英文写成 i18n,其中 18 是英文单词中 i 和 n 之间的字母数。[1]

本文次要基于 java,针对语言国际化进行论述。 任何一个面向全世界的软件都会面临多语言国际化的问题,对于 java web 利用,要实现国际化性能,就是在数据展现给用户之前,替换成用户可辨认的语言。

应用 spring 自带的 i18n(国际化)

这部分比较简单,在网上搜寻就能够找到教程,这里将会手动配置一次 spring i18n 国际化来介绍一下。以下是笔者应用的 spring boot 版本号。

1-1. 在 properties 或 yml 资源文件外面配置 i18n

笔者用的是 yml 文件,能够自行转换成 properties 文件格式。

basename:以逗号分隔的基名列表(实质上是一个齐全限定的类门路地位),每个基名都遵循 ResourceBundle 约定,对基于斜杠的地位提供宽松的反对。如果它不蕴含包限定符(例如“org.mypackage”),它将从类门路根目录解析。

cache-duration:加载的资源包文件缓存的持续时间。如果没有设置,捆绑包将被永恒缓存。如果没有指定持续时间后缀,将应用秒。

1-2. 在 resources 文件夹下新增 i18n 文件夹,并新建相应的国际化文件

spring 容器启动的时候,会依据配置的 basename 去对应的门路加载资源文件到 MessageSource 里,至于是怎么加载到 MessageSource 里的,在这里就不开展论述了。

文件配置如图 1- 1 所示。
留神:红色框里的就是 i18n 资源文件的配置,绿色框是 idea 主动生成的文件夹,理论并不存在,忽视就行。

图 1-1 i18n 资源文件

1-3. 在代码中应用 i18n 进行国际化

这里演示的是比较简单的手动参数替换,还有更好一些的办法,比如说在响应数据写入流的时候进行参数替换。

1-4. 测试 spring i18n

启动我的项目后,查看调用 /test/console 接口返回的数据,调用三次,别离设置 header 中的语言:默认、中文、英文。
笔者用的是 idea 的 HTTP Client,以下是申请参数:

以下是响应参数:

1-5. 剖析执行后果

1-5-1. 测试默认和测试中文的响应数据是一样的,能够确定零碎默认应用的中文环境。
1-5-2. 调用 getMessage() 办法时,不传第 2 个参数就是无参替换;否则,反之。
1-5-3. 应用有参替换时,还能够在 properties 文件里退出 date、time 等参数,spring 能够主动格式化成对应的日期和工夫。

1-6. 论断

这里只是简略的演示了 spring i18n 的性能,能够满足一些简略场景的需要,如果须要进行扩大的话,有几种思路。

1-6-1. 如果应用了 nacos 等配置核心,则须要去注册核心手动拉取 i18n 的 properties 文件内容,并加载到应用程序的内存里,也能够在本地用户文件夹寄存一份。
1-6-2. 如果须要一些正则翻译的话,则须要本人入手写正则替换的表达式。
1-6-3. 该例子展现的是在 controller 里进行替换,更好一点的形式是在 filter,甚至是在响应数据写入流的时候进行替换,比如说指定某个响应对象的某个属性的序列化类(@JsonSerialize(using = TestJsonSerializer.class)),则该字段序列化的时候,就会应用 TestJsonSerializer.class 进行序列化。在这个类外面就能够针对性地做咱们想要的替换了。

自定义 i18n

spring i18n 的性能较为好用,然而面对简单的业务需要,还不够弱小。比方,用户想增加一种语言;递归替换;布局能够自定义,用户增加布局字段时,针对该我的项目或组织的不同地区的人员,设置不同的翻译内容等等。

基于各种各样的起因,扩大 i18n 已是必须要做的事。那么怎么扩大呢?

国际化的实质就是将 key 替换成不同语言的 value,这句话中有几个关键点:key、替换、语言、value。 其中 key、语言、value 都是名词,代表着具体的数据;替换是动词,代表具体的翻译逻辑。那咱们就须要针对这几个点进行设计与实现。

2-1. 设计数据表

思路:通过一种语言和键找到对应的值。表结构设计比较简单,key、value、语言各建一个表,如图 2- 1 所示。

图 2-1 国际化表结构设计

其中每个表只展现了主键编号字段,其实还有一些字段没展现进去,比方 code、name,这些能够依据本人的格调去设计。如果是多租户的零碎,在每张表前面退出对应的租户 id,即可进行数据隔离。
2-1-1. 如果用户新增的字段须要翻译,往语言键里减少一条数据,以及往语言值里减少与语言定义雷同数量的记录即可。
2-1-2. 如果用户新增语言定义,则往语言值外面减少与语言键雷同数量的记录即可。
2-1-3. 更新、删除同理。

2-2. 数据缓存设计

在一个面向世界的利用外面,翻译的频率是很高的,而且随着工夫的流逝,翻译的数据必定会越来越多,如果每次响应数据的翻译都去查询数据库的话,那势必会造成数据库性能以及利用自身性能的节约。对于这种批改频率不算高的数据,咱们能够缓存起来,用空间换工夫。

这里打算用两级缓存的设计来适应该翻译场景,一级是 redis,二级是利用内存。

step1: 将用到的数据从数据库缓存在 redis 外面,并且生成一个更新标记放入 redis。利用获取翻译数据的时候先判断 redis 更新标记是否为空。
step2: 若为空,则代表 redis 尚未缓存翻译数据,将翻译数据从数据库拉取到内存,且推送到 redis;若不为空,则代表 redis 已缓存翻译数据,而后再比对 redis 的更新标记和利用内存的更新标记是否统一。
step3: 若不统一,则阐明翻译数据曾经扭转,须要从 redis 从新拉取一次翻译数据,缓存在利用内存中;若统一,则阐明翻译数据尚未扭转,能够间接应用利用内存中的翻译数据。
step4: 将最初拿到的翻译数据(key-value)返回给实现翻译逻辑的组件。

如图 2- 2 所示。

图 2-2 国际化两级缓存设计
代码如下所示。

2-3. 将替换逻辑嵌入 spring 的 filter 或者序列化

笔者在这里只演示简略的 key->value 替换,至于递归替换、正则替换能够自行思考加上。
A. 当一个申请进来的时候,首先须要做一些前置解决。
B. 依据申请的语言设置以后线程的语言环境。
C. 更新一次以后利用内存的语言缓存数据。
D. 当返回响应的时候,通过序列化对响应数据进行替换。
代码如下所示。

2-4. 测试自定义 i18n

启动我的项目后,查看调用 test/custom-i18n 接口返回的数据,调用三次,别离设置 header 中的语言:默认、中文、英文。
笔者用的是 idea 的 HTTP Client,以下是申请参数:

以下是返回参数:

2-5. 剖析执行后果

2-5-1. 测试默认和测试中文的响应数据是一样的,能够确定零碎默认应用的中文环境。
2-5-2. 对于应用了 @JsonSerialize(using = I18nJsonSerializer.class)注解的属性,会依据 key 主动替换成对应的值。
2-5-3. 依据 key 没找到值时,还是会应用本来的 key。

2-6. 论断

这里只是简略的演示了自定义 i18n 的性能,然而未然反对用户新增语言、自定义翻译后的值、多机部署等。如果想要反对正则替换、递归翻译也能够自行扩大。

总结

这里演示了两种 i18n 的实现计划,具体想用哪种就见仁见智了。图不便,开箱即用,那就选 spring i18n;图灵便,可扩展性强,那就选自定义 i18n。天然,必定还有很多我没想到的计划,期待交换。

后续 LigaAI 会持续分享更多技术干货的文章,欢送关注 Liga@sf~ 更多详情,请点击咱们的官方网站 LigaAI- 智能研发治理平台

[1] “Localization vs. Internationalization”.W3C
作者:rookie0peng
原文链接:https://www.jianshu.com/p/95e…
本博客所有文章除特地申明外,均采纳 CC BY-SA 4.0 协定,转载请注明出处!

正文完
 0