基于springboot i18n國際化后臺多種語言設(shè)置的方式
之前有做過手機(jī)端后臺的國際化,因為手機(jī)統(tǒng)一傳遞了language參數(shù)
所以只要設(shè)置LocaleChangeInterceptor就行了/** * 配置國際化語言 */@Configurationpublic class LocaleConfig extends WebMvcConfigurerAdapter{ /** * 默認(rèn)解析器 其中l(wèi)ocale表示默認(rèn)語言 */ @Bean public LocaleResolver localeResolver() {SessionLocaleResolver localeResolver = new SessionLocaleResolver();localeResolver.setDefaultLocale(Locale.CHINA);return localeResolver; } //springboot1.5 @Override public void addInterceptors(InterceptorRegistry registry) { LocaleChangeInterceptor localeInterceptor = new LocaleChangeInterceptor(); localeInterceptor.setParamName('language'); registry.addInterceptor(localeInterceptor); }}
對于某些特殊的后臺運行代碼,比如定時器,我則使用getByLanguage方法
/** * 國際化工具類 */@Componentpublic class MessageUtils{ private static MessageSource messageSource;static SysErrorLogDao sysErrorLogDao; @Resourcepublic void setSysErrorLogDao(SysErrorLogDao sysErrorLogDao) {MessageUtils.sysErrorLogDao = sysErrorLogDao;}private static Logger logger = LoggerFactory.getLogger(MessageUtils.class); public MessageUtils(MessageSource messageSource) { MessageUtils.messageSource = messageSource; } /** * 獲取單個國際化翻譯值 * @param msgKey * @param defaultMsg * @return */ public static String get(String msgKey, String defaultMsg) {try { return messageSource.getMessage(msgKey, null, LocaleContextHolder.getLocale());} catch (Exception e) {logger.error(e.getMessage(), e);String message = StringUtils.getExceptionStackTraceMessage(e);if(message != null && message.length() > 1000) {message = message.substring(0, 999);}SysErrorLogModel errorLog = new SysErrorLogModel();errorLog.setContent(msgKey);errorLog.setType('messageUtils');errorLog.setCreateDate(new Date());errorLog.setClassName(MessageUtils.class.getName());errorLog.setMessage(message);sysErrorLogDao.save(errorLog); return defaultMsg;} } /** * 獲取多個參數(shù)取代的國際化翻譯值 * @param msgKey * @param defaultMsg * @param arg * @return */ public static String get(String msgKey, String defaultMsg, Object... arg) {try {msgKey = messageSource.getMessage(msgKey, arg, LocaleContextHolder.getLocale()); return msgKey;} catch (Exception e) {logger.error(e.getMessage(), e);String message = StringUtils.getExceptionStackTraceMessage(e);if(message != null && message.length() > 1000) {message = message.substring(0, 999);}SysErrorLogModel errorLog = new SysErrorLogModel();errorLog.setContent(msgKey);errorLog.setType('messageUtils');errorLog.setCreateDate(new Date());errorLog.setClassName(MessageUtils.class.getName());errorLog.setMessage(message);sysErrorLogDao.save(errorLog); return MessageFormat.format(defaultMsg, arg);} } /** * 指定語言獲得單個國際化翻譯值 * @param msgKey * @param defaultMsg * @param language * @return */ public static String getByLanguage(String msgKey, String defaultMsg, String language) { try { Locale locale = new Locale(language);msgKey = messageSource.getMessage(msgKey, null, locale); return msgKey;} catch (Exception e) {logger.error(e.getMessage(), e);String message = StringUtils.getExceptionStackTraceMessage(e);if(message != null && message.length() > 1000) {message = message.substring(0, 999);}SysErrorLogModel errorLog = new SysErrorLogModel();errorLog.setContent(msgKey);errorLog.setType('messageUtils');errorLog.setCreateDate(new Date());errorLog.setClassName(MessageUtils.class.getName());errorLog.setMessage(message);sysErrorLogDao.save(errorLog); return defaultMsg;} } /** * 指定語言獲取多參數(shù)取代的國際化翻譯值 * @param msgKey * @param defaultMsg * @param language * @param arg * @return */ public static String getByLanguage(String msgKey, String defaultMsg, String language, Object... arg) { try { Locale locale = new Locale(language);msgKey = messageSource.getMessage(msgKey, arg, locale); return msgKey;} catch (Exception e) {logger.error(e.getMessage(), e);String message = StringUtils.getExceptionStackTraceMessage(e);if(message != null && message.length() > 1000) {message = message.substring(0, 999);}SysErrorLogModel errorLog = new SysErrorLogModel();errorLog.setContent(msgKey);errorLog.setType('messageUtils');errorLog.setCreateDate(new Date());errorLog.setClassName(MessageUtils.class.getName());errorLog.setMessage(message);sysErrorLogDao.save(errorLog); return MessageFormat.format(defaultMsg, arg);} }}
但是后面又要做網(wǎng)頁的國際化,因為網(wǎng)頁沒有傳遞統(tǒng)一的語言參數(shù),如果要一一添加的話太過麻煩,于是就要用到cookie來保存?zhèn)鬟f語言
這個時候就要實現(xiàn)自己的解析器了public class MyLocaleResolver implements LocaleResolver {@Override public Locale resolveLocale(HttpServletRequest httpServletRequest) {Locale locale = Locale.getDefault();{//通過參數(shù)解析locale,language參數(shù)優(yōu)先String temp = httpServletRequest.getParameter('language');if (!StringUtils.isEmpty(temp)) {locale = new Locale(temp);return locale;}}//得到cookie,解析localeCookie[] cookies = httpServletRequest.getCookies();if(cookies != null) { for (Cookie cookie : cookies) {if (cookie.getName().equals('userLanguage')) { String temp = cookie.getValue(); if (!StringUtils.isEmpty(temp)) {locale = new Locale(temp); } continue;} }}return locale; } @Override public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { }}
@Configurationpublic class LocaleConfig extends WebMvcConfigurerAdapter{ @Bean public LocaleResolver localeResolver() {MyLocaleResolver localeResolver = new MyLocaleResolver();return localeResolver; }}這樣就實現(xiàn)了使用cookie來設(shè)置語言
不過最后還是有所遺漏,因為我們的分布式項目中用到了很多http的內(nèi)部調(diào)用,用不上cookie,也沒有l(wèi)anguage參數(shù)。
但是大部分的內(nèi)部調(diào)用都有傳遞公司id,可以通過公司獲得公司對應(yīng)的語言。
可以在攔截器里面直接加入對companyId的解析但是我考慮有沒有通用的實現(xiàn)方法,就是在任何地方,甚至的運行到一半中途設(shè)置語言的辦法。
初步想法是拿到線程中的Locale進(jìn)行設(shè)置
然后我看了下源碼LocaleContextHolder.getLocale()
發(fā)現(xiàn)調(diào)用的是一個LocaleContext類的方法。
然后查詢哪些地方調(diào)用了LocaleResolver.resolveLocale
發(fā)現(xiàn)第一個方法里面返回了一個匿名函數(shù)LocaleContext,其getLocale就是直接調(diào)用localeResolver.resolveLocale方法。
于是我合理的猜想框架里不是通過攔截器設(shè)置一個locale,而是每次調(diào)用LocaleContextHolder.getLocale()都會執(zhí)行l(wèi)ocaleResolver.resolveLocale(request)方法,所以我們只要設(shè)置request屬性就行了
public class MyLocaleResolver implements LocaleResolver {@Override public Locale resolveLocale(HttpServletRequest httpServletRequest) {//得到cookie,解析localeLocale locale = Locale.getDefault();{//通過參數(shù)解析localeString temp = httpServletRequest.getParameter('language');if (!StringUtils.isEmpty(temp)) {locale = new Locale(temp);return locale;}}{String temp = (String) httpServletRequest.getAttribute('language');if (!StringUtils.isEmpty(temp)) {locale = new Locale(temp);return locale;}}Cookie[] cookies = httpServletRequest.getCookies();if(cookies != null) { for (Cookie cookie : cookies) {if (cookie.getName().equals('userLanguage')) { String temp = cookie.getValue(); if (!StringUtils.isEmpty(temp)) {locale = new Locale(temp); } continue;} }}return locale; } @Override public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) { }}
@RequestMapping('/test') public String test(HttpServletRequest request) { String result = '';request.setAttribute('language', 'ch');result += MessageUtils.get('test', '測試');request.setAttribute('language', 'en');result += MessageUtils.get('test', '測試');return result; }
messages_ch.properties
test=測試
messages_en.properties
test=test
這樣我們就實現(xiàn)了在任何地點,甚至中途變換語言了
發(fā)現(xiàn)LocaleContextHolder.getLocale()在實體類中也可以調(diào)用。因此可以后臺保存json格式,在get方法中根據(jù)語言返回相應(yīng)的值。
我本來想直接改造原來的字段,但是發(fā)現(xiàn)緩存會直接讀取get中的值,下次讀取就不是json了,所以只好麻煩點增加一個字段了
public String getFullNameByLanguage() {String language = LocaleContextHolder.getLocale().getLanguage();Map<String, String> map;try {map = JsonUtil.string2Obj(fullName);return map.get(language);} catch (IOException e) {return fullName;}}
當(dāng)使用@Async異步方法時,LocaleContext就是空的。這時候需要強(qiáng)制設(shè)置語言LocaleContextHolder.setLocale(Locale locale),當(dāng)然一般的方法也可以用這個來設(shè)置語言,不過這樣的話就不會再調(diào)用localeResolver.resolveLocale(request)方法了
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持好吧啦網(wǎng)。
相關(guān)文章:
1. 基于PHP做個圖片防盜鏈2. php使用正則驗證密碼字段的復(fù)雜強(qiáng)度原理詳細(xì)講解 原創(chuàng)3. ASP.NET MVC使用Boostrap實現(xiàn)產(chǎn)品展示、查詢、排序、分頁4. XML在語音合成中的應(yīng)用5. jscript與vbscript 操作XML元素屬性的代碼6. asp.net core 認(rèn)證和授權(quán)實例詳解7. ASP.NET MVC把數(shù)據(jù)庫中枚舉項的數(shù)字轉(zhuǎn)換成文字8. 如何使用ASP.NET Core 配置文件9. .NET中實現(xiàn)對象數(shù)據(jù)映射示例詳解10. 基于javaweb+jsp實現(xiàn)企業(yè)車輛管理系統(tǒng)
