Spring国际化的应用及原理详解

1. 简介

Spring国际化(Spring Internationalization,简称i18n)是Spring框架提供的一种机制,用于支持多语言的应用程序。它使得开发者能够轻松地在应用程序中实现不同语言的支持,从而满足全球化的需求。通过Spring国际化,开发者可以将应用程序的文本、标签、消息等资源抽取出来,并使用合适的语言文件进行翻译,使得应用程序能够根据用户的语言偏好自动切换语言。这种机制不仅简化了多语言支持的实现,还使得应用程序更加易于维护和扩展。在Spring国际化的实现中,主要涉及到了MessageSource、LocaleResolver等核心组件,它们共同协作,实现了语言切换的功能。通过使用Spring国际化的API,开发者可以方便地定义语言区域、加载资源文件、处理消息等操作,从而快速构建多语言的应用程序。

2. API介绍

ApplicationContext 接口扩展了一个名为 MessageSource 的接口,因此提供了国际化("i18n")功能。Spring 还提供了 HierarchicalMessageSource 接口,该接口可以分层解析消息。这些接口共同构成了 Spring 实现消息解析的基础。这些接口定义的方法包括:

  • String getMessage(String code, Object[] args, String default, Locale loc)

用于从 MessageSource 获取消息的基本方法。如果在指定的本地没有找到消息,则使用默认消息。通过标准库提供的 MessageFormat 功能,传入的任何参数都会成为替换值。

  • String getMessage(String code, Object[] args, Locale loc)

与前一种方法基本相同,但有一点不同:不能指定默认信息。如果找不到信息,就会抛出 NoSuchMessageException 异常。

  • String getMessage(MessageSourceResolvable resolvable, Locale locale)

前面方法中使用的所有属性也都封装在一个名为 MessageSourceResolvable 的类中,你可以使用该方法。

3. 国际化初始化

Spring容器ApplicationContext初始化过程中,会从容器中查找MessageSource类型的Bean。并且该Bean的名称必须是 messageSource。如果找到了这样一个 Bean,对前面方法的所有调用都会委托给消息源。如果没有找到消息源,ApplicationContext 会尝试查找包含同名Bean的父类。如果找到了,它就会使用该 bean 作为消息源。如果 ApplicationContext 无法找到任何消息源,则会实例化一个空的 DelegatingMessageSource,以便能够接受对上述方法的调用。


public abstract class AbstractApplicationContext {
  public void refresh() {
    // 初始化消息源
    initMessageSource();
  }

  /**
 * 初始化消息源。
 * 如果当前上下文中没有定义消息源,则使用父级消息源。
 */
protected void initMessageSource() {
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();
    if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
        this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
        // 使消息源知道父级消息源。
        if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource hms &&
                hms.getParentMessageSource() == null) {
            // 只有当父级消息源尚未注册时,才将父上下文设置为父级消息源。
            hms.setParentMessageSource(getInternalParentMessageSource());
        }
        if (logger.isTraceEnabled()) {
            logger.trace("使用的消息源为 [" + this.messageSource + "]");
        }
    }
    else {
        // 使用空消息源以能够接受getMessage调用。
        DelegatingMessageSource dms = new DelegatingMessageSource();
        dms.setParentMessageSource(getInternalParentMessageSource());
        this.messageSource = dms;
        beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
        if (logger.isTraceEnabled()) {
            logger.trace("没有'" + MESSAGE_SOURCE_BEAN_NAME + "' bean,使用 [" + this.messageSource + "]");
        }
    }
}
}


4. 国际化配置

基于Spring环境


@Bean(AbstractApplicationContext.MESSAGE_SOURCE_BEAN_NAME)
public MessageSource messageSource() {
  ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource() ;
  // 这里设置的是basename,message是文件的前缀(不是包)
  messageSource.addBasenames("classpath:com/pack/main/databinder/message") ;
  return messageSource ;
}

在包com/pack/main/databinder下建2个文件分别:message_zh_CN.properties和message_en_US.properties。文件内容如下:

message_zh_CN.properties

#姓名必须填写
user.name.empty=\u59D3\u540D\u5FC5\u987B\u586B\u5199

message_en_US.properties

user.name.empty=name is required

调用


try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class)) {
  // Locale.CHINA或者Locale.US
  System.out.println(context.getMessage("user.name.empty", null, Locale.CHINA)) ;
}

基于SpringBoot环境

