Spring国际化

转载:http://blog.csdn.net/gaogaoshan/article/details/21227079

java基础MessageFormat

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

MessageFormat在NumberFormat和DateFormat的基础上提供了强大的占位符字符串的格式化功能,它支持时间、货币、数字以及对象属性的格式化操作。下面的实例演示了一些常见的格式化功能:

    //①信息格式化串  
    String pattern1 = "{0},你好!你于{1}在工商银行存入{2} 元。";  
    String pattern2 = "At {1,time,short} On{1,date,long},{0} paid {2,number, currency}.";  

    //②用于动态替换占位符的参数  
    Object[] params = {"John", new GregorianCalendar().getTime(),1.0E3};  

    //③使用默认本地化对象格式化信息  
    String msg1 = MessageFormat.format(pattern1,params);   

    //④使用指定的本地化对象格式化信息  
    MessageFormat mf = new MessageFormat(pattern2,Locale.US);   
    String msg2 = mf.format(params);  
    System.out.println(msg1);  
    System.out.println(msg2);  

pattern1是简单形式的格式化信息串,通过{n}占位符指定动态参数的替换位置索引,{0}表示第一个参数,{1}表示第二个参数,以此类推。
pattern2格式化信息串比较复杂一些,除参数位置索引外,还指定了参数的类型和样式。从pattern2中可以看出格式化信息串的语法是很灵活的,一个参数甚至可以出现在两个地方:如 {1,time,short}表示从第二个入参中获取时间部分的值,显示为短样式时间;而{1,date,long}表示从第二个入参中获取日期部分的值,显示为长样式时间。关于MessageFormat更详细的使用方法,请参见JDK的Javadoc。

在②处,定义了用于替换格式化占位符的动态参数,这里,我们使用到了JDK5.0自动装包的语法,否则必须采用封装类表示基本类型的参数值。
在③处,通过MessageFormat的format()方法格式化信息串。它使用了系统默认的本地化对象,由于我们是中文平台,因此默认为Locale.CHINA。

在④处,我们显式指定MessageFormat的本地化对象。

运行上面的代码,输出以下信息:
引用

John,你好!你于07-1-8 下午9:58在工商银行存入1,000元。
At 9:58 PM OnJanuary 8, 2007,John paid $1,000.00.

国际化

资源文件定义

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

<资源名><语言代码><国家/地区代码>.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=\u60a8\u597d\uff01
greeting.morning=\u65e9\u4e0a\u597d\uff01
greeting.afternoon=\u4e0b\u5348\u597d\uff01

ResourceBoundle

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

代码清单5-16 ResourceBoundle

    ResourceBundle rb1 = ResourceBundle.getBundle("com/baobaotao/i18n/resource", Locale.US);  
    ResourceBundle rb2 = ResourceBundle.getBundle("com/baobaotao/i18n/resource", Locale.CHINA);  
    System.out.println("us:"+rb1.getString("greeting.common"));  
    System.out.println("cn:"+rb2.getString("greeting.common"));  

rb1加载了对应美国英语本地化的resource_en_US.properties资源文件;而rb2加载了对应中国大陆中文的resource_zh_CN.properties资源文件。运行上面的代码,将输出以下信息:
引用

us:How are you!
cn:您好!

加载资源文件时,如果不指定本地化对象,将使用本地系统默认的本地化对象。所以,在中文系统中,ResourceBundle.getBundle(“com/baobaotao/i18n/resource”)语句也将返回和代码清单5-14中rb2相同的本地化资源。

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

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

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中,按照同样的方式编写对应的中文本地化资源文件fmt_resource_zh_CN.properties。
下面,我们联合使用ResourceBoundle和MessageFormat得到美国英文的本地化问候语:

