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国际化的更多相关文章

  1. 20145320 《Java程序设计》第8周学习总结

    20145320 <Java程序设计>第8周学习总结 教材学习内容总结 15.1日志 java.util.logging包提供了日志功能相关类与接口,不必额外配置日志组件,就可以在标准ja ...

  2. Spring源码分析(二十三)BeanFactory的后处理

    摘要: 本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 目录 一.激活注册的 BeanFactoryPostProcessor ...

  3. Spring学习(一)IOC

     Spring是一站式框架: (1)Spring在javaee三层结构中,每一层都提供不同的解决技术. web层:SpringMVC service层:Spring的Ioc dao层:Spring的J ...

  4. BeanFactory和ApplicationContext

    BeanFactory是一个类的通用工厂,可以创建并管理各种类的对象 Bean工厂是Spring框架最核心的接口,它提供了高级Ioc的配置机制.BeanFeactory使管理不同类的Java对象成为可 ...

  5. ASP.NET MVC之国际化(十一)

    前言 在项目中遇到国际化语言的问题是常有的事情,之前在做关于MVC国际化语言时,刚开始打算全部利用AngularJS来实现,但是渐渐发现对于页面Title难以去控制其语言转换,于是对于页面Tiltle ...

  6. 利用angular结合translate为项目实现国际化

    前言 利用H5项目第一版本已经上线,话说有了第一期就有了第二期,这不要为第二期做准备了,老大发话第一件事就要利用Angular JS实现项目的国际化以及后续要借助这个框架来实现其他功能,好吧我表示没怎 ...

  7. MVC之国际化

    MVC之国际化 前言 在项目中遇到国际化语言的问题是常有的事情,之前在做关于MVC国际化语言时,刚开始打算全部利用AngularJS来实现,但是渐渐发现对于页面Title难以去控制其语言转换,于是对于 ...

  8. JavaWeb框架_Struts2_(八)----->Struts2的国际化

    这一篇博文拖了蛮久了,现在先把它完成,结束struts2这个版块,当然这只是最基础的部分,做项目还需要更深的理解.下一个web后端的版块准备做Spring框架的学习-嗯,加油! 1. Struts2的 ...

  9. springboot配置il8n

    springMvc下,配置il8n: 1.配置ResourceBundleMessageSource管理国际化资源文件 2.在页面使用fmt标签取出国际化内容 springBoot下,自动配置了il8 ...

随机推荐

  1. Tools - 使用Doxygen和Graphviz分析代码

    简介 使用Doxygen来生成结构,使用Graphviz来显示结构: Doxygen:http://www.doxygen.nl/ 用来生成项目文档的工具软件,可将程序中的特定批注转换成为说明文件,还 ...

  2. 06-TypeScript中的表达式

    TypeScript中提供了箭头表达式,通过箭头表达式可以简化我们的编码. 1.箭头表达式简化匿名函数 在JS中,我们通常使用匿名函数,匿名函数实际上是赋值给一个变量,常见的写法如下: var sun ...

  3. iOS事件拦截及应用

    1.概述 我们知道事件的分发是由Application到Window再到各级View的,所以显然最安全可靠的拦截地方是Application.这里拦截事件后如果不手动往下分发,则进入hit-test ...

  4. Zabbix4.2.0基本配置和邮件报警

    目录 1. 修改中文 2. 添加监控本机 3. 监控本机mysql 4. 配置邮件报警 4.1 添加FTP模板 4.2 报警媒介类型 4.3 配置报警到用户 4.4 配置动作 4.5 模拟FTP故障 ...

  5. SQL 必知必会·笔记<11>创建高级联结

    1. 使用表别名 SQL 除了可以对列名和计算字段使用别名,还允许给表名起别名.这样 做有两个主要理由: 缩短SQL 语句: 允许在一条SELECT 语句中多次使用相同的表. 使用表别名示例: SEL ...

  6. netty源码解解析(4.0)-7 线程模型-IO线程EventLoopGroup和NIO实现(二)

    把NIO事件转换成对channel unsafe的调用或NioTask的调用 processSelectedKeys()方法是处理NIO事件的入口: private void processSelec ...

  7. [NOI 2017]整数

    Description 题库链接 P 博士将他的计算任务抽象为对一个整数的操作. 具体来说,有一个整数 \(x\) ,一开始为 \(0\) . 接下来有 \(n\) 个操作,每个操作都是以下两种类型中 ...

  8. 第4章 ext文件系统机制原理剖析

    将磁盘进行分区,分区是将磁盘按柱面进行物理上的划分.划分好分区后还要进行格式化,然后再挂载才能使用(不考虑其他方法).格式化分区的过程其实就是创建文件系统. 文件系统的类型有很多种,如CentOS 5 ...

  9. C#基础知识回顾-- 属性与字段

    今天在公交车上,突然想属性和字段到底有什么区别?很多字段属性都存在 get{}和set{} 和普通的变量没什么区别(可读可写) 我就感觉属性就是给字段一个多的选择方式,有的字段是不允许更改的.. 刚写 ...

  10. WebFrom 小程序【分页功能 】

    实现分页展示功能 基本功能:上一页.下一页.首页.尾页.跳转 两个重要的变量 1.每页显示几条数据  2.现在是第几页    方法 } /*表格样式*/ .tab { width: %; backgr ...