WEB網站國際化的一種解決方案

nqdy666發表於2019-03-04

場景

這裡簡單用一個詳情頁面開始我們的國際化講解

國際化頁面佈局.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"`/>
複製程式碼

抽取配置的自動化指令碼

國際化的文字處於各個程式碼檔案中,手動拷貝到配置檔案是一件效率相當底下且容易出錯的事情。故寫個自動化指令碼溜起來。

結語

隨著我們國家的國力不斷強盛,國際影響力不斷擴大。會有更多更好的產品走向世界,國際化已經成為勢不可擋的趨勢。

相關文章