Spring4.x 笔记(9):Ioc 容器高级-资源国际化
文章目录
了解资源国际化(i18n)
-
一个支持多国语言的应用程序,要求系统可以根据客户端系统的语言类型返回对应的界面,英文返回英文,中文返回中文,这就是 i18n 国际化问题。
-
对于国际化要求的应用系统,不能简单的硬编码。需要对这些需要国际化的信息进行特殊处理,即为每种语言提供一套相应的资源文件,并且以规范化命名的方式保存在特定的目录中,由系统自动根据客户端语言选择合适的资源文件
-
国际化信息,也成为本地化信息,主要有两个条件:语言类型、国家/地区类型,简单示例如下
语言 | 代码 | 国家/地区类型 | 代码 |
---|---|---|---|
中文 | zh | 中国大陆 | CN |
英语 | cn | 中国台湾 | TW |
利于 | ja | 英国 | EN |
JDK 的实现
本地化对象 Local
-
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();
- JVM 设置本地化参数
java -Duser.language=cn -Duser.region-US
本地化工具
- 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);
本地化资源文件加载类
国际资源文件规范
-
<资源名>_<语言代码>_<国家/地区代码>.properties
,其中语言代码、国家/地区代码 是可选的
-
<资源名>.properties
是默认的资源文件 -
<资源名>_<语言代码>.properties
是某一个语言默认的资源文件
- 资源文件只能包含 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
- 如果程序中有大量,使用File加载太麻烦,Java提供了加载本地化资源文件的类
java.util.ResourceBundle
- 简单示例如下:
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 类结构
-
MessageSource 类图
-
类结构
实现类 | 描述 |
---|---|
HierarchicalMessageSource | 建立父子层级的 MessageSource 结构 |
ApplicationContext | 容器级别的国际化信息 |
ResourceBundleMessageSource | 基于Java 的 ResourceBundle 实现,允许仅通过资源名加载国际化信息 |
ReloadableResourceBundleMessageSource | 功能类似ResourceBundleMessageSource。 还提供定时刷新功能 |
- 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);
容器级的国际化信息资源
-
ApplicationContext 实现了 MessageSource接口,其本身也是一个 MessageSource 对象
-
在Spring 中,国际化资源就应该是容器级别的,MessageSource 作为容器的基础设施向容器中所有的Bean 开放。
-
在容器的初始化过程中(见容器初始化相关博文),refresh() 方法中 initMessageSource() 方法初始化容器中的国际化资源,主要是根据反射从 BeanDefinitionRegistry 中获取名称为
messageSource
且类型为org.springframework.context.MessageSource
的 Bean,将这个Bean 定义的信息资源加载为容器级别的国际化信息资源。 -
简单示例代码如下
- 配置,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);