掘金 后端 ( ) • 2024-04-09 21:30

@[TOC]

一、国际化

1、概述

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

2、Spring国际化

Spring国际化详解,Spring国家化实例及源码详解

二、springboot简单使用国际化

1、定义MessageSource

/**
 * 国际化相关
 * @return
 */
@Bean
public MessageSource messageSource() {
    ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    messageSource.setBasename("messages/message");
    messageSource.setDefaultEncoding("UTF-8");
    return messageSource;
}

2、定义message配置文件

在这里插入图片描述

# message_en.properties
test=meiguo
test2=meiguo{0}

# message_zh.properties
test=中国

3、测试

@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    String message = applicationContext.getMessage("test", null, new Locale("zh"));
    System.out.println(message); // 中国

    String message2 = applicationContext.getMessage("test", null, new Locale("en"));
    System.out.println(message2); // meiguo

	String message3 = applicationContext.getMessage("test2", new String[]{"content"}, new Locale("en"));
    System.out.println(message3); // meiguocontent
}

我们发现,按照不同地区,根据配置文件获取到了不同的配置。

三、根据请求的地区获取信息

1、定义message配置文件

在这里插入图片描述

# message_en_US.properties
Success={0}success
Test=myTest

# message_zh_CN.properties
Success={0}成message功
Test=我的test内容

2、定义配置类

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;

@Configuration
public class I18nConfig {

    /**
     * 国际化相关
     */
    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages/message");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
}

3、基础模板工具

import org.springframework.context.NoSuchMessageException;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;
import org.springframework.web.servlet.support.RequestContextUtils;

import javax.servlet.http.HttpServletRequest;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

public interface I18nTemplateBase {


    String defaultMessage();

    String name();


    /**
     * 解析国际化模板
     */
    default String resolve(HttpServletRequest request, Object... args) {
        // 先解析参数
        List<Object> argResolveList = new ArrayList<>();
        if (args != null) {
            for (Object arg : args) {
                if (arg instanceof I18nTemplateBase) {
                    I18nTemplateBase i18nTemplateBase = (I18nTemplateBase) arg;
                    try {
                        argResolveList.add(resolveTemplate(request, i18nTemplateBase.name()));
                    } catch (NoSuchMessageException e) {
                        argResolveList.add(i18nTemplateBase.defaultMessage());
                    }
                }
            }
        }


        // 再解析最终的
        String resolveResult;
        try {
            resolveResult = resolveTemplate(request, name(), argResolveList.toArray());
        } catch (NoSuchMessageException e) {
            // 拿不到模板用默认模板
            resolveResult = MessageFormat.format(defaultMessage(), args);
        }
        return resolveResult;

    }


    /**
     * 根据key解析国际化模板
     */
    default String resolveTemplate(HttpServletRequest request, String code, Object... args) {
        Locale locale = RequestContextUtils.getLocale(request);
        WebApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
        if (context != null) {
            return context.getMessage(String.valueOf(code), args, locale);
        } else {
            throw new NoSuchMessageException("WebApplicationContext not available");
        }
    }
}

4、消息模板定义枚举


/**
 * 标准国际化消息模板
 */
public enum I18nTemplate implements I18nTemplateBase {

    Success("{0}成功"),
    Error("{0}失败"),

    Data("{0}"),

    // TODO - 定义更多消息模板
    Test("测试结果"),
    ;

    private final String defaultMessage;

    I18nTemplate(String defaultMessage) {
        this.defaultMessage = defaultMessage;
    }

    public String defaultMessage() {
        return defaultMessage;
    }

}

5、测试一下

@GetMapping("/test1")
public String test1(HttpServletRequest request) {
    // 模板定制 + 参数定制
    String resolve1 = I18nTemplate.Success.resolve(request, I18nTemplate.Test);
    System.out.println(resolve1);

    // 模板定制 + 参数手输
    String resolve2 = I18nTemplate.Error.resolve(request, "手写的参数");
    System.out.println(resolve2);

    // 模板参数都手输
    String resolve3 = I18nTemplate.Data.resolve(request, "手写的参数");
    System.out.println(resolve3);
    return "success";
}
请求头:Accept-Language=en-US

结果:
myTestsuccess
手写的参数失败
手写的参数
请求头:Accept-Language=zh-CN

结果:
我的test内容成message功
手写的参数失败
手写的参数

可以实现模板消息、默认消息等。

6、总结

我们可以通过Spring的国际化,将每一个国家的语言模板都定义在配置文件中,这样就可以动态的解决数据返回的语言问题了。

真正生产环境还会将消息再进一步封装,配合httpcode码、返回的数据、请求成功状态、消息等等统一进行封装返回。此处就不进行详细分享了。