spring:
  messages:
    basename: message

注意:你需要提供一个默认的message.properties文件


@RestController
@RequestMapping("/i18n")
public class I18NController {

  @Resource
  private ApplicationContext context ;
  
  @GetMapping("/index")
  public String index() {
    return context.getMessage("user.name.empty", null, "默认消息", LocaleContextHolder.getLocale()) ;
  }
  
}

Locale从当前线程上下文中获取。该Locale是在DispatcherServlet中初始化的。

在接口调用时,我们只需要指定Access-Language header

5. 其它配置

Spring为我们提供了一个便捷的类,可以更方便的访问消息源,项目中只需要注册如下bean:

@Bean
public MessageSourceAccessor messageSourceAccessor(MessageSource messageSource) {
  MessageSourceAccessor accessor = new MessageSourceAccessor(messageSource) ;
  return accessor ;
}

访问

@Resource
private MessageSourceAccessor accessor ;
@GetMapping("/index")
public String index() {
  return accessor.getMessage("user.name.empty") ;
}

带占位符的消息访问

在消息文件中定义如下:


#年龄的取值范围从{0}~{1}
user.age.range=\u5E74\u9F84\u7684\u53D6\u503C\u8303\u56F4\u4ECE{0}~{1}

访问

@GetMapping("/index")
public String index() {
  return accessor.getMessage("user.age.range", new Object[] {1, 100}) ;
}

注:Spring 还提供了一个ReloadableResourceBundleMessageSource 类。该变体支持相同的捆绑文件格式,但比基于 JDK 的标准 ResourceBundleMessageSource 实现更灵活。特别是,它允许从任何 Spring 资源位置(而不仅仅是从类路径)读取文件,并支持捆绑属性文件的热重载(同时在两者之间有效地缓存它们)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/294697.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Selenium-java 定位元素时切换iFrame时的方法

具体方法如下图所示,如果iFrame中嵌套多层iFrame需要逐层定位到需要的那一层iFrame,完成操作后,执行该代码:driver.switchTo() .defaultContent() ; 是返回最顶部的frame

C语言编译器(C语言编程软件)完全攻略(第二部分:与编译器相关的几个知识点)

介绍常用C语言编译器的安装、配置和使用。 二、与编译器相关的几个知识点 上节我们介绍了编译器和 IDE 的概念,大家肯定希望赶紧实践一下,用 IDE 真正地运行一段C语言代码来看看效果,这样能够更快地获得成就感。 但是,使用 IDE …

网络故障问题一般性检查排查思路

一、基本连通性检查 在网络中ping是一个十分强大的TCP/IP工具。它可以用来检测网络的连通情况和分析网络速度、也可以ping网址根据域名得到服务器IP、同时我们根据ping返回的TTL值来判断对方所使用的操作系统及数据包经过路由器数量。 ping 网址,有几种输出情况&a…

开源项目go-admin的代码生成功能使用

go-admin代码生成功能 具体如何配置go-admin项目的可以查看首次使用go-admin进行配置启动go-admin,再看下一篇文章! 找到代码生成 先进入到界面,点击开发工具,点击代码生成 代码生成操作 1. 创建表,可以使用可视…

【RK3399 PCIE调试——硬件信息资源获取】

一、1、 硬件接口 二、2、 PCB原理图 三、 官网地址: https://t.rock-chips.com/portal.php 相关资料和固件烧写可参考资料下载菜单

Linux GDB 调试

文章目录 一、Qemu二、Gdbvscode 调试 三、RootFs 一、Qemu qemu 虚拟机 Linux内核学习 Linux 内核调试 一:概述 Linux 内核调试 二:ubuntu20.04安装qemu Linux 内核调试 三:《QEMU ARM guest support》翻译 Linux 内核调试 四:…

半导体Memory的分类

文章目录 略图introRAM & ROM 略图 intro 存储器是嵌入式系统中用于存放数据和程序的模块。有些存储器是MCU内置的,有些是扩展的。 存储器嵌入式系统中常见且重要的外设模块。搞清楚存储器的分类是从事嵌入式开发工作的一项基本功。 从功能上,存储器…

利用小红书笔记详情API:为内容运营提供强大的支持

利用小红书笔记详情API,内容运营者可以获得对小红书平台上的笔记内容的深入洞察,从而为其运营工作提供强大的支持。以下是该API如何支持内容运营的几个关键方面: 获取笔记内容与数据: API允许内容运营者直接获取小红书平台上的笔记…

