美文网首页区块链入门
WEB网站国际化的一种解决方案

WEB网站国际化的一种解决方案

作者: star__light | 来源:发表于2018-03-14 11:59 被阅读1628次

    场景

    这里简单用一个详情页面开始我们的国际化讲解

    国际化页面布局.png
    这个场景中,logo需要国际化,tab以及面包屑的文字需要国际化,详情需要国际化,动态详情以及动态详情中的文字需要国际化。
    经过总结,国际化数据会有四种类型
    • 后台管理配置的动态数据
    • 服务端渲染的静态的文字
    • js渲染的静态文字
    • 静态的图片

    后台管理配置的动态数据

    场景图中详情数据是通过一个后台管理系统管理,数据通过语言隔离的方式管理,接口设计大致如下
    语言管理

    创建语种 [POST] /m/languages
    更新语种 [PUT] /m/languages/{id}
    查询语种 [GET] /c/languages/{id}
    查询语种列表 [GET] /c/languages?$offset=偏移量&$limit=数量&$count=true&state=1
    

    数据管理

    创精文章 [POST] /m/languages/{language_id}/articles
    更新文章 [PUT] /m/languages/articles/{article_id}
    删除文章 [DELETE] /m/languages/articles/{article_id}
    查询文章 [GET] /c/languages/articles/{article_id}
    查询文章列表 [GET]/c/languages/{language_id}/articles?$offset=偏移量&$limit=数量&$count=true
    

    服务端渲染的静态的文字

    如场景图中面包屑,比如面包屑文字首页->详情, 像这种固定的文字不适合在后台管理由运维人员配置。用文件统一存储这些国际化的文件比较合适。这里采用SpringMVC自带的国际化解决方案。
    配置ResourceBundleMessageSource

    @Configuration
    public class I18nConfig {
        @Bean
        public ResourceBundleMessageSource messageSource() {
            ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
            messageSource.setBasename("i18n");
            messageSource.setUseCodeAsDefaultMessage(true);
            messageSource.setDefaultEncoding("UTF-8");
            return messageSource;
        }
    }
    

    基于Cookie的国际化实现

     @Bean
     public CookieLocaleResolver localeResolver() {
       CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver();
       cookieLocaleResolver.setCookieName("lang");
       return cookieLocaleResolver;
     }
    

    SpringMVC国际化的的resolver有很多,用法也很多样,可以参考这篇博客,这里就不造轮子了()

    国际化语言拦截器

    @Component
    public class I18nInterceptor extends HandlerInterceptorAdapter {
        public static final String DEFAULT_PARAM_NAME = "lang";
    
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
                throws ServletException {
    
            String newLocale = request.getParameter(DEFAULT_PARAM_NAME);
            if (newLocale != null) {
                LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
                if (localeResolver == null) {
                    throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
                }
                localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
            }
            // Proceed in any case.
            return true;
        }
    }
    

    这里拦截器显示多语言路由的实现是通过改变参数来实现语言切换

    http://i18n.example.com?lang=en
    http://i18n.example.com?lang=cn
    

    费些功夫通过改写这个拦截器的实现以及路由的设计,可以把国际化的路由改写成这样子

    http://i18n.example.com/en
    http://i18n.example.com/cn
    

    在resources中配置配置国际化语言文件

    i18n.properties    默认
    i18n_en.properties 英文
    i18n_cn.properties 中文
    

    添加el表达式

    public static String i18n(String key) {
      RequestContext requestContext = new RequestContext(SpringUtil.getRequest());
      return requestContext.getMessage(key);
    }
    在tld配置
    <function>
        <description>国际化</description>
        <name>i18n</name>
        <function-class>com.example.utils.ElFuncUtil
        </function-class>
        <function-signature>java.lang.String i18n(java.lang.String))</function-signature>
        <example>${elf:i18n(key)}</example>
      </function>
    

    使用

    <span>${elf:i18n("详情")}</span>
    

    很遗憾,Spring自带的国际化方案有一个缺陷:配置文件是内置在项目代码中的,无法剥离到后台统一管理,这样子如果新增一种语言,就必须动到项目代码。
    有能力的同学可以尝试改写ResourceBundleMessageSource,能支持读取远端的配置文件,这样就完美了。

    js渲染的静态的文字

    场景图中动态推荐部分是用js渲染出来的,其中会出现全部等一些静态的文本。这些文本也需要国际化。我在项目中使用现在最受欢迎的js框架vue。
    配合使用(vue-i18n)[http://kazupon.github.io/vue-i18n/en/started.html]进行国际化。
    引入vue-i18n

    import Vue from 'vue'
    import VueI18n from 'vue-i18n'
    import messages from './message.json'
    import { langCode } from '../lang'
    
    Vue.use(VueI18n)
    
    export default new VueI18n({
      locale: langCode,
      messages
    })
    

    message.json

    "cn": {
      "全部": "全部"
    },
    "en": {
      "全部": "All"
    }
    

    使用

    vueI18n.t('全部')
    // 或者,在template模板中
    <p>{{ $t("全部") }}</p>
    

    静态的图片

    场景图中的logo根据不同语言也需要不同,这样的图片需要直接其访问其图片路径,我们约定图片的访问路径规则。

    <img src="/images/logo_${lang}.svg" onerror='this.src="${ctx}/images/logo_en.svg"'/>
    

    抽取配置的自动化脚本

    国际化的文本处于各个代码文件中,手动拷贝到配置文件是一件效率相当底下且容易出错的事情。故写个自动化脚本溜起来。
    抽取国际化文本成json文件的自动化脚本实现
    抽取国际化文本成properties文件的自动化脚本实现
    把properties中的文件转移到xlsx文件中的自动化脚本实现

    结语

    随着咱国家的国力不断强盛,国际影响力不断扩大。会有更多更好的产品走向世界,国际化已经成为势不可挡的趋势。

    相关文章

      网友评论

      • 9f16060300b7:自动化脚本的链接可以给一个吗
        下面的三个链接全挂了

      本文标题:WEB网站国际化的一种解决方案

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