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. Linux下MySQL的简单操作

    Linux下MySQL的简单操作 更改mysql数据库root的密码 首次进入数据库是不用密码的: [root@localhost ~]# /usr/local/mysql/bin/mysql -ur ...

  2. 14-03 java BigInteger类,BigDecimal类,Date类,DateFormat类,Calendar类

    BigInteger类 发 package cn.itcast_01; import java.math.BigInteger; /* * BigInteger:可以让超过Integer范围内的数据进 ...

  3. 通过Anaconda在Ubuntu16.04上安装 TensorFlow(GPU版本)

    一. 安装环境 Ubuntu16.04.3 LST GPU: GeForce GTX1070 Python: 3.5 CUDA Toolkit 8.0 GA1 (Sept 2016) cuDNN v6 ...

  4. Python:SQLMAP参数中文解释

    #HiRoot's BlogOptions(选项):--version 显示程序的版本号并退出-h, --help 显示此帮助消息并退出-v VERBOSE 详细级别:0-6(默认为1) Target ...

  5. 使用 Portainer UI 管理 Docker 主机

    Docker 使用命令行的方式来管理有时候并没有那么直观,可以使用 Portainer 的 UI 来管理 Docker 主机和 Docker Swarm 集群. 安装 Portainer 环境:cen ...

  6. mysql 开发进阶篇系列 36 工具篇mysqlshow(数据库对象查看工具)

    一.概述 mysqlshow客户端查找工具,能很快地查找存在哪些数据库,数据库中的表,表中的列或索引,和mysql客户端工具很类似,不过有些特性是mysql客户端工具所不具备的. mysqlshow的 ...

  7. 串口USB单一映射及重命名

    本文针对在开发过程中有时会出现用到多个串口设备,usb端口号会发生变化,如设备的灯指示信号和其他控制器都是ttyUSB* .其序号与控制接入的顺序有关,对于写好的launch每次修改串口连接名很麻烦. ...

  8. NoSuchFieldError

    最近用Fresco框架加载GIF动态图片,遇到一个bug,记录下来,以供后来者少走弯路: 各种百度,最后参照Fresco官方文档,将原有的 fresco:1.3.0替换成0.12.0即: 在APP b ...

  9. 理解极大似然估计(MLE)

    极大似然估计学习时总会觉得有点不可思议,为什么可以这么做,什么情况才可以用极大似然估计.本文旨在通俗理解MLE(Maximum Likelihood Estimate). 一.极大似然估计的思想与举例 ...

  10. 通过反射实现IOC功能

    这段时间园子里有不少介绍IOC组件的文章,由于自己也一直在学习IOC的各种组件,及IOC的思想,常见的IOC组件很多:AutoFac.Ninject.Utity包括.NET自带的MEF等.由于今天周六 ...