• 导读
  • 概述
  • 基础知识
    • 概述
    • javautilLocale
    • 本地化工具类
      • NumberFormat DateFormat
      • MessageFormat
    • ResourceBoundle
      • 实例

        • 中文本地化资源文件两种转换方式

          • JDK的native2ascii工具
          • IDE自带的支持
      • ResourceBundle加载资源的顺序
      • 在资源文件中使用格式化串

导读

Spring-国际化信息01-基础知识

Spring-国际化信息02-MessageSource接口

Spring-国际化信息03-容器级的国际化信息资源


概述

假设我们开发一个支持多国语言的Web应用系统,要求能够根据客户端系统的语言类型返回对应的界面。

这是典型的i18n国际化问题。 简单的来讲就是为每种语言提供一套相应的资源文件,并以规范化命名的方式保存在特定的目录中,由系统自动根据客户端语言选择合适的资源文件。

基础知识

概述

国际化信息也称为本地化信息。

一般需要两个条件才可以确定一个特定类型的本地化信息

  1. 语言类型
  2. 国家/地区类型

比如中文本地化信息既有中国大陆地区的中文,又有中国台湾、中国香港地区的中文,还有新加坡地区的中文。

Java通过java.util.Locale类表示一个本地化对象,它允许通过语言参数国家/地区参数创建一个确定的本地化对象。

语言参数使用ISO标准语言代码标识,由ISO-639标准定义,每种语言由两位小写字母表示。标准语言代码信息可参考: http://www.loc.gov/standards/iso639-2/php/English_list.php

国家/地区参数也由标准的ISO国家/地区代码标识,由ISO-3166标准定义,每个国家/地区由两个大写字母标识。详情请参考:https://www.iso.org/obp/ui/#search/code/

比如:


代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

java.util.Locale

java.util.Locale是表示语言和国家/地区信息的本地化类,它是创建国际化应用的基础。

请看下面的几个创建本地化对象的实例:

