[原创]java WEB学习笔记51:国际化 概述,API 之 locale类,dataFormat类,numberFormat类, MessageFormat类,ResourceBundle 类
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用
内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系。
本人互联网技术爱好者,互联网技术发烧友
微博:伊直都在0221
QQ:951226918
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1.国际化的概述
1)概念
① 软件的本地化:一个软件在某个国家或地区使用时,采用该国家或地区的语言,数字,货币,日期等习惯。
② 软件的国际化:软件开发时,让它能支持多个国家和地区的本地化应用。使得应用软件能够适应多个地区的语言和文化风俗习惯。
③ 随用户区域信息而变化的数据称为本地信息敏感数据。例如数字,货币等数据。
④ 应用程序的国际化就是在应用软件的设计阶段,使软件能够支持多个国家和地区的用户的使用习惯。
⑤ 国际化又称为 i18n:internationalization
2)软件国际化的特征
① 对于程序中的本地信息敏感的数据(日期,货币等)能根据当前所在的国家或地区的文化习惯进行显示
② 对于文本元素(错误提示信息,状态信息等)不是直接写在应用程序中,而是存储在应用程序外部的资源文件中,在应用程序中通过程序代码来动态获得这些数据
③ 无需修改和重新编译程序就能支持新的国家或地区的用户使用
3)Java 国际化解决方案
① 本文信息不能硬编码在程序代码中,而是需要将它们从应用程序中分离出来,在软件运行时根据本地信息读取相应的文本内容进行显示
② 数值,货币,时间,日期等本地敏感数据可能在程序运行时动态产生,所以无法像文字一样简单地将它们从应用程序中分离出来,而是需要特殊处理。
Java 中提供了解决这些问题的 API 类(位于 java.util 包和 java.text 包中)
2.Locale 类
1)Locale 实例对象代表一个特定的地理,政治或文化上的区域 。JDK 中提供了很多常量。也可以通过 Locale(languageCode,countryCode) 创建对象;在WEB 应用中可以使用 request.getLocale()方法获取
2)一个 Locale 对象本身不会验证它代表的语言和国家地区信息是否正确,只是向本地敏感的类提供本地信息,与国际化相关的格式化和解析任务由本地敏感的类(若JDK中的某个类在运行时需要根据 Locale 对象来调整其功能,这个类就称为本地敏感类)去完成
1 package com.jason.i18n;
2
3 import java.util.Locale;
4
5 import org.junit.Test;
6
7
8 public class i18nTest {
9
10 @Test
11 public void testLocal(){
12 //封装了特定的地理,政治,文化的区域
13 Locale locale = Locale.CHINA;
14 System.out.println(locale.getDisplayCountry());
15 System.out.println(locale.getLanguage());
16 }
17
18 }
3.DateFormat 类
1)DateFormat 类可以将一个日期/时间对象格式化为表示某个国家地区的日期/时间字符串,也可以将表示某个本地的日期/时间的字符串解析为相应的日期/时间对象
2)DateFormat 类定义了一些用于描述日期/时间的显示模式的 int 型的常量,包括FULL, LONG, MEDIUM, DEFAULT, SHORT,这些常量用于描述表示日期/时间字符串的长度。这些常量说明表示的日期/时间的确切格式取决于具体的国家和地区
步骤:
① 获取 DateFormat 对象:DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
② DateFormat 对象通常不是线程安全的,每个线程都应该创建自己的 DateFormat 实例对象
③ DateFormat 对象的方法:
format: 将日期/时间对象格式化为符合某个本地环境习惯的字符串
parse:将符合某个本地环境习惯的日期/时间字符串解析为日期/时间对象
1 @Test
2 public void testDateFormat(){
3 Locale locale = Locale.CHINA;
4 Date date = new Date();
5
6 //获取 DateFormat 对象
7 DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
8
9 String str = dateFormat.format(date);
10 System.out.println(str); //2016-7-27 22:08:53
11 }
1 @Test
2 public void testDateFormat2() throws ParseException{
3 String str = "20012-12-12 12:12:12";
4 //指定被解析的字符串的格式
5 DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
6
7 Date date = dateFormat.parse(str);
8 System.out.println(date);
9
10 }
DateFormat.java
1 /**
2 * Constant for full style pattern.
3 */
4 public static final int FULL = 0;
5 /**
6 * Constant for long style pattern.
7 */
8 public static final int LONG = 1;
9 /**
10 * Constant for medium style pattern.
11 */
12 public static final int MEDIUM = 2;
13 /**
14 * Constant for short style pattern.
15 */
16 public static final int SHORT = 3;
17 /**
18 * Constant for default style pattern. Its value is MEDIUM.
19 */
20 public static final int DEFAULT = MEDIUM;
注意:以此加深对API的了解
1. 若只希望通过DateFormat 把一个Date 对象转化为一个字符串,则可以使用DateFormat 的工厂方法来获取 DateFormat 对象
2. 可以获取只格式 化 Date 的DateFormat 对象:getDateInstance(int style , Locale alocale)
3. 可以获取只格式化 Time 的DateFormat 对象:getTimeInstance(int style, Locale alocale)
4. 可以既格式 Date 又 格式化 Time 的DateFormat 对象:getDateTimeInstance(int dateStyle,int timeStyle,Locale alocale)
5.style :FULL, LONG, MEDIUM, DEFAULT, SHORT。locale则代表国家地区的Locale 对象
6.通过DateFormat 的format 方法 格式化 一个Date 对象到字符串
7.字符串解析成 data
1)先创建DataFormat 对象:创建DateFormat 的子类SimpleDateFormet 对象 :DateFormat dateFormat = new SimpleDateFormat(String pattern); 其中pattern 为日期,时间的格式,例如:"yyyy-MM-dd hh:mm:ss"
2)调用parse 方法来解析字符串到Date 对象:Date date = dateFormat.parse(str);
4.NumberFormat 类
1)NumberFormat 可以将一个数值格式化为符合某个国家地区习惯的数值字符串,也可以将符合某个国家地区习惯的数值字符串解析为对应的数值
2)NumberFormat 类的方法:
format 方法:将一个数值格式化为符合某个国家地区习惯的数值字符串
parse 方法:符合某个国家地区习惯的数值字符串解析为对应的数值
格式化
1 @Test 2 public void testNumberFormat(){ 3 double d = 123131321.45564d; 4 Locale locale = Locale.CHINA; 5 NumberFormat numberFormat = NumberFormat.getNumberInstance(locale); 6 7 //转数字 8 String str = numberFormat.format(d); 9 System.out.println(str);//123,131,321.456 10 11 //转货币 12 numberFormat = numberFormat.getCurrencyInstance(locale); 13 System.out.println(numberFormat.format(d));//¥123,131,321.46 14 } 15
解析
1 @Test 2 public void testNumberFormat() throws ParseException{ 3 double d = 123131321.45564d; 4 Locale locale = Locale.CHINA; 5 NumberFormat numberFormat = NumberFormat.getNumberInstance(locale); 6 7 String str1 = "123,456,789,.123"; 8 d = (double) numberFormat.parse(str1); 9 System.out.println(d); 10 11 }
5.MessageFormat类
1) MessageFormat 类提供了一种参数替换模式字符串中的占位符的方式,它将根据模式字符串中包含的占位符产生一系列的格式化对象,然会调用这些格式化对象对参数进行格式化,并用格式化后的结果字符串替换模式字符串中的相应占位符
2)模式字符串与占位符
①:模式字符串: On {0}, {1} destroyed {2} houses and caused {3} of damage. 对模式字符串进行格式化操作时,需要采用数组的方式提供模式字符串中的每个占位符所对应的参数.
②:占位符有以下三种方式:
-- {argumentIndex}: 0-9 之间的数字,表示要格式化对象数据在参数数组中的索引号
-- {argumentIndex,formatType}: 参数的格式化类型
-- {argumentIndex,formatType,FormatStyle}: 与指定的格式化类型对应的模式,它的值必须是与相应的格式化类型匹配的合法模式或表示合法模式的字符串
3)MessageFormat 格式化模式字符串 MessageFormat 格式化模式字符串
MessageFormat 类可以格式化模式字符串,它根据其中的占位符产生一系列的格式化对象,然后调用这些格式化对象对参数进行格式化,并用格式化后的结果字符串替换模式字符串中的相应占位符
① 创建 MessageFormat 对象:须指定格式化的模式字符串,也可以指定 Locale 对象来按某个国家地区的习惯进行格式化
② 调用 MessageFormat 对象的 format 方法执行格式化操作:须为format 方法传递一个数组类型的参数,数组中的每个元素分别用于代替模式字符串中的与其索引号相对应的占位符
1 /**
2 *
3 * @Title: testMessageFormat
4 * @Description:
5 * MessageFormat:可以格式化模式字符串
6 * 模式字符串:带占位符的字符串:"Date:{0}, Salary:{1}"
7 * 可以通过Format 方法可以对模式字符串进行格式化
8 *
9 */
10 @Test
11 public void testMessageFormat(){
12 String str = "Date:{0} ,Salary:{1}";
13 Locale locale = Locale.CHINA;
14 Date date = new Date();
15 double sal = 12345.65;
16
17 DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
18 String dateStr = dateFormat.format(date);
19
20 NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);
21 String salStr = numberFormat.format(sal);
22
23 MessageFormat messageFormat = new MessageFormat(str);
24
25 String result = messageFormat.format(str, date, sal);//Date:16-8-1 上午11:16 ,Salary:12,345.65
26 // String result = messageFormat.format(str, dateStr, salStr);//Date:2016-8-1 ,Salary:¥12,345.65
27
28 System.out.println(result);
29
30 }
6.ResourceBundle 类
1)ResourceBundle 类用于描述一个资源包,一个资源包用于包含一组与某个本地环境相关的对象,可以从一个资源包中获取特定于本地环境的对象。对于不同的本地环境,可以有不同的 ResourceBundle 对象与之关联,关联的 ResourceBundle 对象中包含该本地环境下专有的对象。
2)资源包简介
① 在设计一个国际化应用时,应该把程序显示的文本内容从源程序中分离出来,放在独立的资源文件中,并针对不同的本地环境编写不同的资源文件。这些资源文件被称为应用程序的资源包
② 应用程序在运行时,将从与用户的本地环境相对应资源文件中读取名称项对应的值的内容,由于同一个名称项在各个资源文件中对应的值内容是随本地环境信息而改变的,这样就实现了程序的静态文本内容的国际化。
③ 当要为应用程序添加某个新的本地化支持时,只需编写一个适合的本地环境的资源文件即可,不用修改源程序代码。
④ 一个应用程序可以有多个资源包,一个资源包中的每个资源文件都拥有共同的基名。除了基名,每个资源文件的名称中还有标识其本地信息的附加部分。
例如:一个资源包的基名是:“myproperties”, 则该资源包中与中文环境相对应的资源文件为: “myproperites_zh.properties”
⑤ 一般情况下,每个资源包都有一个默认的资源文件,默认的资源文件不带标识本地信息的附加部分。若应用程序在资源包中找不到某个本地环境匹配的资源文件,最后将选择该资源包中的默认资源文件。
3)资源文件的内部格式
① 资源文件通常采用 java.util.Properties 类要求的文件格式,其中包含每项资源信息的名称项和值内容,每个名称项用于唯一地标识一个资源信息,值内容用于指定资源信息在某个本地环境下的内容
② 一个资源包中的所有资源文件中通常都应包含相同的名称项,与各个本地环境对应的资源文件中为这些名称项设置的值分别是适合该本地环境的内容。
③ 资源文件完全遵循 java.util.Properties 类要求的文件格式,它要求资源文件中的字符必须全部为有效的 ASCII 字符。若资源文件中要包含非 ASCII 的字符,必须将它们转化成”\uXXXX”形式的转移序列,其中 XXXX 是该字符的 Unicode 编码的十六进制数值
例子
i18n_en_US.properties
1 date=Date
2 salary=Salary
i18n_zh_CN.properties
1 date=\u65E5\u671F
2 salary=\u5DE5\u8D44
i18n.properties
1 date=Date
2 salary=Salary
测试代码:根据不同的Locale 值
1 @Test
2 public void testResourceBundle(){
3 // Locale locale = Locale.US;
4 Locale locale = Locale.CHINA;
5 ResourceBundle resourceBundle = ResourceBundle.getBundle("i18n", locale);
6 System.out.println(resourceBundle.getString("salary"));
7 System.out.println(resourceBundle.getString("date"));
8 }
结合上述 处理类 完成国际化demo
1 /** 2 * 3 * @Title: testResourceBundle 4 * @Description: 5 * 1.在类路径下需要有对应的资源文件:baseName.paroperties。其中baseName 是基名 6 * 2.可以使用:基名_语言_国家代码.properties 来添加不同国家或者地区的资源文件。例如本例中的:i18n_zh_CN.properties 7 * 3.要求所有基名相同的资源文件的 key 完全相同。 8 * 4.可以使用 natice2ascii 命令得到 汉子 一一对应的一个asc 码。Eclipes 内置了此工具 9 * 5.可以调用 resourceBundle 的getBundel(基名,Locale 实例) 方法,获取ResourceBundel 对象 10 * 6.可以调用resourceBundle 的getString(key) 来获取资源文件的value 字符串的值 11 * 7.结合DateFormat,NumberForm,MessageForm即 可以 实现国际化 12 * 13 */ 14 @Test 15 public void testResourceBundle(){ 16 // Locale locale = Locale.US; 17 Locale locale = Locale.CHINA; 18 ResourceBundle resourceBundle = ResourceBundle.getBundle("i18n", locale); 19 // System.out.println(resourceBundle.getString("salary")); 20 // System.out.println(resourceBundle.getString("date")); 21 22 23 String deteLabel = resourceBundle.getString("date"); 24 String salLabel = resourceBundle.getString("salary"); 25 26 String str = "{0}:{1}, {2}:{3}"; 27 28 Date date = new Date(); 29 double sal = 12345.65; 30 31 DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM, locale); 32 String dateStr = dateFormat.format(date); 33 34 NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale); 35 String salStr = numberFormat.format(sal); 36 37 38 String result = MessageFormat.format(str, deteLabel, dateStr, salLabel, salStr); 39 System.out.println(result); 40 }