惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
V2EX
C
Check Point Blog
博客园_首页
B
Blog
D
Docker
U
Unit 42
量子位
I
InfoQ
有赞技术团队
有赞技术团队
Martin Fowler
Martin Fowler
GbyAI
GbyAI
L
LangChain Blog
云风的 BLOG
云风的 BLOG
博客园 - Franky
美团技术团队
T
The Blog of Author Tim Ferriss
阮一峰的网络日志
阮一峰的网络日志
月光博客
月光博客
Vercel News
Vercel News
Recent Announcements
Recent Announcements
雷峰网
雷峰网
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Google DeepMind News
Google DeepMind News

Java技术经验分享

生产故障处理SOP分享 | Java技术经验分享 系统稳定性建设实践总结【转载】 | Java技术经验分享 valine访问leancloud国际版异常,评论失效修复 | Java技术经验分享 匆匆忙忙的2021 | Java技术经验分享 聊一下换工作 | Java技术经验分享 IoT系列(2):WIFI设备常见配网方案介绍 | Java技术经验分享 IoT系列(1):什么是物联网 | Java技术经验分享 Java8特性2 - StreamApi | Java技术经验分享 Java8特性1 - lambda表达式&函数式接口 | Java技术经验分享 设计模式(5)-适配器模式 | Java技术经验分享 设计模式(4)-建造者模式 | Java技术经验分享 设计模式(3)-原型模式与浅拷贝和深拷贝 | Java技术经验分享 设计模式(2)-工厂模式图文介绍 | Java技术经验分享 设计模式(1)-带你了解3类8种单例模式 | Java技术经验分享 Java时间处理5---Java8中时区相关类库介绍 | Java技术经验分享 Java时间处理4---Java8中LocalDate、LocalTime、LocalDateTime介绍 | Java技术经验分享 Java时间处理3---Java8中Instant、Duration、Period、Clock介绍 | Java技术经验分享 一些有意思的问答 | Java技术经验分享 Nacos系列博客说明 | Java技术经验分享 菜鸡程序员的2019年度总结 | Java技术经验分享 Java中“附近的人”实现方案讨论及代码实现 | Java技术经验分享 Java时间处理2----时区TimeZone类方法探究(Java8以前) | Java技术经验分享 Java时间处理1----Date和Calendar方法探究(Java8以前) | Java技术经验分享 FastJson中JSONString、JavaBean、JSONObject、JSONArray的转换关系及API示例 | Java技术经验分享 2019.11软考软件设计师归来心得体会及复习备考指南 | Java技术经验分享 你还没用过“约定式提交”吗?那你赶紧来补补知识吧 | Java技术经验分享 教你如何看懂UML中的类图及类图中的关系 | Java技术经验分享 设计模式总览 | Java技术经验分享 萌新入门Github请看这里,学不会远程教 | Java技术经验分享 Hexo的工作原理探究 | Java技术经验分享
SpringBoot项目中实现国际化 | Java技术经验分享
文章作者: LarsCheng · 2019-04-01 · via Java技术经验分享

前言

什么是国际化呢?国际惯例,来时来一段官方介绍:

国际化(internationalization)是设计和制造容易适应不同区域要求的产品的一种方式。它要求从产品中抽离所有地域语言,国家/地区和文化相关的元素。换言之,应用程序的功能和代码设计考虑在不同地区运行的需要,其代码简化了不同本地版本的生产。开发这样的程序的过程,就称为国际化。

在我们实际开发中,一个web应用可能要在多个地区使用,面对不同地区的不同语言,为了适应不同的用户,我们可以尝试在前端页面实现多语言的支持,那么同样对于后端返回的一些提示信息,异常信息等,我们后端也可以根据不同的语言环境来进行国际化处理,返回相应的信息。

开发工具

IDEA、Maven、SpringBoot2.0.5、Jdk1.8、google浏览器

SpringBoot中的国际化