package com.xgj.ioc.i18n.locale;import java.util.Locale;public class LocaleTest {public static void main(String[] args) {// (1)带有语言和国家/地区信息的本地化对象Locale locale1 = new Locale("zh", "CN");System.out.println("Locale(\"zh\", \"CN\"):" + locale1);// (2)只带有语言信息的本地化对象Locale locale2 = new Locale("zh");System.out.println("Locale(\"zh\"):" + locale2);// (3)等同于Locale("zh", "CN")Locale locale3 = Locale.CHINA;System.out.println("Locale.CHINA:" + locale3);// (4)等同于Locale("zh")Locale locale4 = Locale.CHINESE;System.out.println("Locale.CHINESE:" + locale4);// (5)获取本地系统默认的本地化对象Locale locale5 = Locale.getDefault();System.out.println("Locale.getDefault():" + locale5);}
}

运行结果:

Locale("zh", "CN"):zh_CN
Locale("zh"):zh
Locale.CHINA:zh_CN
Locale.CHINESE:zh
Locale.getDefault():zh_CN
  • 用户既可以同时制定语言和国家/地区参数来定义一个本地化对象,如(1)
  • 也可以仅通过语言参数定义一个泛本地化对象,如(2)
  • Locale类中通过静态常量定义可一些常用的本地化对象,可以直接引用常量返回本地化对象,如(3)(4)。 具体可查看Locale源码
  • 此外用户还可以获取系统默认的本地化对象,如(5)

如果用户希望改变系统默认的本地化设置,可以在启动JVM时通过命令参数指定

java -Duser.language=en -Duser.regin=US LocaleTest 

在IDE中,可以如下设置

运行一下:

Locale("zh", "CN"):zh_CN
Locale("zh"):zh
Locale.CHINA:zh_CN
Locale.CHINESE:zh
Locale.getDefault():en_US

可以看到Locale.getDefault() 已经是 en_US了。


本地化工具类

JDK的java.util包中提供了几个支持本地化的格式化操作工具类,比如NumberFormat、DateFormat、MessageFormat。

下面我们来看下具体的用法

NumberFormat / DateFormat

package com.xgj.ioc.i18n.tools;import java.text.DateFormat;
import java.text.NumberFormat;
import java.util.Date;
import java.util.Locale;public class FormatToolTest {public static void main(String[] args) {// 中文本地化信息Locale locale = Locale.CHINA;NumberFormat numberFormat = NumberFormat.getCurrencyInstance(locale);double amt = 123456.78;System.out.println(numberFormat.format(amt));// 英文本地化信息Locale locale2 = Locale.US;NumberFormat nFormat = NumberFormat.getCurrencyInstance(locale2);double amt2 = 123456.78;System.out.println(nFormat.format(amt2));// 英文本地化信息Locale locale3 = new Locale("en", "US");Date date = new Date();// 按照本地化的方式对日期进行格式化操作DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.MEDIUM,locale3);System.out.println(dateFormat.format(date));// 中文本地化信息Locale locale4 = new Locale("zh", "CN");Date date2 = new Date();// 按照本地化的方式对日期进行格式化操作DateFormat dateFormat2 = DateFormat.getDateInstance(DateFormat.MEDIUM,locale4);System.out.println(dateFormat2.format(date2));}
}

运行结果:

¥123,456.78
$123,456.78
Aug 10, 2017
2017-8-10

MessageFormat

MessageFormat在NumberFormat和DateFormat的基础上提供了强大的占位符字符串的格式化功能,支持时间、货币、数字以及对象属性的格式化操作。

package com.xgj.ioc.i18n.tools;import java.text.MessageFormat;
import java.util.GregorianCalendar;
import java.util.Locale;public class MessageFormatToolTest {public static void main(String[] args) {// (1)格式化信息串String pattern1 = "{0},你好!你与{1}支付了货款{2}元";String pattern2 = "At {1,time,short} on {1,date,long},{0} paid {2,number,currency}";// (2)用于动态替换占位符的参数Object[] params = { "XiaoGongJiang", new GregorianCalendar().getTime(),200 };// (3)使用默认的本地化对象格式化信息String msg1 = MessageFormat.format(pattern1, params);// (4)使用指定的本地化对象格式化信息MessageFormat messageFormat = new MessageFormat(pattern2, Locale.US);String msg2 = messageFormat.format(params);System.out.println(msg1);System.out.println(msg2);}
}

运行结果

XiaoGongJiang,你好!你与17-8-10 下午2:04支付了货款200元
At 2:04 PM on August 10, 2017,XiaoGongJiang paid $200.00

分析:

  • pattern1是简单形式的格式化信息串,通过{n}占位符指定动态参数的替换位置索引,{0}表示第一个参数,{1}表示第二个参数,以此类推。

  • pattern2格式化信息串比较复杂一些,除参数位置索引外,还指定了参数的类型和样式。从pattern2中可以看出格式化信息串的语法是很灵活的,一个参数甚至可以出现在两个地方:如{1,time,short}表示从第二个入参中获取时间部分的值,显示为短样式时间;而{1,date,long}表示从第二个入参中获取日期部分的值,显示为长样式时间

  • 在(2)处,定义了用于替换格式化占位符的动态参数,这里,我们使用到了JDK5.0自动装包的语法,否则必须采用封装类表示基本类型的参数值。

  • 在(3)处,通过MessageFormat的format()方法格式化信息串。它使用了系统默认的本地化对象,由于我们是中文平台,因此默认为Locale.CHINA

  • 在(4)处,我们显式指定MessageFormat的本地化对象。


ResourceBoundle

如果应用系统中某些信息需要支持国际化功能,则必须为希望支持的不同本地化类型分别提供对应的资源文件,并以规范的方式进行命名。

国际化资源文件的命名规范规定资源名称采用以下的方式进行命名:
  

<资源名>_<语言代码>_<国家/地区代码>.properties

其中,语言代码和国家/地区代码都是可选的.

<资源名>.properties命名的国际化资源文件是默认的资源文件,即某个本地化类型在系统中找不到对应的资源文件,就采用这个默认的资源文件.

<资源名>_<语言代码>.properties命名的国际化资源文件是某一语言默认的资源文件,即某个本地化类型在系统中找不到精确匹配的资源文件,将采用相应语言默认的资源文件。

实例

我们命名资源名称为“resource”。 提供两个国际化信息配置文件

  • 语言为英文,国家为美国,与其对应的本地化资源文件命名为resource_en_US.properties。 内容为:
greeting.common=How are you?
greeting.morning=Good Morning!
greeting.afternoon=Good Afternoon!
  • 语言为中文,国家/地区为中国大陆,与其对应的本地化资源文件为resource_zh_ CN.properties 。 内容为:
greeting.common=\u4F60\u597D\u5417\uFF1F
greeting.morning=\u4E0A\u5348\u597D\uFF01
greeting.afternoon=\u4E0B\u5348\u597D\uFF01

本地化不同的同一资源文件,虽然属性值各不相同,但属性名却是相同的,这样应用程序就可以通过Locale对象和属性名精确调用到某个具体的属性值了。

注意:上面中文的本地化资源文件内容采用了特殊的编码表示中文字符,这是因为资源文件对文件内容有严格的要求:只能包含ASCII字符。所以必须将非ASCII字符的内容转换为Unicode代码的表示方式。

如上面中文的resource_zh_CN.properties资源文件的三个属性值分别是“你好吗?”、“上午好!”和“下午好!”三个中文字符串对应的Unicode代码串。


中文本地化资源文件两种转换方式

如果在应用开发时,直接采用Unicode代码编辑资源文件是很不方便的,所以,通常我们直接使用正常的方式编写资源文件,在测试或部署时再采用工具进行转换。

JDK的native2ascii工具

JDK在bin目录下为我们提供了一个完成此项功能的native2ascii工具,它可以将中文字符的资源文件转换为Unicode代码格式的文件

命令格式如下

 native2ascii [-reverse] [-encoding 编码] [输入文件 [输出文件]]

CMD,进入 native2ascii所在的目录,执行:

native2ascii -encoding utf-8 D:\workspace\workspace-sts\SpringMaster\src\main\resources\i18n\resource_zh_CN.properties 
IDE自带的支持

对于IDE来讲,无须安装任何插件就自然支持资源属性文件的这种编辑方式,比如我用的Spring Tool Suits,输入中文,自动转换为Unicode。


如果应用程序中拥有大量的本地化资源文件,直接通过传统的File操作资源文件显然太过笨拙。Java为我们提供了用于加载本地化资源文件的方便类java.util.ResourceBoundle。

来看下实例:
结合上面的项目结构,加载i18n目录下的名为resource资源文件。

package com.xgj.ioc.i18n.resourceBoundle;import java.util.Locale;
import java.util.ResourceBundle;public class ResourceBoundleTest {public static void main(String[] args) {ResourceBundle resBundle = ResourceBundle.getBundle("i18n/resource",Locale.getDefault());System.out.println(resBundle.getString("greeting.common"));System.out.println(resBundle.getString("greeting.morning"));System.out.println(resBundle.getString("greeting.afternoon"));ResourceBundle resBundle2 = ResourceBundle.getBundle("i18n/resource",Locale.US);System.out.println(resBundle2.getString("greeting.common"));System.out.println(resBundle2.getString("greeting.morning"));System.out.println(resBundle2.getString("greeting.afternoon"));}
}

resBundle加载了默认的本地化资源文件,因为是中文平台,所以是对应中国大陆中文的resource_zh_CN.properties资源文件。

resBundle2 加载了对应美国英语本地化的resource_en_US.properties资源文件。

运行结果:

你好吗?
上午好!
下午好!
How are you?
Good Morning!
Good Afternoon!

ResourceBundle加载资源的顺序

ResourceBundle在加载资源时,如果指定的本地化资源文件不存在,它按以下顺序尝试加载其他的资源:本地系统默认本地化对象对应的资源→默认的资源

举例:
假设我们使用ResourceBundle.getBundle(“i18n/resource”,Locale.CANADA)加载加拿大的本地资源文件,由于不存在resource_en_CA.properties资源文件,它将尝试加载resource_zh_CN.properties的资源文件(中文平台,默认是中文本地化资源文件),假设resource_zh_CN.properties资源文件也不存在,它将继续尝试加载resource.properties的资源文件,如果这些资源都不存在,将抛出java.util.MissingResourceException异常。


在资源文件中使用格式化串

在上面的资源文件中,属性值都是一般的字符串,它们不能结合运行时的动态参数构造出灵活的信息,而这种需求是很常见的。要解决这个问题,只须使用带占位符的格式化串作为资源文件的属性值并结合使用MessageFormat就可以满足要求了。

下面我们来改造下资源文件,通过格式化串让问候语更具个性化:

fmt_resource_en_US.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_zh_CN.properties:

greeting.common=\u4F60\u597D\u5417{0}\uFF1F\u3002\u4ECA\u5929\u662F{1}
greeting.morning=\u65E9\u4E0A\u597D{0}\uFF01\u73B0\u5728\u662F{1,time,short}
greeting.afternoon=\u4E0B\u5348\u597D{0}\uFF01\u73B0\u5728\u662F{1,date,long}

下面使用ResourceBoundle和MessageFormat来操作资源文件

package com.xgj.ioc.i18n.resourceBoundle;import java.text.MessageFormat;
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.ResourceBundle;public class ResourceBoundleWithFormatTest {public static void main(String[] args) {// 加载本地资源ResourceBundle reBundle1 = ResourceBundle.getBundle("i18n/fmt_resource", Locale.CHINA);ResourceBundle reBundle2 = ResourceBundle.getBundle("i18n/fmt_resource", Locale.US);Object[] params = { "XiaoGongJiang", new GregorianCalendar().getTime() };// 用本地化对象进行格式化String greetingCommonCH = new MessageFormat(reBundle1.getString("greeting.common"), Locale.CHINA).format(params);String greetingMorningCH = new MessageFormat(reBundle1.getString("greeting.morning"), Locale.CHINA).format(params);String greetingAfternoonCH = new MessageFormat(reBundle1.getString("greeting.afternoon"), Locale.CHINA).format(params);System.out.println(greetingCommonCH);System.out.println(greetingMorningCH);System.out.println(greetingAfternoonCH);String greetingCommonEN = new MessageFormat(reBundle2.getString("greeting.common"), Locale.US).format(params);String greetingMorningEN = new MessageFormat(reBundle2.getString("greeting.morning"), Locale.US).format(params);String greetingAfternoonEN = new MessageFormat(reBundle2.getString("greeting.afternoon"), Locale.US).format(params);System.out.println(greetingCommonEN);System.out.println(greetingMorningEN);System.out.println(greetingAfternoonEN);}
}

运行结果:

你好吗XiaoGongJiang?。今天是17-8-10 下午3:44
早上好XiaoGongJiang!现在是下午3:44
下午好XiaoGongJiang!现在是2017年8月10日
How are you XiaoGongJiang?,today is 8/10/17 3:44 PM
Good Morning XiaoGongJiang! now is 3:44 PM
Good Afternoon XiaoGongJiang! now is August 10, 2017

Spring-国际化信息01-基础知识相关推荐

  1. 目前人们把通用计算机,计算机与信息社会基础知识测试题.doc

    计算机与信息社会基础知识测试题 计算机与信息社会基础知识测试题2011级信科1班 刘巍(选择题6~10 填空题6~11)陈军(选择题11~16 填空题12~16) 陈阳(选择题1~5 填空题1~5) ...

  2. PLC编程入门-01基础知识介绍

    PLC编程入门-01基础知识介绍 PLC的组成结构 PLC编程语言: PLC输入输出的特点 输入 输出 PLC的组成结构 简图 明细图 CPU:控制器和运算器本身就是CPU主要组成部分,和PC的CPU ...

  3. C语言基础-01 基础知识

    一.C语言的特点 二.最简单的C语言程序 1.基础知识 (1)scanf: 输入,从命令行将用户输入的值,保存到变量中. int x = 0: scanf("%d" ,&x ...

  4. python编程01 -- 基础知识

    简介 本文主要对运用的python语言知识进行归纳和回顾使用,不定期更新,主要是对语言特性.数据类型.语句块.函数.类.模块.错误.线程.进程等内容的积累 python2/python3 核心类差异 ...

  5. Spring IOC和MVC基础知识

    (1)SpringBoot分析 – Spring IOC原理解析 IOC,控制反转 Spring,避免那些可能致使代码变得繁杂.混乱的大量业务工具组合在一起,包括它的创建与销毁,等等,会帮助你进行管理 ...

  6. 人工智能 ---(01.基础知识)

    前言:小编开始进入人工智能的学习了,写博客的原因是想记录一下自己的学习日常,将博客内容作为自己的一份笔记.由于小编也是初学者,对于相关理论可能理解的不是很透彻,自身的理解可能不充分,望各位读者见谅(部 ...

  7. 【Spring Boot】1.基础知识

    2019独角兽企业重金招聘Python工程师标准>>> 前言 该相关文档其实是学习一段名为"尚硅谷Spring Boot的学习视频"的过程中所做的笔记,教导老师讲 ...

  8. python基础知识笔记简书_Python学习笔记01——基础知识

    Python常用数据类型: 整数(int),浮点数(float),字符串(str) 布尔型(True,False),空值(None) 列表(list):一种有序集合,可以随时添加删除其中的元素. cl ...

  9. 其实就是为了能有字幕特效,用MeGUI + AVS压制PSP MP4AVC视频01 - 基础知识篇

    A.需要准备的软件: .net framework 2.0 运行库(下面两个软件都是.net写的) MeGUI(AVS等软件的集合GUI) Lite MP4 Tool(批处理AVS转换的GUI) 通用 ...

  10. GNN 系列:Graph 基础知识介绍

    点击上方"Datawhale",选择"星标"公众号 第一时间获取价值内容 [导读]图卷积神经网络(Graph Convolutional Network)作为最 ...

最新文章

  1. CF20C Dijkstra?( Dijkstra!练手)难度⭐⭐⭐
  2. AWS — AWS ECS
  3. 龙格-库塔(Runge-Kutta)方法数学原理及实现
  4. Centos 7 上 查看MySQL当前使用的配置文件my.cnf的方法
  5. Flow Problem
  6. ubuntu linux 批量部署,使用Cobbler批量部署Linux和Windows:CentOS/Ubuntu批量安装(二)...
  7. zabbix在ubuntu16.04上的安装
  8. 其他——SPSS做线性回归分析最好的例子
  9. 微信小程序在线考试项目开发-用户授权登录、身份信息获取
  10. 从不跑步到无间断跑步1年感受
  11. nacos启动后CPU使用率过高
  12. 三级等保 mysql8.0.24密码策略设置
  13. Me-tetrazine-Disulfo-Cyanine5,甲基四嗪-磺酸基菁染料Cy5,蓝色固体
  14. 2021威海高考成绩查询电话,2021威海高考成绩查询系统
  15. 2021 ICPC Southeastern Europe Regional Contest 树上dfs+思维
  16. adonis 开发 01
  17. 记录一遍易语言调用java
  18. 地图采集小白日赚100+卖网红美食教程月入5W+(15个热门项目)
  19. Unity 实战项目 ☀️| 实现“嫦娥奔月“小动画,一起来看看这 ‘漂亮‘的嫦娥 吧【仅供娱乐】
  20. htk的使用Hcopy.exe的ERROR [+6311]和ERROR [+1014]报错解决

热门文章

  1. pymysql dataframe 写入sql
  2. 网易2020校招笔试编程题回顾
  3. R语言实战应用-lightgbm 算法优化:不平衡二分类问题(附代码)
  4. 从无到有算法养成篇-线性表历练
  5. 强化学习(六)时序差分在线控制算法SARSA
  6. 支持向量机SVM原理(一)
  7. linux vim编辑kconfig 无法wq,编译linux-3.15.5时遇到的几个错误
  8. 塞尔达传说gba_回顾 | 猹鱼主题速写:塞尔达传说 英国绅士
  9. 唯品会Java核心项目VJTools开源了
  10. git fetch和git pull之间的区别--转载