美文网首页
springMVC项目进行国际化改造

springMVC项目进行国际化改造

作者: Ray昱成 | 来源:发表于2018-01-25 17:09 被阅读0次

    1. 概述

    1.1名词定义

    i18n(其来源是英文单词 internationalization的首末字符i和n,18为中间的字符数)是“国际化”的简称。在资讯领域,国际化(i18n)指让产品(出版物,软件,硬件等)无需做大的改变就能够适应不同的语言和地区的需要。对程序来说,在不修改内部代码的情况下,能根据不同语言及地区显示相应的界面。 在全球化的时代,国际化尤为重要,因为产品的潜在用户可能来自世界的各个角落。通常与i18n相关的还有L10n(“本地化”的简称)。

    1.2 多语言的原则

    笔者认为,在对我们已有系统进行多语言改造,应当遵循几个原则:

    1)尽可能不改动内部代码逻辑,仅仅是在vm模板中进行更改。这样可以避免在上层改动造成逻辑上的错误;

    2)对于不可预知的、没有正确配置翻译文案的字段,在进行翻译函数处理时,直接显示原语言,确保不会出错。

    1.3 对今后需要多语言的系统的建议

    1)禁止文案硬编码在java代码中

    例如:如果一定要写入静态文本,也建议做成枚举,在Controller放入错误提示信息时也应当说明可能会出现哪些错误提示。

    2)各个系统使用枚举时,一些公用的枚举,应当保持一致

    2. 多语言的流程

    3.多语言的配置

    3.1 资源文件绑定器

    <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource" 
        p:basenames="file:${prod_ui_template}/config/i18n/icfmng"
        p:useCodeAsDefaultMessage="true"
        p:defaultEncoding="UTF-8"
        p:cacheSeconds="600"/>
    

    3.2 拦截器的配置

    <bean id="localeChangeInterceptor" class="XXXXXX.XXXX.IcfmngLocaleChangeInterceptor">
            <property name="paramName" value="locale"/>
            <property name="enableLocales">
                <list>
                    <value>en_US</value>
                    <value>zh_CN</value>
                </list>
            </property>
        </bean> 
    
    public class IcfmngLocaleChangeInterceptor extends LocaleChangeInterceptor {
        
        /** 参数名称 */
        private String       paramName     = DEFAULT_PARAM_NAME;
    
        /** 默认语言 */
        private String       defaultLocale = "zh_CN";
    
        /** 支持的语言*/
        private List<String> enableLocales = new ArrayList<String>();
        
        /**
         * 
         * @see org.springframework.web.servlet.i18n.LocaleChangeInterceptor#preHandle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object)
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
                                 Object handler) throws ServletException {
            String newLocale = request.getParameter(paramName);
            if (newLocale != null) {
                
                if (!enableLocales.contains(newLocale)) {
                    newLocale = defaultLocale;
                }
                LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
                if (localeResolver == null) {
                    throw new IllegalStateException(
                        "No LocaleResolver found: not in a DispatcherServlet request?");
                }
                LocaleEditor localeEditor = new LocaleEditor();
                localeEditor.setAsText(newLocale);
                localeResolver.setLocale(request, response, (Locale) localeEditor.getValue());
            }
            // Proceed in any case.
            return true;
        }
        
        /**
         * 
         * @param enableLocales
         */
        public void setEnableLocales(List<String> enableLocales) {
            this.enableLocales = enableLocales;
        }
    }
    

    用户切换语言的时候客户端发送get请求,local=en_US 或者 local=zh_CN 跟在url后,拦截器拦截到用户请求后,作出相应的相应。

    3.3 LocaleResolver的配置

    localResolver 为区域解析器,用户的区域是通过区域解析器来识别的,它必须实现localResolver接口。Spring MVC提供了几个LocaleResolver实现,让你可以按照不同的条件来解析区域。除此之外,你还可以实现这个接口,创建自己的区域解析器。

    要定义一个区域解析器,只需在web应用程序上下文中注册一个LocaleResolver类型的Bean就可以了。你必须将区域解析器的Bean名称设置为localeResolver,这样DispatcherServlet才能自动侦测到它。请注意,每DispatcherServlet只能注册一个区域解析器。

    一般来说可以选择基于 cookie级别的国际化(locale存cookie)或者基于session级别的国际化(locale存session),即可以从以下两个类继承:

    org.springframework.web.servlet.i18n.CookieLocaleResolver

    org.springframework.web.servlet.i18n.SessionLocaleResolver

    这里我们以基于cookie的国际化为例。
    

    1) 增加区域解析器的配置

    <bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver">

          <property name="cookieName" value="locale"/>
    
          <property name="defaultLocale" value="zh_CN"/>
    
      </bean>
    
       在这里可以配置 cookieName 和默认的语言。
    

    3.4 资源文件的规则

    资源文件绑定器指明资源文件的路径和文件名统一的前缀,并且设定了所有的语言选项,至此,资源文件的命名就确定下来。在进行多语言的时候,框架会根据当前的语言选项,自动帮我们找到对应的资源文件进行多语言“翻译”。

    如果需要多语言的字段较多,建议在excel 整理好,再用脚本语言去生成配置文件,这样不容易出错。

    要注意的是,不要在eclipse下修改资源文件,eclipse下打开资源文件是乱码,修改会出错。建议使用其它编辑软件。

    4. 多语言的使用

    完成了多语言的配置后,就可以开始对页面进行多语言啦!在进行多语言的时候,只需要调用getMessage 即将多语言的key映射到对应的多语言翻译的字段。

    4.1 Controller层进行多语言

    在Controller层进行多语言需要先获得web容器上下文 WebApplicationContext,代码示例如下:

    /**
         * 根据key获取多语言value
         * @param key
         * @param arry 填充翻译后的参数
         * @param defult 默认值
         * @return
         */
        public static String getValueByKey(String key, Object[] arry,
                                           String defult) {
            try {
                WebApplicationContext ctx = RequestContextUtils.getWebApplicationContext(request);
                LocaleResolver localeResolver = ctx.getBean("localeResolver", LocaleResolver.class);
                return ctx.getMessage(key, arry, defult, localeResolver.resolveLocale(request));
            } catch (Exception e) {
                ExceptionUtil.caught(e, "根据key获取多语言value值出错|key=", key);
            }
            return defult;
    
        }
    

    在这里获得上下文以后,取出localeResolver这个Bean,解析当前request的语言选项参数,即可调用 ctx.getMessage(key, new Object[] {}, "", locale); 对key值进行多语言的映射,返回对应的多语言字段。

    getMessage方法中,key对应多语言资源文件的键值,第二个参数是用于填充到翻译后的字段的,比如 若翻译后为“当前第{0}页,总共{1}页”
    第二个参数的两个String就可以填充进去。 第三个参数为默认的返回值,即翻译失败时返回这个。第四个参数为当前的语言选项。

    4.2 vm模板中进行多语言

    在vm模板中进行多语言会简单很多,这里建议使用宏来调用getMessage方法,代码如下:

    ## 根据用户的语言选择对 $key进行翻译
    
    ## #macro(t $key, $args , $defaultMessage)
    
    ##   #if($stringUtil.isBlank($args))
    
    ##     #set($args = [])
    
    ##   #end
    
    ##   #if($stringUtil.isBlank($defaultMessage))
    
    ##        #set($defaultMessage = $key)
    
    ##   #end
    
    ##   #SLITERAL($springMacroRequestContext.getMessage($key, $args , $defaultMessage))
    
    ## #end
    
    #macro(t $key, $args , $defaultMessage)#if($stringUtil.isBlank($args))#set($args = [])#end#if($stringUtil.isBlank($defaultMessage))#set($defaultMessage = $key)#end#SLITERAL($springMacroRequestContext.getMessage($key, $args , $defaultMessage))#end
    

    调用t这个宏,第二个参数用于填充,第三个参数为默认返回值,如果第三个参数不填,如果在资源文件中找不到时会返回key。

    在页面vm模板中调用宏:
    #t("COMMON_ORDER_NO") 或者 #t('COMMON_ORDER_NO')

    ---------------------------------分隔线---------------------------------------------------

    至此,多语言的实现原理已经介绍完了,如果你是在新做一个系统,那么一个比较合理的做法应该是:

    Ⅰ 对于静态的字段的多语言,直接在页面vm模板上调用getMessage方法进行多语言映射;
    Ⅱ 对于动态的字段,在Controller层进行多语言。这就需要在写代码的过程中特别注意,任何你需要在前端展示的字段,都不要硬编码写死在程序中,而是使用枚举。

    比如在Controller层中调用了某一方法,这一方法里面可能会抛出异常,而这一异常的错误信息又需要在前端展示,那么切忌将错误信息写死在代码,这会使后期多语言改造非常困难。如果将错误信息写成枚举,那么在Controller中即可根据该枚举取得key值(比方说,我们的做法是把枚举的classname和name拼在一起作为key值),这样就可以很方便地在Controller层进行多语言。

    相关文章

      网友评论

          本文标题:springMVC项目进行国际化改造

          本文链接:https://www.haomeiwen.com/subject/pdgvaxtx.html