原理
想要使应用支持国际化,首先需要知道用户的语言环境,即用户想要看到的语言,我们设想在用户每次请求时告诉服务器自己的语言环境,服务器收到请求后,根据不同的语言环境返回不同的信息来实现国际化。在spring应用中,用户的语言环境是通过区域解析器来识别的,而区域解析器有分为好几种(后面详细说),在我们不做配置修改时,spring使用AcceptHeaderLocaleResolver作为默认的区域解析器,它是根据HTTP请求 Header中的Accept-language的值来解析,当然区域解析器我们也可以自定义配置。

springboot默认就支持国际化。我们只需要只需要作相应的配置即可。

1.首先你需要一个springboot项目。IDEA中分分钟创建好一个项目。

2.在resources下定义国际化配置文件,注意名称必须以messages开始。(在springboot中,当我们不修改配置时默认去解析名称以message开始的properties文件

  • messages.properties (默认环境,无法确定语言环境时,解析该文件中的相应信息

  • messages_zh_CN.properties(中文语言环境时,解析该文件中的相应信息

  • messages_en_US.properties(英文语言环境时,解析该文件中的相应信息

在三个配置文件中分别以Key = Value形式存储如下三条信息,如下:

1
welcome = 这是一个支持国际化的项目。
1
welcome = 这是一个支持国际化的项目。
1
welcome = This is a project supporting internationalization.

3.创建thymeleaf页面
加入thymeleaf依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

resources/templates目录下创建hello.html页面:
尝试在不同的语言环境下,通过#{welcome}获取信息

1
2
3
4
5
6
7
8
9
10
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8"/>
<title>demo</title>
</head>
<body>
<p><label th:text="#{welcome}"></label></p>
</body>
</html>

4.创建访问页面的controller
注意这里controller的注解时@Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;








@Controller
public class BaseController {
@RequestMapping("/hi")
public String hello() {
return "/hello";
}
}

测试国际化效果

这里使用google浏览器进行测试,测试之前需要安装插件Language Switcher
Language Switcher : 可以改变当前请求的语言环境(根据自己的选择)

启动我们的springboot项目,google浏览器访问 http://127.0.0.1:8080/hi ,可以看到如下页面:

通过Language Switcher切换语言环境为English - United States,重新访问 http://127.0.0.1:8080/hi ,可以看到如下页面:

ok,大功告成,到此一个简单的国际化项目就完成了。

扩展国际化

通过上面的小栗子,我们可以看到一个简单的国际化使用,但是在开发中中还需要我们进行一定的配置,来满足我们不同情况下的使用。

在返回结果中获取国际化信息

很多时候,后端接收到一个请求后,需要返回一个提示信息,而此时我们可以使这个返回信息支持国际化

这里就用到了org.springframework.context.MessageSource接口,MessageSource提供了三个方法

@Nullable//参数字段可为空
String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4);

String getMessage(String var1, @Nullable Object[] var2, Locale var3) throws NoSuchMessageException;

String getMessage(MessageSourceResolvable var1, Locale var2) throws NoSuchMessageException;
  • String getMessage(String var1, @Nullable Object[] var2, @Nullable String var3, Locale var4):用来从MessageSource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。var2中的参数将使用标准类库中的MessageFormat来作消息中替换值。

  • String getMessage(String code, Object[] args, Locale loc):本质上和上一个方法相同,其区别在:没有指定默认值,如果没找到消息,会抛出一个NoSuchMessageException异常。

  • String getMessage(MessageSourceResolvable resolvable, Locale locale):上面方法中所使用的属性都封装到一个MessageSourceResolvable实现中,而本方法可以指定MessageSourceResolvable实现。

下面我们实践一下:

1.创建一个以json返回格式的controller,注入MessageSource,注意controller的注解为@RestController

在这里首先我们需要获取到当前请求的Locale,有两种方法:

1
2
Locale locale = LocaleContextHolder.getLocale();
Locale locale = RequestContextUtils.getLocale(request);

两种方式根据情况选择使用,下面是controller代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.example.i18n.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;







@RestController
public class JsonController {

@Autowired
private MessageSource messageSource;

@RequestMapping("/ha")
public String ha() {
return messageSource.getMessage("welcome", null, LocaleContextHolder.getLocale());
}
}

2.启动项目访问 http://127.0.0.1:8080/ha ,可以看到相应语言环境的返回信息

通过Language Switcher切换语言环境为English - United States,重新访问http://127.0.0.1:8080/ha,可以看到如下页面:

支持占位符国际化信息返回

我们经常会遇到这样一个场景,登录账号需要验证码,填写完手机号获取验证码后会收到一条类似于尊敬的用户13099999999您好,您的验证码是6666,这种信息,其实就是一个模板,通过改变参数,重复使用。我们通过国际化资源文件中的占位符,配合MessageSource提供的api也可以实现。
资源文件中加入如下属性:

messages.properties,messages_zh_CN.properties

1
hello=你好:{0} , 你的验证码为 :{1}

messages_en_US.properties

1
hello=Hello: {0}, your verification code is: {1}

我们在JsonController中,创建一个测试接口

1
2
3
4
@RequestMapping("/haha")
public String haha() {
return messageSource.getMessage("hello", new Object[]{"zhangsan","123456"}, LocaleContextHolder.getLocale());
}

启动项目直接,访问 http://127.0.0.1:8080/haha 可以看到相应语言环境的返回信息

通过Language Switcher切换语言环境为English - United States,重新访问 http://127.0.0.1:8080/haha ,可以看到如下页面:

支持国际化的枚举类

既然返回信息可以实现国际化,那我们的枚举类同样也可以实现国际化咯

创建一个枚举类EnumSuccessOrError.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40








public enum EnumSuccessOrError {
SUCCESS(0, "操作成功"),
ERROR(1, "操作失败");




private int statusCode;



private String statusMsg;

EnumSuccessOrError(int statusCode, String statusMsg) {
this.statusCode = statusCode;
this.statusMsg = statusMsg;
}




public int getStatusCode() {
return statusCode;
}




public String getStatusMsg() {
return statusMsg;
}
}

如上,刚刚创建的枚举类是不支持国际化的,我们呢需要改造他,当调用getStatusMsg方法时根据语言环境返回相应的国际化字符串。可以从如下两个点着手:

  • getStatusMsg方法改造
  • 资源文件中添加不同语言环境对应的返回值

先在三个资源文件中加入不同环境的返回值:

messages.properties,messages_zh_CN.properties

1
2
SUCCESS = 操作成功
ERROR = 操作失败

messages_en_US.properties

1
2
SUCCESS=success
ERROR=error

改造后的枚举如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public enum  EnumSuccessOrError {
SUCCESS(0, "SUCCESS"),
ERROR(1, "ERROR");




private int statusCode;



private String statusMsg;

EnumSuccessOrError(int statusCode, String statusMsg) {
this.statusCode = statusCode;
this.statusMsg = statusMsg;
}

private MessageSource messageSource;

public EnumSuccessOrError setMessageSource(MessageSource messageSource) {
this.messageSource = messageSource;
return this;
}


@Component
public static class ReportTypeServiceInjector {

@Autowired
private MessageSource messageSource;

@PostConstruct
public void postConstruct() {
for (EnumSuccessOrError rt : EnumSet.allOf(EnumSuccessOrError.class))
rt.setMessageSource(messageSource);
}
}




public int getStatusCode() {
return statusCode;
}




public String getStatusMsg() {
return messageSource.getMessage(statusMsg,null,statusMsg, LocaleContextHolder.getLocale());
}

此时我们在JsonController中,再创建一个测试接口

1
2
3
4
@RequestMapping("/enumDemo")
public String enumDemo() {
return EnumSuccessOrError.SUCCESS.getStatusMsg();
}

启动项目直接,访问 http://127.0.0.1:8080/enumDemo 可以看到相应语言环境的返回信息

通过Language Switcher切换语言环境为English - United States,重新访问 http://127.0.0.1:8080/enumDemo ,可以看到如下页面:

参考和感谢

https://blog.csdn.net/linxingliang/article/details/52350238
https://blog.csdn.net/flowingflying/article/details/76358970