1 默认properties方式

SHA1: 9ac4ad7e2e0b4a50db46326280dd1c1cfdad6b4a

1.1. yml

server:
  port: 8888

spring:
  web:
    locale: zh_CN            # 设置本地语言为zh_CN
  messages:
    basename: i18n/messages  # 在i18n文件下message开头的配置文件
    cache-duration: 10       # 配置缓存的时间,单位 s
    encoding: UTF-8          # 编码格式

1.2 自定义解析类CustomLocaleResolver

package com.taiwii.i18ndemo.config;

import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;

import java.util.Arrays;
import java.util.List;
import java.util.Locale;

/**
 * 自定义Locale header key为HEADER_LOCALE,值为zh_CN、en_US
 */
@Slf4j
@Component("localeResolver")
public class CustomLocaleResolver extends AcceptHeaderLocaleResolver {
    public final static String HEADER_LOCALE = "language";

    private static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
    private static final List SUPPORTED_LOCALES = Arrays.asList(Locale.US, Locale.SIMPLIFIED_CHINESE);


    public CustomLocaleResolver() {
        setDefaultLocale(DEFAULT_LOCALE);
        setSupportedLocales(SUPPORTED_LOCALES);
    }

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        String lang = request.getHeader(HEADER_LOCALE);
        return getLocale(lang);
    }

    private Locale getLocale(String lang) {
        if (StringUtils.isEmpty(lang)) {
            return getDefaultLocale();
        }

        try {
            String[] items = lang.split("_");
            if (items.length != 2) {
                return getDefaultLocale();
            }
            return new Locale(items[0], items[1]);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return getDefaultLocale();
        }
    }
}

1.3 WebConfig

package com.taiwii.i18ndemo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;

@Configuration
public class WebConfig implements WebMvcConfigurer {

    /**
     * 默认的拦截器,其中language表示要切换语言的参数名
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();
        localeInterceptor.setParamName(CustomLocaleResolver.HEADER_LOCALE);
        registry.addInterceptor(localeInterceptor);
    }
}

1.4 I18nHelper

package com.taiwii.i18ndemo.helper;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

import java.util.Locale;

@Slf4j
@Component
public class I18nHelper {

    private static MessageSource messageSource;

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

    public static String getMessage(Locale locale, String key, Object... args) {
        String message = null;
        try {
            message = messageSource.getMessage(key, args, locale);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            message = key;
        }
        return message;
    }

    public static String getMessage(String key, Object... args) {
        return getMessage(LocaleContextHolder.getLocale(), key, args);
    }
}

1.5 Controller

package com.taiwii.i18ndemo.controller;

import com.taiwii.i18ndemo.helper.I18nHelper;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/v1/language")
public class LanguageController {

    @GetMapping("/test")
    public String test() {
        return I18nHelper.getMessage("language.zh_cn");
    }

    @GetMapping("/test2")
    public String test2() {
        return I18nHelper.getMessage("language.zh_cn", new String[] {"参数A", "参数B"});
    }
}

1.6 资源文件

  • /resources/i18n/messages_en_US.properties
language.zh_cn=Chinese{0}, {1}
language.en_us=US
  • /resources/i18n/messages_zh_CN.properties
language.zh_cn=简体中文{0}, {1}
language.en_us=英语(美国)

1.7 测试

# 请求
curl -X GET localhost:8888/v1/language/test --header "language: zh_CN"
# 返回
简体中文

# 请求
curl -X GET localhost:8888/v1/language/test --header "language: en_US"
# 返回
Chinese

# 请求
curl -X GET localhost:8888/v1/language/test2 --header "language: zh_CN"
# 返回
简体中文参数A, 参数B

# 请求
curl -X GET localhost:8888/v1/language/test2 --header "language: en_US"
# 返回
Chinese参数A, 参数B

2 自定义MessageSource

  • brahche:i18n-自定义MessageSource
  • 代码基于第1章节
  • 测试结果与1.6相同

2.1 yml

仅保留以下内容:

server:
  port: 8080

2.1 删除资源文件夹

删除1.6创建的资源文件夹。即/resources/i18n

2.3 自定义MessageSource

为简单起见,这里采用将资源存储于内存的实现方式,其他实现方式可自行扩展。

package com.taiwii.i18ndemo.config;

import org.springframework.context.support.AbstractMessageSource;
import org.springframework.stereotype.Component;

import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

@Component("messageSource")
public class MemoryMessageSource extends AbstractMessageSource {
    private static final Map<String, String> MESSAGES = new HashMap<>();
    private static final Map<String, String> EN_CN = new HashMap<>();

    static {
        MESSAGES.put("en_US:language.zh_cn", "Chinese{0}, {1}");
        MESSAGES.put("en_US:language.en_us", "US");
        MESSAGES.put("zh_CN:language.zh_cn", "简体中文{0}, {1}");
        MESSAGES.put("zh_CN:language.en_us", "英语(美国)");
    }

    @Override
    protected MessageFormat resolveCode(String code, Locale locale) {
        String message = MESSAGES.get(String.format("%s_%s:%s", locale.getLanguage(), locale.getCountry(), code));
        return new MessageFormat(message, locale);
    }
}