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. css 如何“画”一个抽奖转盘

    主要描述的是如何运用 css 绘制一个抽奖转盘,并运用原生 js 实现转盘抽奖效果. 先来张效果图: 布局 一般来说,转盘一般有四个部分组成:外层闪烁的灯.内层旋转的圆盘.圆盘上的中奖结果.指针. 所 ...

  2. 用vue-cli脚手架搭建一个仿网易云音乐的全家桶vue项目

    一,vue-cli环境搭建 1,全局安装webpack npm install webpack -g 2,安装vue脚手架 npm install vue-cli -g 3,新建一个新的project ...

  3. LDO和DC-DC的概念,区别及优缺点

    最近在做蓝牙项目的时候,遇到了需要配置这两种不同的供电模式的问题,这里顺便温习一下这种供电方式的概念,做个总结. LDO :LOW DROPOUT VOLTAGE 低压差线性稳压器,故名思意,为线性的 ...

  4. 凉凉了,Eureka 宣布闭源,Spring Cloud 何去何从?

    今年 Dubbo 活了,并且被 Apache 收了.同时很不幸,Spring Cloud 下的 Netflix Eureka 组件项目居然宣布闭源了.. 已经从 Dubbo 迁移至 Spring Cl ...

  5. Golang Struct 声明和使用

    Golang Struct 声明和使用 Go可以声明自定义的数据类型,组合一个或多个类型,可以包含内置类型和用户自定义的类型,可以像内置类型一样使用struct类型 Struct 声明 具体的语法 t ...

  6. Servlet-session简介及使用场景

  7. 3-2 模板语法(vue中的内容写法)

    插值表达式.v-text.v-html的用法

  8. windows下更新node环境

    https://github.com/Kenshin/gnvm 下载gnvm.exe程序 使用where node命令查看node所在目录,并将下载好的gnvm.exe程序复制到目录中 输入gnvm  ...

  9. js实现深拷贝的一些方法

    在ECMAScript变量中包含两种不同类型的值:基本类型值和引用类型值. 基本类型值:Undefined.Null.Boolean.Number.String 引用类型值:Object.Array. ...

  10. 利用shell显示wordcount功能

      Shell脚本编程是Linux系统最为核心的技术之一,它能够利用简单的命令来实现一些复杂的功能,同时,由于Linux提供了很多文本处理命令,如grep(grep family), tr, sed, ...