il8n国际化
il8n国际化
支持多国语言的web应用,根据客户端系统的语言类型返回对应的界面
方案
为每种语言提供一套相应的资源文件,并以规范化命名的方式保存在特定的目录中,由系统自动根据客户端语言选择适合的资源文件返回
JDK对国际化的支持
1、国际化信息,也称为本地化信息,一般需要两个条件可以确定,即语言类型和国家/地区类型。java通过java.util.Locale类表示一个本地化对象
@Test
public void testLocale() {
// 语言参数和国家/地区参数都使用ISO标准语言代码表示,每种语言由两位小写字母表示,每个国家/地区由两个大写字母表示
Locale locale = new Locale("zh", "CN");
}
@Test
public void testLocale1() {
Locale locale = Locale.getDefault();
System.out.println(locale); // zh_CN
}
2、java.util包中还提供了几个支持本地化工具类,如NumberFormat、DateFormat、MessageFormat
@Test
public void numberFormat() {
double amt = 123456.78;
Locale locale = new Locale("zh", "CN");
NumberFormat currFmt = NumberFormat.getCurrencyInstance(locale);
System.out.println(currFmt.format(amt)); // ¥123,456.78
}
@Test
public void dateFormat() {
Date date = new Date();
Locale locale = new Locale("en", "US");
DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); // 第一个参数是时间样式
System.out.println(df.format(date)); // Jan 17, 2019
}
@Test
public void messageFormat1() {
// 以下两行是不同本地化的资源,{n}是占位符
String pattern1 = "{0},你好!你于{1}在工商银行存入{2} 元。";
String pattern2 = "At {1,time,short} On {1,date,long},{0} paid {2,number,currency}.";// short表示获取时分秒部分,long获取日期部分
// 将要替换的变量
Object[] params = {"John", new GregorianCalendar().getTime(),1.0E3};
// 中国格式
String msg1 = MessageFormat.format(pattern1,params);
System.out.println(msg1); // John,你好!你于19-1-17 上午11:56在工商银行存入1,000 元。
// 美国格式
MessageFormat mf = new MessageFormat(pattern2, Locale.US);
String msg2 = mf.format(params);
System.out.println(msg2); // At 11:56 AM On January 17, 2019,John paid $1,000.00.
}
国际化资源的命名规范
国际化资源的命名规范:资源名_语言代码_国家/地区代码.properties;资源名.properties是默认的资源文件,即系统按照命名规范在系统中找不到对应的文件时就使用默认的资源文件;资源名_语言代码.properties是某一语言的默认资源文件
示例:my_zh_CN.properties、my_en_US.properties
JDK ResourceBoundle 加载国际化资源
如果应用中有大量的本地化资源文件,直接通过File操作太笨拙。java提供了专门用于加载本地化资源文件的java.util.ResourceBoundle
1、资源文件
greeting.common=How are you!
greeting.morning = Good morning!
greeting.afternoon = Good Afternoon!
resource.properties
greeting.common=How are you!
greeting.morning = Good morning!
greeting.afternoon = Good Afternoon!
resource_en_US.properties
greeting.common=\u60a8\u597d\uff01
greeting.morning=\u65e9\u4e0a\u597d\uff01
greeting.afternoon=\u4e0b\u5348\u597d\uff01
resource_zh_CN.properties
greeting.common=How are you! {0},today is {1}
greeting.morning = Good morning! {0},now is {1,time,short}
greeting.afternoon = Good Afternoon! {0} now is {1,date,long}
fmt_resource.properties
greeting.common=How are you! {0},today is {1}
greeting.morning = Good morning! {0},now is {1,time,short}
greeting.afternoon = Good Afternoon! {0}, now is {1,date,long}
fmt_resource_en_US.properties
greeting.common=\u60a8\u597d\uff01 {0}\uff0c\u4eca\u5929\u662f {1}
greeting.morning=\u65e9\u4e0a\u597d\uff01 {0}\uff0c\u73b0\u5728\u662f{1,time,short}
greeting.afternoon=\u4e0b\u5348\u597d\uff01 {0}\uff0c\u73b0\u5728\u662f{1,date,long}
fmt_resource_zh_CN.properties
2、程序
@Test
public void resourceBoundle(){
// 如果不指定本地化对象,将使用本地系统默认的本地化对象。
ResourceBundle rb1 = ResourceBundle.getBundle("resource",Locale.US);
ResourceBundle rb2 = ResourceBundle.getBundle("resource",Locale.CANADA);
System.out.println("us:"+rb1.getString("greeting.common")); // us:How are you!
System.out.println("cn:"+rb2.getString("greeting.common")); // cn:您好!
}
@Test
// 在资源文件中使用占位符
public void resourceBoundleFmt(){
ResourceBundle rb1 = ResourceBundle.getBundle("fmt_resource",Locale.US);
ResourceBundle rb2 = ResourceBundle.getBundle("fmt_resource",Locale.CHINA);
Object[] params = {"John", new GregorianCalendar().getTime()}; String str1 = new MessageFormat(rb1.getString("greeting.common"),Locale.US).format(params);
String str2 =new MessageFormat(rb2.getString("greeting.morning"),Locale.CHINA).format(params);
String str3 =new MessageFormat(rb2.getString("greeting.afternoon"),Locale.CHINA).format(params);
System.out.println(str1);
System.out.println(str2);
System.out.println(str3);
}
Spring的MessageSource接口
Spring定义了访问国际化信息的MessageSource接口,MessageSource接口被HierarchicalMessageSource、ApplicationContext这两个接口扩展。
HierarchicalMessageSource添加了两个方法,setParentMessageSource()和getParentMessageSource(),用来设置父子层级的MessageSource。
HierarchicalMessageSource最重要的两个实现类是ResourceBundleMessageSource、ReloadableResourceBundleMessageSource,它们基于java的ResourceBundle实现。ReloadableResourceBundleMessageSource提供了定时刷新功能,在不重启系统的情况下可以更新资源。
ApplicationContext也实现了MessageSource接口,在AbstractApplicationContext的refresh()方法中调用initMessageSource()就是初始化容器中的国际化信息资源,它根据反射机制从BeanDefinitionRegistry中找出名为messageSource且类型为org.springframework.context.MessageSource的bean,并将这个bean定义的信息资源加载为容器级的国际化信息资源,假设bean没有被命名为messageSource,会抛出异常。
资源文件使用上面的properties文件
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myResource" class="org.springframework.context.support.ResourceBundleMessageSource">
<!-- basenames要写死,父类源码里有这个属性 -->
<property name="basenames">
<list>
<value>fmt_resource</value>
</list>
</property>
</bean>
</beans>
my.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="myResource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- basenames要写死,父类源码里有这个属性 -->
<property name="basenames">
<list>
<value>fmt_resource</value>
</list>
</property>
<property name="cacheSeconds" value="5"/>
</bean>
</beans>
my2.xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- id的值messageSource是写死的,默认为找它 -->
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<!-- basenames要写死,父类源码里有这个属性 -->
<property name="basenames">
<list>
<value>fmt_resource</value>
</list>
</property>
</bean>
</beans>
my3.xml
@Test
public void TestResourceBundleMessageSource() throws InterruptedException {
//ApplicationContext context = new ClassPathXmlApplicationContext("xml/my.xml");
ApplicationContext context = new ClassPathXmlApplicationContext("xml/my2.xml");
MessageSource messageSource = context.getBean("myResource", MessageSource.class);
// 数据
Object[] params = {"John", new GregorianCalendar().getTime()};
// 得到了最终的字符串
String message1 = messageSource.getMessage("greeting.common", params, Locale.US);
String message2 = messageSource.getMessage("greeting.morning", params, Locale.CHINA);
String message3 = messageSource.getMessage("greeting.afternoon", params, Locale.CHINA);
System.out.println(message1);
System.out.println(message2);
System.out.println(message3);
}
@Test
public void TestApplication() throws InterruptedException {
ApplicationContext context = new ClassPathXmlApplicationContext("xml/my3.xml");
// 下面这行代码是可以省略的,因为默认加载messageSource的bean;当然不省略也可以
//MessageSource messageSource = context.getBean("messageSource", MessageSource.class);
// 数据
Object[] params = {"John", new GregorianCalendar().getTime()};
// 得到了最终的字符串
String message1 = context.getMessage("greeting.common", params, Locale.US);
String message2 = context.getMessage("greeting.morning", params, Locale.CHINA);
String message3 = context.getMessage("greeting.afternoon", params, Locale.CHINA);
System.out.println(message1);
System.out.println(message2);
System.out.println(message3);
}
java
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.14.RELEASE</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
pom.xml
il8n国际化的更多相关文章
- 20145320 《Java程序设计》第8周学习总结
20145320 <Java程序设计>第8周学习总结 教材学习内容总结 15.1日志 java.util.logging包提供了日志功能相关类与接口,不必额外配置日志组件,就可以在标准ja ...
- Spring源码分析(二十三)BeanFactory的后处理
摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.激活注册的 BeanFactoryPostProcessor ...
- Spring学习(一)IOC
Spring是一站式框架: (1)Spring在javaee三层结构中,每一层都提供不同的解决技术. web层:SpringMVC service层:Spring的Ioc dao层:Spring的J ...
- BeanFactory和ApplicationContext
BeanFactory是一个类的通用工厂,可以创建并管理各种类的对象 Bean工厂是Spring框架最核心的接口,它提供了高级Ioc的配置机制.BeanFeactory使管理不同类的Java对象成为可 ...
- ASP.NET MVC之国际化(十一)
前言 在项目中遇到国际化语言的问题是常有的事情,之前在做关于MVC国际化语言时,刚开始打算全部利用AngularJS来实现,但是渐渐发现对于页面Title难以去控制其语言转换,于是对于页面Tiltle ...
- 利用angular结合translate为项目实现国际化
前言 利用H5项目第一版本已经上线,话说有了第一期就有了第二期,这不要为第二期做准备了,老大发话第一件事就要利用Angular JS实现项目的国际化以及后续要借助这个框架来实现其他功能,好吧我表示没怎 ...
- MVC之国际化
MVC之国际化 前言 在项目中遇到国际化语言的问题是常有的事情,之前在做关于MVC国际化语言时,刚开始打算全部利用AngularJS来实现,但是渐渐发现对于页面Title难以去控制其语言转换,于是对于 ...
- JavaWeb框架_Struts2_(八)----->Struts2的国际化
这一篇博文拖了蛮久了,现在先把它完成,结束struts2这个版块,当然这只是最基础的部分,做项目还需要更深的理解.下一个web后端的版块准备做Spring框架的学习-嗯,加油! 1. Struts2的 ...
- springboot配置il8n
springMvc下,配置il8n: 1.配置ResourceBundleMessageSource管理国际化资源文件 2.在页面使用fmt标签取出国际化内容 springBoot下,自动配置了il8 ...
随机推荐
- 初识The ONE
Author:bakari Date:2014.1.14 转载请注出处:http://www.cnblogs.com/bakari/p/3519841.html,谢谢! 本学期开始做真正意义上的研究 ...
- 为什么我们喜欢用 sigmoid 这类 S 型非线性变换?
本文整理自 @老师木 的一条图片新浪微博,从另一个角度给出为何采用 sigmoid 函数作非线性变换的解释. 为什么我们喜欢用 sigmoid 这类 S 型非线性变换?
- matlab中数组的拼接
matlab中,行拼接用逗号“:”,列拼接用分号“,”.示例如下: >> a=[1,2,3,4] 结果: a = 1 2 3 4 >> b=[1;2;3;4] 结果: b = ...
- Python -- tabulate 模块,
pip install tabulate >>> from tabulate import tabulate >>> table = [["Sun&quo ...
- MVC笔记--特性路由
物性路由:将路由和控制器放在一起,这样更简单方便,还可以处理复杂的路由场景 传统路由:集中.强制.基于代码风格来定义的. 每个MVC应用程序都需要路由来定义自己的处理请求方式,路由是MVC是应用程序的 ...
- 使用mybatis中的自定义TypeHandler处理PostgreSQL中的Json类型字段
业务扩展字段在PostgreSQL数据库中经常会使用json格式的数据来存储,然而mybatis默认是没有实现json类型字段对应的TypeHandler,所以一般我们需要自定义mybatis的Typ ...
- 以ActiveMQ为例JAVA消息中间件学习【4】——消息中间件实际应用场景
前言 当前真正学习消息中间件,当前已经走到了,可以简单的使用,网上有很多那种复杂的高可用的架构,但是那些都是对于一些比较大型的项目来说的. 对于一些小型的项目可能用不到那么大的架构,于是我们需要从最简 ...
- 【详解】Spring Security 之 SecurityContext
前言 本文主要整理一下SecurityContext的存储方式. SecurityContext接口 顾名思义,安全上下文.即存储认证授权的相关信息,实际上就是存储"当前用户"账号 ...
- asp.net MVC 5 Scaffolding多层架构代码生成向导开源项目(邀请你的参与)
Visual Studio.net 2013 asp.net MVC 5 Scaffolding代码生成向导开源项目 提高开发效率,规范代码编写,最好的方式就是使用简单的设计模式(MVC , Repo ...
- netty源码解解析(4.0)-3 Channel的抽象实现
AbstractChannel和AbstractUnsafe抽象类 io.netty.channel.AbstractChannel 从本章开始,会有大量的篇幅涉及到代码分析.为了能够清晰简洁的地说明 ...