视频号小店开店需要准备什么资料?

我是电商珠珠 很多想要开通视频号小店的新手并不知道开通视频号小店需要准备什么资料。 今天我就来给大家详细的讲一下。 视频号小店分为三种类型,一种是普通企业店,一种是个体工商店,还有一种是品牌企业店。 先来说说普通企业店 1、营业…

面向对象编程(高级)

面向对象编程(高级) 1、类变量和类方法 (1) 概念 类变量,也称为静态变量,是指在类级别声明的变量。它们与特定类相关联,而不是与类的实例(对象)相关联。每个类变量只有…

【docker】cgroups资源限制

目录 一、cpu资源控制 1、 设置cpu使用率上限 2、设置cpu资源占用比(设置多个容器时才有效)Docker通过–cpu-shares指定cpu份额,默认为1024,值为1024的倍数。 3、设置容器绑定指定的CPU 三、内存资源控制 四、磁盘IO配额控制…

恭喜 Databend 上榜 2023 开源创新榜「优秀开源项目 」

近日,国家科技传播中心见证了一场开源界的重要事件:由中国科协科学技术传播中心、中国计算机学会、中国通信学会和中国科学院软件研究所联合主办,CSDN 承办的 2023 年开源创新榜专家评审会圆满落幕。由王怀民院士担任评委会主任,评…

MR实战:词频统计

文章目录 一、实战概述二、提出任务三、完成任务(一)准备数据1、在虚拟机上创建文本文件2、上传文件到HDFS指定目录 (二)实现步骤1、创建Maven项目2、添加相关依赖3、创建日志属性文件4、创建词频统计映射器类5、创建词频统计归并…

如何搭建HomeAssistant智能家居管理平台并实现公网访问内网管理界面

目录 前言 一、下载HomeAssistant镜像 二、内网穿透HomeAssistant,实现异地控制智能家居 三、使用固定域名访问HomeAssistant 结语 前言 作者简介: 懒大王敲代码,计算机专业应届生 今天给大家聊聊如何搭建HomeAssistant智能家居管理平台…

数据结构之哈希——学习笔记

今天看网课学习了哈希的数据结构,写下这一篇博客记录自己的学习过程。 1.哈希简介: 我们发现某些时候映射到小集合的时候会同时有多个值映射到一个下标里面,所以接下来是这种情况的解决方案1: 我们考虑当两个数字映射之后的结果…

Python startswith()和endswith()方法及 index()方法:检测字符串中是否包含某子串

Python startswith()和endswith()方法 Python 字符串变量还可以使用 startswith() 和endswith() 方法。 startswith()方法 startswith() 方法用于检索字符串是否以指定字符串开头,如果是返回 True;反之返回 False。此方法的语法格式如下: …

向日葵远程工具的使用Mysql5.7的安装与配置

目录 一、向日葵远程安装与使用 二、Mysql 5.7 安装与配置 2.1 安装 2.2 Navicat Premium 12 测试连接 本机测试连接 外部访问MySQL测试连接 三、思维导图 一、向日葵远程安装与使用 简介: 向日葵远程控制是一款用于对远程PC进行管理和服务的软件,拥有5秒快速…

isEmpty 和 isBlank 的用法区别,居然一半的人答不上来.....

isEmpty 和 isBlank 的用法区别 isEmpty系列isBank系列 hi!我是沁禹~ 也许你两个都不知道,也许你除了isEmpty/isNotEmpty/isNotBlank/isBlank外,并不知道还有isAnyEmpty/isNoneEmpty/isAnyBlank/isNoneBlank的存在, come on ,让我们一起来探索org.apache…

网络调试 TCP,开发板用静态地址-入门4

用两台电脑(无线网络)做实验 1.1, 在电脑A上设置为Server如下: 选择TCP Server后,直接跳出用本机IP做为“本地主机地址” 1.2在 电脑B上设置为Client, 远程主机地址设置为Server的 IP 1.3, 在A, B两台电脑上能够互相发送数据 用…

[C语言]程序设计(四)

大家好,这里是争做图书馆扫地僧的小白。非常感谢各位的支持,也期待着您的关注。 目前博主有着C语言、C、linux以及数据结构的专栏,内容正在逐步的更新。 希望对各位朋友有所帮助同时也期望可以得到各位的支持,有任何问题欢迎私信与…