代码清单5-17 资源文件格式化串处理

     //①加载本地化资源  
    ResourceBundle rb1 = ResourceBundle.getBundle("com/baobaotao/i18n/fmt_ resource",Locale.US);   
    ResourceBundle rb2 = ResourceBundle.getBundle("com/baobaotao/i18n/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);  

运行以上的代码,将输出以下信息:

How are you!John,today is 1/9/07 4:11 PM 早上好!John,现在是下午4:11
下午好!John,现在是2007年1月9日

spring 国际化MessageSource

MessageSource的类结构

MessageSource分别被HierarchicalMessageSource和ApplicationContext接口扩展
HierarchicalMessageSource接口最重要的两个实现类是ResourceBundleMessageSource和ReloadableResourceBundleMessageSource。它们基于Java的ResourceBundle基础类实现,允许仅通过资源名加载国际化资源。ReloadableResourceBundleMessageSource提供了定时刷新功能,允许在不重启系统的情况下,更新资源的信息。StaticMessageSource主要用于程序测试,它允许通过编程的方式提供国际化信息。而DelegatingMessageSource是为方便操作父MessageSource而提供的代理类。

ResourceBundleMessageSource

代码清单5-18 通过ResourceBundleMessageSource配置资源

 <bean id="myResource"  
    class="org.springframework.context.support.ResourceBundleMessageSource">  
        <!--①通过基名指定资源,相对于类根路径-->  
        <property name="basenames">    
           <list>  
              <value>com/baobaotao/i18n/fmt_resource</value>  
           </list>  
        </property>  
      </bean>   

代码清单5-19 访问国际化消息:ResourceBundleMessageSource

    String[] configs = {"com/baobaotao/i18n/beans.xml"};  
    ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);  

    //①获取MessageSource的Bean  
    MessageSource ms = (MessageSource)ctx.getBean("myResource");   
    Object[] params = {"John", new GregorianCalendar(). getTime()};  

    //②获取格式化的国际化信息  
    String str1 = ms.getMessage("greeting.common",params,Locale.US);  
    String str2 = ms.getMessage("greeting.morning",params,Locale.CHINA);  
    String str3 = ms.getMessage("greeting.afternoon",params,Locale.CHINA);  
    System.out.println(str1);  
    System.out.println(str2);  
    System.out.println(str3);  

比较代码清单5-19中的代码,我们发现最主要的区别在于我们无须再分别加载不同语言、不同国家/地区的本地化资源文件,仅仅通过资源名就可以加载整套的国际化资源文件。此外,我们无须显式使用MessageFormat操作国际化信息,仅通过MessageSource# getMessage()方法就可以完成操作了。这段代码的运行结果与代码清单5 17的运行结果完全一样。

ReloadableResourceBundleMessageSource

前面,我们提到该实现类比之于ResourceBundleMessageSource的唯一区别在于它可以定时刷新资源文件,以便在应用程序不重启的情况下感知资源文件的变化。很多生产系统都需要长时间持续运行,系统重启会给运行带来很大的负面影响。这时,通过该实现类就可以解决国际化信息更新的问题。请看下面的配置:

代码清单5-20 通过ReloadableResourceBundleMessageSource配置资源

    <bean id="myResource"   
    lass="org.springframework.context.support. ReloadableResourceBundleMessageSource">  
       <property name="basenames">  
          <list>  
            <value>com/baobaotao/i18n/fmt_resource</value>  
          </list>  
       </property>  
       <!--① 刷新资源文件的周期,以秒为单位-->  
       <property name="cacheSeconds" value="5"/>   
     </bean>  

在上面的配置中,我们通过cacheSeconds属性让ReloadableResourceBundleMessageSource每5秒钟刷新一次资源文件(在真实的应用中,刷新周期不能太短,否则频繁的刷新将带来性能上的负面影响,一般不建议小于30分钟)。cacheSeconds默认值为-1表示永不刷新,此时,该实现类的功能就蜕化为ResourceBundleMessageSource的功能。
代码清单5-21 刷新资源:ReloadableResourceBundleMessageSource

  String[] configs = {"com/baobaotao/i18n/beans.xml"};  
    ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);  

    MessageSource ms = (MessageSource)ctx.getBean("myResource");  
    Object[] params = {"John", new GregorianCalendar().getTime()};  

    for (int i = 0; i < 2; i++) {  
        String str1 = ms.getMessage("greeting.common",params,Locale.US);      
        System.out.println(str1);  
        Thread.currentThread().sleep(20000); //①模拟程序应用,在此期间,我们更改资源文件   
    }  

在①处,我们让程序睡眠20秒钟,在这期间,我们将fmt_resource_zh_CN.properties资源文件的greeting.common键值调整为:

