Spring i18n国际化配置

Spring i18n国际化配置

Scroll Down

源码地址:spring-boot-i18n

项目采用maven方式构建,其目录结构如下:

pom

因为我采用的是spring-boot项目

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

一、后台国际化

1、配置国际化参数

默认解析器:LocaleResolver 用于设置当前会话的默认的国际化语言。

默认拦截器:LocaleChangeInterceptor 指定切换国际化语言的参数名。例如 ?lang=zh_CN 表示读取国际化文件messages_zh_CN.properties

/**
 * 国际化配置
 *
 * @author bing_huang
 */
@Configuration
public class LocaleConfiguration implements WebMvcConfigurer {
 /**
     * 默认解析器 其中locale表示默认语言
     */
    @Bean
    public LocaleResolver localeResolver() {
        //session级
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        //默认语言
        localeResolver.setDefaultLocale(Locale.US);
        return localeResolver;
    }
    /**
     * 拦截lang 参数
     */
    @Bean
    public LocaleChangeInterceptor localeChangeInterceptor() {
        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
        lci.setParamName("lang");
        return lci;
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(localeChangeInterceptor());
    }
}

2、添加国际化文件

首先在配置文件 application.yml 填写国际化文件的相对路径,表示读取classpath:/static/i18n/messages_language_country.properties 。例如:

spring:
  messages:
    # 相对路径i18n文件下
    basename: i18n/message

然后在 classpath:/static/i18n 目录中添加如下国际化文件:

默认文件:messages.properties

##这里填写默认翻译,内容可以留空,但文件必须存在。
hello=你好

中文简体:messages_zh_CN.properties

hello=你好

中文繁体:messages_zh_TW.properties

hello=你號

美式英语:messages_en_US.properties

hello=hello

3、代码国际化

@RestController
@RequiredArgsConstructor
public class HelloController {
    private final MessageSource source;

    @GetMapping("/hello")
    private Object hello(HttpServletRequest request) {
        //参数1 为message.properties =左边的
        //参数2 为message.properties的占位符
        //参数3 为当前环境下的locale
        return source.getMessage("hello", null, LocaleContextHolder.getLocale());
    }
}

4.访问

  1. Get 请求
    http://localhost:8080/hello?lang=zh-TW
    http://localhost:8080/hello?lang=zh-CN
    http://localhost:8080/hello?lang=en-US
    这里主要是 LocaleChangeInterceptor 起到了作用

解析器 LocaleResolver

  1. org.springframework.web.servlet.i18n.CookieLocaleResolver cookie解析
  2. org.springframework.web.servlet.i18n.SessionLocaleResolver session解析
  3. org.springframework.web.servlet.i18n.FixedLocaleResolver 固定解析
  4. org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver header解析

cookie解析器

  1. configuration

    /**
     * 默认解析器,cookie
     */
     public CookieLocaleResolver localeResolver() {
         CookieLocaleResolver localeResolver = new CookieLocaleResolver();
         //默认语言
         localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
         //解析器cookie名称
         localeResolver.setCookieName("cookie-lang");
         localeResolver.setCookieMaxAge(-1);
         return localeResolver;
     }
    
  2. test

    @Test
    public void cookieTest() throws Exception {
        Cookie cookie = new Cookie("cookie-lang", "zh-TW");
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/hello").cookie(cookie)).andReturn();
        String resultContent = result.getResponse().getContentAsString();
        log.info(resultContent);
    }
    

session解析器

  1. configuration

    @Bean
    public SessionLocaleResolver localeResolver() {
        SessionLocaleResolver localeResolver = new SessionLocaleResolver();
        localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        localeResolver.setLocaleAttributeName("session-lang");
        return localeResolver;
    }
    
  2. test

    @Test
    public void sessionTest() throws Exception {
        MockHttpSession session = new MockHttpSession();
        session.setAttribute("session-lang", Locale.forLanguageTag("en-US"));
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/hello").session(session)).andReturn();
        String resultContent = result.getResponse().getContentAsString();
        log.info(resultContent);
    }
    

header解析器

注意1: 这里采取了自定义LocaleResolver: AcceptHeaderResolver,因为在测试时发现原有的AcceptHeaderLocaleResolver并未生效

注意2: 每一次在创建localeResolver()方法时名称必须是 localeResolver() 除非自定义了 @Bean(localeResolver) ,原因请看: WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#localeResolver()

注意3: 如果采用header方式默认是不支持时区,以及参数 LocaleChangeInterceptor 的拦截

  1. 自定义resolver
    /**
     * 主要解决request local为空
     *
     * @author bing_huang
     */
    public class AcceptHeaderResolver extends AcceptHeaderLocaleResolver {
    
    
        @Override
        public Locale resolveLocale(HttpServletRequest request) {
            if (StringUtils.isEmpty(request.getHeader("Accept-Language"))) {
                return Locale.getDefault();
            }
            List<Locale.LanguageRange> list = Locale.LanguageRange.parse(request.getHeader("Accept-Language"));
            Locale locale = Locale.lookup(list, super.getSupportedLocales());
            return locale;
        }
    
        @Override
        public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
    
        }
    }
    

请注意: super.getSupportedLocales() 如果没有设置默认为0,

  1. configuration

    /**
     * 请求头设置Accept-Language,注意方法名
     * <pre>
     *     1.AcceptHeader与其他不兼容,如果使用acceptHeader则其余的无法使用(request Params亦是如此)
     *     2. AcceptHeader的请求则是Accept-Language:zh-CN
     *     3. 为何扩展原有AcceptHeaderLocaleResolver的:因为原有的未生效{@link AcceptHeaderLocaleResolver#findSupportedLocale(HttpServletRequest, List)}下HttpServletRequest#getLocales为空
     *     4. 推荐使用header作为国际化,但是存在时区等问题,具体可以看{@link org.springframework.web.servlet.i18n.CookieLocaleResolver}等源码
     * </pre>
     *
     * @see AcceptHeaderLocaleResolver#resolveLocale
     * @see WebMvcAutoConfiguration.WebMvcAutoConfigurationAdapter#localeResolver()
     */
    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderResolver localeResolver = new AcceptHeaderResolver();
        localeResolver.setSupportedLocales(Arrays.asList(Locale.SIMPLIFIED_CHINESE, Locale.TRADITIONAL_CHINESE, Locale.US));
        localeResolver.setDefaultLocale(Locale.SIMPLIFIED_CHINESE);
        return localeResolver;
    }
    
  2. test

    @Test
    public void headerTest() throws Exception {
        HttpHeaders headers = new HttpHeaders();
        headers.add("Accept-Language", "zh-TW");
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/hello").headers(headers)).andReturn();
        String resultContent = result.getResponse().getContentAsString();
        log.info(resultContent);
    }