Spring 国际化简介

度恨菩提
• 阅读 1027

ResourceBundle

Java 提供了ResourceBundle类,可以实现特定区域(语言环境)的资源加载。以便我们在编码时可以使用一个ResourceBundle而不用考虑特定的语言环境信息,程序自动通过当前的用户的语言环境信息来加载特定资源。
ResourceBundle的使用比较简单,如下面的代码。

public class ResourceBundleDemo {

    public static void main(String[] args) throws UnsupportedEncodingException {
        ResourceBundle rb = ResourceBundle.getBundle("test");
        System.out.println(rb.getString("key1"));
        rb = ResourceBundle.getBundle("test", Locale.GERMAN);
        System.out.println(rb.getString("key1"));
    }
}

ResourceBundle通过了getBundle 工厂方法创建的实例默认被缓存。如果ResourceBundle被缓存多次调用getBundle 方法返回同一个实例。getBundle 的客户端可以清除缓存、管理缓存的缓存时间。参考:clearCache方法、ResourceBundle.Control.getTimeToLive和ResourceBundle.Control.needsReload。

Java平台提供了ResourceBundle两个子类ListResourceBundle 和PropertyResourceBundle。

ResourceBundle工厂方法在加载资源的过程中需要ResourceBundle.Control提供必须要的信息。ResourceBundle.Control 提供包括:bundle名字、创建Bundle、资源寻找等信息。默认的ResourceBundle.Control 可以被覆盖。默认的ResourceBundle.Control实现了两种格式资源的加载,class 格式和properties 格式。例如下面的代码:

ResourceBundle  rb = ResourceBundle.getBundle(“MyResource”); 

那么会加载MyResource.class(及相关语言区域后缀的class),如果class找不到,会加载MyResource.properties(及相关语言区域后缀的properties)的相关文件(通过PropertyResourceBundle)。

MessageFomat

MessageFormat 提供了以与语言无关方式生成连接消息的方式。使用此方法构造向终端用户显示的消息。MessageFormat 本身不实现特定于语言环境的行为。特定于语言环境的行为是由所提供的模式和用于已插入参数的子格式来定义的。
MessageFormat 简单实例如下代码:

 int planet = 7;
 String event = "a disturbance in the Force";

 String result = MessageFormat.format(
     "At {1,time} on {1,date}, there was {2} on planet {0,number,integer}.",
     planet, new Date(), event);

MessageFormat具体使用以及pattern模式可以参考javadoc。
MessageFormat可以和ResourceBundle配合做到个不同语言环境的用户显示。

public static void main(String[] args) {
    Date d = new Date();
    MessageFormat format = new MessageFormat("今天是{0,date ,yyyy-MM-dd}");
    System.out.println(format.format(new Object[]{d}));

    format.applyPattern("today is {0,date, dd/MM/yy}");
    System.out.println(format.format(new Object[]{d}));

}

Spring MessageSource

Spring MessageSource接口,用来支持参数化和国际化消息。

public interface MessageSource {
    @Nullable
    String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);
    String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;

    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;

}

Spring 提供了两个开箱即用的MessageSource实现,ResourceBundleMessageSource 和ReloadableResourceBundleMessageSource。

在AbstractApplicationContext中的initMessageSource方法,检测有无配置名称为MESSAGE_SOURCE_BEAN_NAME(messageSource)的bean,如果没有配置则生成一个DelegatingMessageSource 进行注册。initMessageSource的源码如下:

/**
     * Initialize the MessageSource.
     * Use parent's if none defined in this context.
     */
    protected void initMessageSource() {
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();
        if (beanFactory.containsLocalBean(MESSAGE_SOURCE_BEAN_NAME)) {
            this.messageSource = beanFactory.getBean(MESSAGE_SOURCE_BEAN_NAME, MessageSource.class);
            // Make MessageSource aware of parent MessageSource.
            if (this.parent != null && this.messageSource instanceof HierarchicalMessageSource) {
                HierarchicalMessageSource hms = (HierarchicalMessageSource) this.messageSource;
                if (hms.getParentMessageSource() == null) {
                    // Only set parent context as parent MessageSource if no parent MessageSource
                    // registered already.
                    hms.setParentMessageSource(getInternalParentMessageSource());
                }
            }
            if (logger.isTraceEnabled()) {
                logger.trace("Using MessageSource [" + this.messageSource + "]");
            }
        }
        else {
            // Use empty MessageSource to be able to accept getMessage calls.
            DelegatingMessageSource dms = new DelegatingMessageSource();
            dms.setParentMessageSource(getInternalParentMessageSource());
            this.messageSource = dms;
            beanFactory.registerSingleton(MESSAGE_SOURCE_BEAN_NAME, this.messageSource);
            if (logger.isTraceEnabled()) {
                logger.trace("No '" + MESSAGE_SOURCE_BEAN_NAME + "' bean, using [" + this.messageSource + "]");
            }
        }
    }

DelegatingMessageSource的默认代理MesageSource对象来源于getInternalParentMessageSource。要么是parent的mesageSource要么是,null。

    protected MessageSource getInternalParentMessageSource() {
        return (getParent() instanceof AbstractApplicationContext ?
                ((AbstractApplicationContext) getParent()).messageSource : getParent());
    }

AbstractApplicationContext也实现了MessageSource的接口,相关的实现都是通过委托内部的messageSource进行处理的。源码如下:

 @Override
