Spring Cloud微服务下如何配置I8n
Published on 2024-07-15 11:43 in 暂未分类 with LvLaoTou

Spring Cloud微服务下如何配置I8n

    什么是I8n

    国际化(I18n)指的是设计和开发产品的过程,使得它们能够适应多种语言和文化环境,而不需要进行大量的代码更改。这通常涉及到创建一个基础版本的产品,然后通过配置和资源文件来添加对不同语言和地区的支持。

    这样,当产品需要在新的地理区域或语言环境中使用时,只需要添加或更新相应的资源文件,而不需要修改产品本身的代码。

    "I18n" 是 "Internationalization" 的缩写形式,之所以是 "I18n" 而不是 "Int" 或者其他缩写,是因为 "Internationalization" 这个词的第一个字母是 "I",最后一个字母是 "n",而在这两个字母之间有 18 个字符。因此,"I18n" 成为了一个流行的缩写方式,类似的还有 "K8s" 。

    Spring Boot I18n

    I8n体现在Java后端比较常见的就是错误提示,而SpringBoot本身就提供了对I8n的支持。使用也非常简单,可以参考一下官方文档

    添加国际化资源文件

    SpringBoot默认会读取classpath/resource下的messages目录里的国际化资源文件,可以通过下面这个配置更改:

    spring.messages.basename=messages
    

    咱们先通过Idea 创建国际化资源文件,方法如下:

    Untitled
    Untitled

    创建完成后在reources目录下能看到这些国际化资源文件,图中为了演示,定义了咱们开发中比较常见的登录错误提示信息。

    Untitled

    创建工具类

    创建工具类的目的是方便咱们获取国际化信息

    public class I18nUtil {
     public static String getI18nMessage(String code) {
             try {
               // SpringBoot提供有一个MessageSource的默认实现
                 MessageSource messageSource = SpringUtils.getBean("messageSource");
                 // 从SpringBoot中获取请求上下文 语言
                 Locale locale = LocaleContextHolder.getLocale();
                 // 因为我项目只有中文和英文,所以判断一下除了指定中文,否则默认使用英文  
                 // 这里对简体中文的定义,Locale[] SIMPLIFIED_CHINESE = {Locale.CHINESE, Locale.CHINA, Locale.SIMPLIFIED_CHINESE, Locale.PRC};
                 if (Arrays.stream(LocaleUtils.SIMPLIFIED_CHINESE).toList().contains(locale)) {
                     locale = Locale.SIMPLIFIED_CHINESE;
                 } else {
                    locale = Locale.US;
                 }
                return messageSource.getMessage(code, null, locale);
             } catch (Exception e) {
                 log.error("获取国际化内容异常", e);
                 // 如果获取国际化信息失败就返回原内容
                 return code;
             }
         }
    }
    

    定义接口统一返回类

    @Data
    public class RestResult<Timplements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        /** 状态标识码 */
        private String code;
    
        /** 描述信息 */
        private String message;
    
        /** 数据 */
        private T data;
        
        public String getMessage(){
         if (StrUtil.isNotEmpty(this.code)) {
           // 获取I8n
          return I18nUtil.getI18nMessage(this.code)
         }
         return this.message;
        }
        
        // 省略其他方法。。。
    }
    

    请求头添加语言编码

    curl -H "Accept-Language: zh-CN" http://example.com
    

    Spring Cloud 配置I8n

    上面是一个简单的是SpringBoot项目配置I8n的流程,但是在Spring Cloud下通常会有多个服务(SpringBoot项目)。按照我们的习惯一般有一个公共项目(common),用于封装POJO 和一些通用的工具类、常量类之类的功能,然后把这个项目打成jar包,其他业务服务都会依赖这个项目,达到功能复用的目的。通用我们也会将一些通用的错误信息(比如:用户Id不能为空)放到common项目里面,那么怎么把这些通用错误信息配置成I8n呢?

    按照上面所说,我们把common项目打成jar包供其他业务服务使用,那么当其他服务引入common依赖以后,common就和业务服务同处于一个Spring容器,这时候上面的I8n配置就无法读取到common里面的I8n配置了(上面讲过了SpringBoot默认读取的是项目classpath/resource下的配置文件)。因此我们需要自定义一个MessageSource 然后读取common下的I8n配置就可以了。

    1. 首先,我们在commonresource下创建I8n配置文件,方法和上面一样,因为和业务服务同处一个Spring容器,所以我们需要将资源名称区分开,我们暂且就叫common_messages, 如下图所示:
    Untitled
    Untitled
    1. 然后,我们配置一个自定义MessageSource Bean,并且读取我们设置的common_messages
    @Bean(name = "commonMessageSource")
    public ResourceBundleMessageSource resourceBundleMessageSource() throws IOException {
        ResourceBundleMessageSource source = new ResourceBundleMessageSource();
        source.setDefaultEncoding(StandardCharsets.UTF_8.displayName());
        source.setBasename("common_messages");
        return source;
    }
    
    1. 最后,调整I8nUtil逻辑,先读取业务服务自己的I8n,如果没有再从common I8n获取,如果还没有则返回原code
    public class I18nUtil {
     public static String getI18nMessage(String code) {
             try {
               // SpringBoot提供有一个MessageSource的默认实现
                 MessageSource messageSource = SpringUtils.getBean("messageSource");
                 // 从SpringBoot中获取请求上下文 语言
                 Locale locale = LocaleContextHolder.getLocale();
                 // 因为我项目只有中文和英文,所以判断一下除了指定中文,否则默认使用英文  
                 // 这里对简体中文的定义,Locale[] SIMPLIFIED_CHINESE = {Locale.CHINESE, Locale.CHINA, Locale.SIMPLIFIED_CHINESE, Locale.PRC};
                 if (Arrays.stream(LocaleUtils.SIMPLIFIED_CHINESE).toList().contains(locale)) {
                     locale = Locale.SIMPLIFIED_CHINESE;
                 } else {
                    locale = Locale.US;
                 }
                try{
                  // 先读取业务服务自己配置的I8n
                 return messageSource.getMessage(code, null, locale);
                }catch (NoSuchMessageException e) {
                    // 如果没有获取到,再从common里面读取I18n
                  ResourceBundleMessageSource commonMessageSource = SpringUtils.getBean("commonMessageSource");
                    return commonMessageSource.getMessage(code, null, locale);
                }
             } catch (Exception e) {
                 log.error("获取国际化内容异常", e);
                 // 如果获取国际化信息失败就返回原内容
                 return code;
             }
         }
    }
    

    本文使用 markdown.com.cn 排版

    posted @   LvLaoTou  阅读(453)  评论(0编辑  收藏  举报
    相关博文:
    阅读排行:
    · 分享4款.NET开源、免费、实用的商城系统
    · 全程不用写代码,我用AI程序员写了一个飞机大战
    · MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
    · 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
    · 上周热点回顾(2.24-3.2)
    点击右上角即可分享
    微信分享提示