場景
這裡簡單用一個詳情頁面開始我們的國際化講解
這個場景中,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"`/>
複製程式碼
抽取配置的自動化指令碼
國際化的文字處於各個程式碼檔案中,手動拷貝到配置檔案是一件效率相當底下且容易出錯的事情。故寫個自動化指令碼溜起來。
結語
隨著我們國家的國力不斷強盛,國際影響力不斷擴大。會有更多更好的產品走向世界,國際化已經成為勢不可擋的趨勢。