—How are you!{0},today is {1}—

我们将看到两次输出的格式化信息分别对应更改前后的内容,也即本地化资源文件的调整被自动生效了:

How are you!John,today is 1/9/07 4:55 PM
—How are you!John,today is 1/9/07 4:55 PM—

容器级的国际化信息资源

在如图5-7所示的MessageSource类图结构中,我们发现ApplicationContext实现了MessageSource的接口。也就是说ApplicationContext的实现类本身也是一个MessageSource对象。

将ApplicationContext和MessageSource整合起来,乍一看挺让人费解的,Spring这样设计的意图究竟是什么呢?原来Spring认为:在一般情况下,国际化信息资源应该是容器级。我们一般不会将MessageSource作为一个Bean注入到其他的Bean中,相反MessageSource作为容器的基础设施向容器中所有的Bean开放。只要我们考察一下国际化信息的实际消费场所就更能理解Spring这一设计的用意了。国际化信息一般在系统输出信息时使用,如Spring MVC的页面标签,控制器Controller等,不同的模块都可能通过这些组件访问国际化信息,因此Spring就将国际化消息作为容器的公共基础设施对所有组件开放。

既然一般情况下我们不会直接通过引用MessageSource Bean使用国际信息,那如何声明容器级的国际化信息呢?我们其实在5.1.1节讲解Spring容器的内部工作机制时已经埋下了伏笔:在介绍容器启动过程时,我们通过代码清单5-1对Spring容器启动时的步骤进行剖析,④处的initMessageSource()方法所执行的工作就是初始化容器中的国际化信息资源:它根据反射机制从BeanDefinitionRegistry中找出名称为“messageSource”且类型为org.springframework.context.MessageSource的Bean,将这个Bean定义的信息资源加载为容器级的国际化信息资源。请看下面的配置:

代码清单5-22 容器级资源的配置

    <!--①注册资源Bean,其Bean名称只能为messageSource -->  
    <bean id="messageSource"   
          class="org.springframework.context.support.ResourceBundleMessageSource">  
      <property name="basenames">  
         <list>  
           <value>com/baobaotao/i18n/fmt_resource</value>  
         </list>  
      </property>  
    </bean>  

下面,我们通过ApplicationContext直接访问国际化信息,如代码清单5 23所示:

代码清单5-23 通过ApplicationContext访问国际化信息

 String[] configs = {"com/baobaotao/i18n/beans.xml"};  
    ApplicationContext ctx = new ClassPathXmlApplicationContext(configs);  
    //①直接通过容器访问国际化信息  
    Object[] params = {"John", new GregorianCalendar().getTime()};  

    String str1 = ctx.getMessage("greeting.common",params,Locale.US);  
    String str2 = ctx.getMessage("greeting.morning",params,Locale.CHINA);     
    System.out.println(str1);  
    System.out.println(str2);  

运行以上代码,输出以下信息:

How are you!John,today is 1/9/07 5:24 PM 早上好!John,现在是下午5:24

假设MessageSource Bean名字没有命名为“messageSource”,以上代码将抛出NoSuchMessageException异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring的i18n国际化功能可以通过配置properties资源文件来实现。通常,我们会在src/main/resources目录下创建一个i18n文件夹,并在其中创建各类语言的properties资源文件,例如i18n/messages.properties、i18n/messages_en_US.properties、i18n/messages_zh_CN.properties等。\[1\] 在配置文件中,我们可以使用yaml格式进行配置。例如,可以使用spring.messages.basename属性来指定properties文件的路径,如spring.messages.basename: i18n.login。这样,Spring就会根据配置的路径去读取相应的国际化资源文件。\[2\] 另外,如果你在前端使用jQuery,你也可以使用jQuery.i18n.properties插件来实现国际化。该插件可以根据用户指定的语言和国家编码来解析对应的.properties资源文件,从而实现前端的国际化功能。\[3\] #### 引用[.reference_title] - *1* [spring中i18n国际化处理多语言](https://blog.csdn.net/shenyunsese/article/details/128326378)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [SpringBoot -> 国际化(i18n)](https://blog.csdn.net/rod0320/article/details/110086280)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [Spring国际化i18n](https://blog.csdn.net/daobuxinzi/article/details/127982064)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值