Spring4.x 笔记(9):Ioc 容器高级-资源国际化

了解资源国际化(i18n)

  1. 一个支持多国语言的应用程序,要求系统可以根据客户端系统的语言类型返回对应的界面,英文返回英文,中文返回中文,这就是 i18n 国际化问题。

  2. 对于国际化要求的应用系统,不能简单的硬编码。需要对这些需要国际化的信息进行特殊处理,即为每种语言提供一套相应的资源文件,并且以规范化命名的方式保存在特定的目录中,由系统自动根据客户端语言选择合适的资源文件

  3. 国际化信息,也成为本地化信息,主要有两个条件:语言类型、国家/地区类型,简单示例如下

语言代码国家/地区类型代码
中文zh中国大陆CN
英语cn中国台湾TW
利于ja英国EN

JDK 的实现

本地化对象 Local

  1. java.util.Locale 表示语言类型、国家/地区类型的本地化类,是创建国际化应用的基础,简单的示例如下
Locale locale = new Locale("zh", "CN");
Locale china = Locale.CHINA;

// 只有语言信息的本地化对象
Locale locale2 = new Locale("zh");
Locale chinese = Locale.CHINESE;

// 获取本地系统默认的本地化对象
Locale aDefault = Locale.getDefault();
  1. JVM 设置本地化参数
java -Duser.language=cn -Duser.region-US

本地化工具

  1. JDK 提供了几个支持本地化的格式化操作工具类,主要有 NumberFormat、DateFormat、MessageFormat(占位符功能),简单示例如下
Locale locale = new Locale("zh", "CN");
NumberFormat currencyInstance = NumberFormat.getCurrencyInstance(locale);

String format = currencyInstance.format(12345.98);
// ¥12,345.98
System.out.println(format);


DateFormat dateInstance = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
String date = dateInstance.format(new Date());
// 2018-8-22
System.out.println(date);


// MessageFormat(占位符功能)
String pattern = "{0}, 你好!{1}";

String[] args = {"Sam", "MessageFormat 的功能"};
MessageFormat messageFormat = new MessageFormat(pattern, locale);
String msg = messageFormat.format(args);

// Sam, 你好!MessageFormat 的功能
System.out.println(msg);

本地化资源文件加载类

国际资源文件规范
  1. <资源名>_<语言代码>_<国家/地区代码>.properties,其中语言代码、国家/地区代码 是可选的
  • <资源名>.properties 是默认的资源文件
  • <资源名>_<语言代码>.properties 是某一个语言默认的资源文件
  1. 资源文件只能包含 ASCII 字符,使用 Unicode 编码
  • 正常中文使用JDK bin目录下的 native2ascii 工具转换。语法:native2ascii [-reverse] [-encoding 编码] [输入文件] [输出文件]
native2ascii -encoding utf-8 resource_zh_CN.properties resource_zh_CN_2.properties
  • Idea 插件可以方便开发:Setting - Editor - File Encoding - 勾选 Transparent native-to-ascii conversion
JDK 加载类 ResourceBundle
  1. 如果程序中有大量,使用File加载太麻烦,Java提供了加载本地化资源文件的类 java.util.ResourceBundle
  2. 简单示例如下: classpath/messages/messages_en.properties、classpath/messages/messages_zh.properties 资源文件
ResourceBundle bundle = ResourceBundle.getBundle("messages.messages", Locale.getDefault());
System.out.println(bundle.getString("button.submit"));

ResourceBundle bundle2 = ResourceBundle.getBundle("messages.messages", Locale.ENGLISH);
System.out.println(bundle2.getString("button.submit"));

输出: 
提交
Submit

Spring 资源国际化的实现

MessageSource 接口

了解 MessageSource

Spring 定义了访问国际化信息的 org.springframework.context.MessageSource 接口,主要的方法:

方法描述
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);code-国际化信息中的属性名;args-参数;defaultMessage-默认信息;locale-本地化对象
String getMessage(String code, Object[] args, Locale locale) throws NoSuchMessageException;功能一样,找不到资源中对应的属性名,抛出异常
String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;MessageSourceResolvable 是对 String code, Object[] args, String defaultMessage 三个参数的封装,找不到资源中对应的属性名,抛出异常
MessageSource 类结构
  1. MessageSource 类图
    image

  2. 类结构

实现类描述
HierarchicalMessageSource建立父子层级的 MessageSource 结构
ApplicationContext容器级别的国际化信息
ResourceBundleMessageSource基于Java 的 ResourceBundle 实现,允许仅通过资源名加载国际化信息
ReloadableResourceBundleMessageSource功能类似ResourceBundleMessageSource。 还提供定时刷新功能
  1. ResourceBundleMessageSource 与 ReloadableResourceBundleMessageSource 的简单使用
  • 配置 Bean
<bean id="messageSource1" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>messages.messages</value>
        </list>
    </property>
</bean>

<!--ReloadableResourceBundleMessageSource 支持定时刷新-->
<bean id="messageSource2" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>messages.messages</value>
        </list>
    </property>
    <property name="cacheSeconds" value="5"/>
</bean>
  • 测试代码
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
MessageSource messageSource = (MessageSource) context.getBean("messageSource");

String message = messageSource.getMessage("button.submit", null, Locale.getDefault());
// 提交
System.out.println(message);

容器级的国际化信息资源

  1. ApplicationContext 实现了 MessageSource接口,其本身也是一个 MessageSource 对象

  2. 在Spring 中,国际化资源就应该是容器级别的,MessageSource 作为容器的基础设施向容器中所有的Bean 开放。

  3. 在容器的初始化过程中(见容器初始化相关博文),refresh() 方法中 initMessageSource() 方法初始化容器中的国际化资源,主要是根据反射从 BeanDefinitionRegistry 中获取名称为 messageSource 且类型为org.springframework.context.MessageSource的 Bean,将这个Bean 定义的信息资源加载为容器级别的国际化信息资源。

  4. 简单示例代码如下

  • 配置,bean 的名字只能是 messageSource
<!--容器级别的国际资源化,bean 的名字只能是 messageSource,不然会报错 -->
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames">
        <list>
            <value>messages.messages</value>
        </list>
    </property>
</bean>
  • 测试:直接从容器对象获取
ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
String message = context.getMessage("button.submit", null, Locale.getDefault());
System.out.println(message);

参考

  1. 源码地址

Fork me on Gitee

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值