什么是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 创建国际化资源文件,方法如下:



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


创建工具类

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

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<T> implements 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
  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 排版

Spring Cloud微服务下如何配置I8n的更多相关文章

  1. Spring Cloud微服务下的权限架构调研

    随着微服务架构的流行,系统架构调整,项目权限系统模块开发提上日程,需要对权限架构进行设计以及技术选型.所以这段时间看了下相关的资料,做了几个对比选择. 一.架构图 初步设想的架构如下,结构很简单:eu ...

  2. spring cloud微服务下手动回滚事务

    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); 这里使用的场景是,跨服务调用接口,比如:用户信息和用户积分 ...

  3. Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结

    在Spring Cloud微服务体系中,由于限流熔断组件Hystrix开源版本不在维护,因此国内不少有类似需求的公司已经将眼光转向阿里开源的Sentinel框架.而以下要介绍的正是作者最近两个月的真实 ...

  4. Spring Cloud微服务限流之Sentinel+Apollo生产实践

    Sentinel概述 在基于Spring Cloud构建的微服务体系中,服务之间的调用链路会随着系统的演进变得越来越长,这无疑会增加了整个系统的不可靠因素.在并发流量比较高的情况下,由于网络调用之间存 ...

  5. Servlet+MyBatis项目转Spring Cloud微服务,多数据源配置修改建议

    一.项目需求 在开发过程中,由于技术的不断迭代,为了提高开发效率,需要对原有项目的架构做出相应的调整. 二.存在的问题 为了不影响项目进度,架构调整初期只是把项目做了简单的maven管理,引入spri ...

  6. Spring Cloud微服务系列文,服务调用框架Feign

    之前博文的案例中,我们是通过RestTemplate来调用服务,而Feign框架则在此基础上做了一层封装,比如,可以通过注解等方式来绑定参数,或者以声明的方式来指定请求返回类型是JSON.    这种 ...

  7. 一张图了解Spring Cloud微服务架构

    Spring Cloud作为当下主流的微服务框架,可以让我们更简单快捷地实现微服务架构.Spring Cloud并没有重复制造轮子,它只是将目前各家公司开发的比较成熟.经得起实际考验的服务框架组合起来 ...

  8. 如何优化Spring Cloud微服务注册中心架构?

    作者: 石杉的架构笔记 1.再回顾:什么是服务注册中心? 先回顾一下什么叫做服务注册中心? 顾名思义,假设你有一个分布式系统,里面包含了多个服务,部署在不同的机器上,然后这些不同机器上的服务之间要互相 ...

  9. Dubbo和Spring Cloud微服务架构比较

    Dubbo 出生于阿里系,是阿里巴巴服务化治理的核心框架,并被广泛应用于中国各互联网公司:只需要通过 Spring 配置的方式即可完成服务化,对于应用无入侵,设计的目的还是服务于自身的业务为主. 微服 ...

  10. Dubbo 和 Spring Cloud微服务架构 比较及相关差异

    你真的了解微服务架构吗?听听八年阿里架构师怎样讲述Dubbo和Spring Cloud微服务架构. 微服务架构是互联网很热门的话题,是互联网技术发展的必然结果.它提倡将单一应用程序划分成一组小的服务, ...

随机推荐

  1. 关于.net Core在华为云的鲲鹏服务器上部署的细节纪要

    由于鲲鹏使用的是ARM的cpu,,非x86的,我们公司买的是Centos,,由于需要在上面部署.net core 3.0/3.1的应用,,在按照官方的文章进行部署之后,会提示 FailFast: Co ...

  2. efcore如何优雅的实现按年分库按月分表

    efcore如何优雅的实现按年分库按月分表 介绍 本文ShardinfCore版本 本期主角: ShardingCore 一款ef-core下高性能.轻量级针对分表分库读写分离的解决方案,具有零依赖. ...

  3. NFS共享文件

    NFS共享文件 服务端 安装NFS [root@localhost www] yum -y install nfs-utils rpcbind 创建需要共享的文件夹share [root@localh ...

  4. linux下srpm源码包的使用和安装

    目录 一.关于srpm包 二.srpm包和rpm包的区别 三.不对srpm包做修改,直接安装srpm包 四.对srpm包的源码进行修改,然后安装srpm包 一.关于srpm包 ​ SRPM包是Sour ...

  5. Anagrams(字谜)

    描述 Most crossword puzzle(猜字谜) fans are used to anagrams(字谜)--groups of words with the same letters i ...

  6. windows7 + Qt(MSVC2017) + VS2019安装配置

    在windows下使用qt时调用QWebEngineView 库会报错,即使在pro文件QT += webenginewidgets也找不到, 而在MinGW和MSVC2015的路径下我并没有找到这个 ...

  7. TensorRT环境配置(VS+opencv4.5)

    1 TensorRT下载 下载与TensorRT相匹配的CUDA和cuDNN版本:https://docs.nvidia.com/deeplearning/tensorrt/archives/tens ...

  8. python 简单剖析及语法基础

    1.Python的应用领域 WEB开发 网络编程 爬虫 云计算 人工智能.数据分析 自动化运维  金融分析  科学运算  游戏开发 2.Python的发展前景 知乎上有一篇文章,问Python未来10 ...

  9. go随笔

    1)声明在函数内部,是函数的本地值,类似private 2)声明在函数外部,是对当前包可见(包内所有.go文件都可见)的全局值,类似protect 3)声明在函数外部且首字母大写是所有包可见的全局值, ...

  10. MySQL BETWEEN AND包含边界值

    select count(1) from table_a where my_date between '20230715' and '20230717'; 上面的SQL我们发现只统计了20230715 ...