I18N spring 实现国际化

一、查看 java 原生国际化

国际化的核心就是根据语言获取资源包。

二、使用MessageSource 获取数据

ApplicationContext 接口扩展了 MessageSource 接口,因而提供了消息处理的功能(i18n或者国际化)。

1. 它所定义的方法:

String getMessage(String code, Object[] args, String default, Locale loc)

用来从MessageSource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。args中的参数将使用标准类库中的MessageFormat来作消息中替换值。

代码解释:

参数:
code – 要查找的代码,例如“calculator.noRateSet”。鼓励此类的用户将消息名称基于相关的完全限定类名称,从而避免冲突并确保最大程度的清晰度。
args –将为消息中的参数填充的参数数组(参数在消息中看起来像“{0}”、“{1,date}”、“{2,time}”),如果没有则为null .
default – 查找失败时返回的默认消息
locale – 进行查找的区域设置

返回:
如果查找成功,则显示已解决的消息;否则默认消息作为参数传递

String getMessage(String code, Object[] args, Locale loc)

本质上和上一个方法相同,其区别在:没有指定默认值,如果没找到消息,会抛出一个NoSuchMessageException异常。

String getMessage(MessageSourceResolvable resolvable, Locale locale)

上面方法中所使用的属性都封装到一个MessageSourceResolvable实现中,而本方法可以指定MessageSourceResolvable实现。

可以看到,他就是将 java 的国际化进行了封装,由原来的是三步归结为一步,一气呵成。

当一个 ApplicationContext 被加载时,它会自动在 context 中查找已定义为 MessageSource 类型的 bean。此 bean 的名称须为messageSource。如果找到,那么所有对上述方法的调用将被委托给该 bean。否则 ApplicationContext 会在其父类中查找是否含有同名的bean。如果有,就把它作为 MessageSource 。如果它最终没有找到任何的消息源,一个空的 StaticMessageSource 将会被实例化,使它能够接受上述方法的调用。

Spring目前提供了两个MessageSource的实现:ResourceBundleMessageSource和StaticMessageSource。

StaticMessageSource很少被使用,但能以编程的方式向消息源添加消息。ResourceBundleMessageSource会用得更多一些,为此提供了一下示例:

2. 通过 读取 xml 获取 messageSource,直接调用 getMessage

(这儿还没有用到国际化,看 java 实现国际化章节可以知道资源包的命名方式,以下先采用不包含语言环境的命名方式)

<beans>
    <bean id="messageSource"
            class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="basenames">
            <list>
                <value>format</value>
                <value>exceptions</value>
                <value>windows</value>
            </list>
        </property>
    </bean>
</beans>

这段配置假定在你的classpath中有三个资源文件(resource bundle),它们是format, exceptions和windows。通过ResourceBundle,使用JDK中解析消息的标准方式,来处理任何解析消息的请求。出于示例的目的,假定上面的两个资源文件的内容为…

format.properties

message=Alligators rock!

exceptions.properties

argument.required=The {0} argument is required.

因为ApplicationContext实现也都实现了 MessageSource 接口,所以能被转型为MessageSource接口

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory, MessageSource, ApplicationEventPublisher, ResourcePatternResolver

示例:

public static void main(String[] args) {
    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
    String message = resources.getMessage("message", null, "Default", null);
    System.out.println(message);
}

输出结果:

Alligators rock!

总而言之,我们在’beans.xml’的文件中(在classpath根目录下)定义了一个messageSource bean,通过它的 basenames 属性引用多个资源文件;而 basenames 属性值由 list 元素所指定的三个值传入,它们以文件的形式存在并被放置在classpath的根目录下(分别为format.properties,exceptions.properties 和 windows.properties)。

3. 通过依赖注入得到 messageSource,并调用 getMessage

再分析个例子,这次我们将着眼于传递参数给查找的消息,这些参数将被转换为字符串并插入到已查找到的消息中的占位符(译注:资源文件中花括号里的数字即为占位符)

<beans>

    <!-- this MessageSource is being used in a web application -->
    <bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
        <property name="baseName" value="WEB-INF/test-messages"/>
    </bean>
    
    <!-- let's inject the above MessageSource into this POJO -->
    <bean id="example" class="com.foo.Example">
        <property name="messages" ref="messageSource"/>
    </bean>

</beans>
public class Example {

    private MessageSource messages;

    public void setMessages(MessageSource messages) {
        this.messages = messages;
    }

    public void execute() {
        String message = this.messages.getMessage("argument.required",
            new Object [] {"userDao"}, "Required", null);
        System.out.println(message);
    }

}

调用该execute()方法的结果输出如下:

The userDao argument is required.

三、 国际化

关于国际化(“i18n”),Spring 的各种MessageSource 实现遵循与标准 JDK ResourceBundle 相同的区域设置解析和回退规则 。如果希望根据英国(en-GB)语言环境解析消息,创建名为format_en_GB.propertis、exceptions_en_GB.properties 和 windows_en_GB.properties。

1. 读取 xml 获取国际化数据

Locale解析通常由应用程序根据运行环境来指定。出于示例的目的,我们对将要处理的(British)消息手工指定locale参数值。

exceptions_en_GB.properties

argument.required=Ebagum lad, the ''{0}'' argument is required, I say, required.
public static void main(final String[] args) {
    MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
    String message = resources.getMessage("argument.required",
        new Object [] {"userDao"}, "Required", Locale.UK);
    System.out.println(message);
}

结果:

Ebagum lad, the 'userDao' argument is required, I say, required.

MessageSourceAware接口还能用于获取任何已定义的MessageSource引用。任何实现了MessageSourceAware接口的bean将在创建和配置的时候与MessageSource一同被注入。

2. 通过依赖注入获取国际化数据

@Component
public class MessageUtils {

    private static MessageSource messageSource;

    @Autowired
    public void setMessageUtils(MessageSource messageSource) {
        MessageUtils.messageSource = messageSource;
    }

    /**
     * 获取单个国际化翻译值
     */
    public static String get(String msgKey) {
        try {
            return messageSource.getMessage(msgKey, null, LocaleContextHolder.getLocale());
        } catch (Exception e) {
            return msgKey;
        }
    }
}

四、针对 web 应用程序

对于Web应用程序,要实现国际化功能,主要是渲染View的时候,要把各种语言的资源文件提出来,这样,不同的用户访问同一个页面时,显示的语言就是不同的。

@Configuration
public class LocaleConfig {

    //用于设置当前会话的默认的国际化语言。
    @Bean
    public LocaleResolver localeResolver() {
        AcceptHeaderLocaleResolver acceptHeaderLocaleResolver = new AcceptHeaderLocaleResolver();
        acceptHeaderLocaleResolver.setDefaultLocale(Locale.CHINA);
        return acceptHeaderLocaleResolver;
    }

    /**
     * 默认拦截器 其中lang表示切换语言的参数名
     */
    @Bean
    public WebMvcConfigurer localeInterceptor() {
        return new WebMvcConfigurer() {
            @Override
            public void addInterceptors(InterceptorRegistry registry) {
                LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor();
                localeInterceptor.setParamName("lang");
                registry.addInterceptor(localeInterceptor);
            }
        };
    }
}

未完待续。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值