public String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale) {
   return getMessageSource().getMessage(code, args, defaultMessage, locale);
}

@Override
public String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException {
   return getMessageSource().getMessage(code, args, locale);
}

@Override
public String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException {
   return getMessageSource().getMessage(resolvable, locale);
}

private MessageSource getMessageSource() throws IllegalStateException {
   if (this.messageSource == null) {
      throw new IllegalStateException("MessageSource not initialized - " +
            "call 'refresh' before accessing messages via the context: " + this);
   }
   return this.messageSource;
}

项目中,我们如果想使用国际化的内容,需要配置一个名字为“messageResource”的MessageResouce实例,可以使用spring开箱即用的现有实现(ResourceBundle 和 MessageFormat的合集)。

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
Java 使用 ResourceBundle 类读取 properties 文件中文乱码的解决方案
Java使用java.util.ResourceBundle类的方式来读取properties文件时不支持中文,要想支持中文必须将文件设置为ISO88591编码格式,这对于开发工具默认为UTF8来说很不友好,而且就算用ISO88591编码,当其他人将这个项目导入开发工具时很容易出现这个properties文件中的内容有乱码(前提是该文件中包含中文)
Stella981 Stella981
3年前
Gradle的基本使用
Gradle的介绍Gradle是一个基于ApacheAnt和ApacheMaven概念的项目自动化建构工具。它使用一种基于Groovy的特定领域语言(DSL)来声明项目设置,抛弃了基于XML的各种繁琐配置。面向Java应用为主。当前其支持的语言限于Java、Groovy和Scala,计划未来将支持更多的语言。Gra
Easter79 Easter79
3年前
Spring容器中Bean的作用域
当通过Spring容器创建一个Bean实例时,不仅可以完成Bean实例的实例化,还可以为Bean指定特定的作用域。Spring支持如下5种作用域:singleton:单例模式,在整个SpringIoC容器中,使用singleton定义的Bean将只有一个实例prototype:原型模式,每次通过容器
Wesley13 Wesley13
3年前
AOP的自动代理
Spring的aop机制提供两类方式实现类代理。一种是单个代理,一种是自动代理。单个代理通过ProxyFactoryBean来实现(就如上面的配置)。自动代理:自动代理能够让切面定义来决定那个bean需要代理,不需要我们为特定的bean明确的创建代理从而提供一个更完整的aop实现通过BeanNameAutoProxyCreator或者Defaul
Stella981 Stella981
3年前
Cocos Creator 资源加载流程剖析【三】——Load部分
Load流程是整个资源加载管线的最后一棒,由Loader这个pipe负责(loader.js)。通过Download流程拿到内容之后,需要对内容做一些“加载”处理。使得这些内容可以在游戏中使用。这里并不是所有的资源都需要进行一个加载处理,目前只有图片、Json、Plist、Uuid(Prefab、场景)等资源才会执行加载的流程,其他的资源在Downloa
Wesley13 Wesley13
3年前
Unity ScriptObject创建Asset文件
创建ScriptObject可以创建带序列化的资源,只保存数据不用绑定在游戏对象上。创建出来的本子资源可以通过资源加载到游戏里使用。这里介绍一下使用Resources加载。创建好的asset文件也可以在Inspector中进行编辑。1usingSystem.Collections.Generic;2usingUnityEng
Wesley13 Wesley13
3年前
Visual Studio 中的 .sln 和 .suo 文件
解决方案文件VisualStudio采用两种文件类型.sln&.suo来存储特定于解决方案的设置。这些文件总称为解决方案文件,为解决方案资源管理器提供显示管理文件的图形接口所需的信息,从而使您每次继续开发任务时,都能够全身心地投入到项目和最终目标中,不会因开发环境而分散精力。.sln(Solution)
Stella981 Stella981
3年前
EKT Java企业级关键技术强化 Enterprise Edition
EKTenterprisekeytechlology企业关键技术本章目标:1.理解Class类2.理解JAVA类加载体系结构3.理解类的加载过程Class对象由JVM自动产生,每当一个类被加载时,JVM就自动为其生成一个Class对象,通过Class对象可以获得类的相关信息。将类信息读到内存中过程,称为类加载
Wesley13 Wesley13
3年前
#pragma命令详解
每种C和C的实现支持对其宿主机或操作系统唯一的功能。例如,一些程序需要精确控制超出数据所在的储存空间,或着控制特定函数接受参数的方式。pragma指示使每个编译程序在保留C和C语言的整体兼容性时提供不同机器和操作系统特定的功能。编译指示被定义为机器或操作系统特定的,并且通常每种编译程序是不同的。语法:pragmatoken\_strin
Spring配置文件的魔法炼金术:如何制造容器化时代的完美配方 | 京东物流技术团队
基于现代服务的云原生十二要素理论,我们在采用容器化部署时,要保证同一个镜像可以满足不同环境的部署要求,而不是不同环境打包不同的镜像。本文档主要介绍一种基于spring框架的满足不同环境配置的编译打包方案,满足同一个镜像可以在环境分组下通过启动项配置实现不同环境的部署。
崇恩圣帝 崇恩圣帝
1年前
滑动验证码识别
在本文中,我们将使用JavaScript语言结合Puppeteer库来实现极验滑动验证码的自动识别和验证过程。通过模拟用户的行为,我们可以有效地应对极验滑动验证码的挑战。准备工作在开始之前,请确保已经安装了Node.js环境,并通过npm安装了Puppet