SpringBoot国际化支持

280 阅读4分钟

前言

国际化,也叫 i18n,为啥叫这个名字呢?因为国际化英文是 internationalization ,在 i 和 n 之间有 18 个字母,所以叫 i18n。是指让产品或是程序在无需做出改变的情况下就能够适应不同语言和地区的需要 ,同样是打招呼在中国你会说 “ 你好 ” ,在美国你会说 “ Hello ”,最常见的就是中文和英文之间的切换。

项目中的国际化我们往往需要多方面的支持,例如后端做国际化、前端页面也要做国际化,共同搭配,才能真正实现国际化的功能。

基本使用

Spring Boot 和 Spring 一脉相承,对于国际化的支持,默认是通过 AcceptHeaderLocaleResolver 解析器来完成的,这个解析器,默认是通过请求头的 Accept-Language 字段来判断当前请求所属的环境的,进而给出合适的响应。

所以在 Spring Boot 中做国际化,这一块我们可以不用配置,直接就开搞。

首先创建一个普通的 Spring Boot 项目,添加 web 依赖即可。项目创建成功后,默认的国际化配置文件放在 resources 目录下,在 resources 目录下右键Resource Bundle

image.png name默认为messages,Locale语言环境,这边我们依次添加en_US(英文)、zh_CN(中文)

image.png 最后会在resource下生成这样层级的目录文件

image.png 文件创建好之后,第一个默认的我们可以先空着,另外两个个分别填入以下内容:

messages_en_US.properties

user.name=jarvis

messages_zh_CN.properties

user.name=贾维斯

配置完成后,我们就可以直接开始使用了。在需要使用值的地方,直接注入 MessageSource 实例即可。在 Spring 中需要配置的 MessageSource 现在不用配置了,SpringBoot会通过org.springframework.boot.autoconfigure.context.MessageSourceAutoConfiguration自动帮我们配置一个 MessageSource 实例。

创建一个 HelloController ,内容如下:

@RestController
public class HelloController {
    @Autowired
    MessageSource messageSource;

    @GetMapping("/hello")
    public String hello() {
        return messageSource.getMessage("user.name", null, LocaleContextHolder.getLocale());
    }
}

在 HelloController 中我们可以直接注入 MessageSource 实例,然后调用该实例中的 getMessage 方法去获取变量的值,第一个参数是要获取变量的 key,第二个参数是如果 value 中有占位符,可以从这里传递参数进去,第三个参数传递一个 Locale 实例即可,这相当于当前的语言环境。

接下来我们就可以直接去调用这个接口了。

默认情况下,在接口调用时,通过请求头的 Accept-Language 来配置当前的环境,我这里通过 ApiFox 来进行测试,结果如下:

英文 image.png 中文 image.png

可以看到,在请求头中设置了 Accept-Language 为 zh-CN,所以拿到的就是简体中文;如果我设置了 en-US,就会拿到英文

自定义参数方式

有的小伙伴觉得切换参数放在请求头里边好像不太方便,那么也可以自定义解析方式。例如参数可以当成普通参数放在地址栏上,通过如下配置可以实现我们的需求。

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //这个拦截器会拦截请求中 key 为 lang 的参数(不配置的话是 locale),这个参数则指定了当前的环境信息。
        LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
        interceptor.setParamName("lang");
        registry.addInterceptor(interceptor);
    }

    /**
     * 这个实例会替换掉默认的 AcceptHeaderLocaleResolver,
     * 不同于 AcceptHeaderLocaleResolver 通过请求头来判断当前的环境信息,
     * SessionLocaleResolver 将客户端的 Locale 保存到 HttpSession 对象中,
     * 并且可以进行修改(这意味着当前环境信息,前端给浏览器发送一次即可记住,
     * 只要 session 有效,浏览器就不必再次告诉服务端当前的环境信息)。
     *
     */
    @Bean
    LocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        return localeResolver;
    }
}

好了,配置完成后,启动项目,访问方式如下:

image.png

image.png 我们通过在请求中添加 lang 来指定当前环境信息。这个指定只需要一次即可,也就是说,在 session 不变的情况下,下次请求可以不必带上 lang 参数,服务端已经知道当前的环境信息了。

自定义文件位置

默认情况下,我们的配置文件放在 resources 目录下,如果大家想自定义,也是可以的,例如定义在 resources/i18n 目录下:

image.png 但是这种定义方式系统就不知道去哪里加载配置文件了,此时还需要 application.properties 中进行额外配置(注意这是一个相对路径):

spring.messages.basename=i18n/messages

工具类封装

@Component
public class MessageUtils {

    private static MessageSource messageSource;

    public MessageUtils(MessageSource messageSource) {
        MessageUtils.messageSource = messageSource;
    }

    /**
     * 获取单个国际化翻译值
     */
    public static String get(String msgKey) {
        try {
            return messageSource.getMessage(msgKey, null, LocaleContextHolder.getLocale());
        } catch (Exception e) {
            return msgKey;
        }
    }
}