概述
需求
一、当切换语言时,可以切换如下数据
数据国际化:所有用户录入的数据,商品、会员、店铺、订单等
二、国际化字典
数据国际化字典:用户可自行增加key,录入文字,比如录入 中文'牛腱',英文'niujian',西文'xxx'
架构思路
数据库入库时,根据用户录入的字典,翻译各种语言
数据查询时,根据当前语言国别,查询相应语言并显示
语言包的写入
- 数据的保存分为两种:
添加
和修改
,都需要对数据生成语言包 - 语言包需要有客户录入的字典中获取,参加数据语言包字典接口
语言包保存
@Aspect
@Component
public class GoodsI18nAop {
@Pointcut("execution(* com.enation.app.javashop.service.goods.GoodsManager.add(..))")
public void goodsAdd() {
}
@Pointcut("execution(* com.enation.app.javashop.service.goods.GoodsManager.edit(..))")
public void goodsEdit() {
}
/**
* 拦截商品的添加
* @param point
* @return
* @throws Throwable
*/
@Around("goodsAdd()")
public GoodsDO aroundAdd(ProceedingJoinPoint point) throws Throwable {
GoodsDTO goodsDTO = (GoodsDTO) point.getArgs()[0];
GoodsDO goodsDO = (GoodsDO)point.proceed(new Object[]{goodsDTO});
//对goods 语言表,goods_sku语言表写入
String lang = LanguageContext.getLanguage();
this.addLang(goodsDO,lang);
return goodsDO;
}
/**
* 拦截商品的修改
* @param point
* @return
* @throws Throwable
*/
@Around("goodsEdit()")
public GoodsDO aroundEdit(ProceedingJoinPoint point) throws Throwable {
GoodsDO goodsDO = (GoodsDO)point.proceed();
String lang = LanguageContext.getLanguage();
this.editLang(goodsDO,lang);
return goodsDO;
}
}
单条数据语言包获取
@Aspect
@Component
public class GoodsI18nAop {
@Pointcut("execution(* com.enation.app.javashop.service.goods.GoodsQueryManager.getFromCache(..))")
public void getFromCache() {
}
@Around("getFromCache()")
public CacheGoods aroundFromCache(ProceedingJoinPoint point) throws Throwable {
Long goodsId = (Long) point.getArgs()[0];
CacheGoods cacheGoods =(CacheGoods) point.proceed(new Object[]{goodsId});
GoodsLang goodsLang = this.getLang(goodsId);
BeanUtils.copyProperties(goodsLang, cacheGoods);
return cacheGoods;
}
}
列表数据语言包的获取
tip
注意,这里需要用 in (id,id...)来批量查询列表数据
@Aspect
@Component
public class GoodsI18nAop {
@Pointcut("execution(* com.enation.app.javashop.service.goods.GoodsQueryManager.list(..))")
public void sellerList() {
}
/**
* 商家读取
* @param point
* @return
* @throws Throwable
*/
@Around("sellerList()")
public WebPage aroundSeller(ProceedingJoinPoint point) throws Throwable {
WebPage<GoodsDO> page=(WebPage)point.proceed();
String lang = LanguageContext.getLanguage();
List<GoodsDO> goodsDOList = page.getData();
List<Long> goodIdList = goodsDOList.stream().map(g -> g.getGoodsId()).collect(Collectors.toList());
List<GoodsLang> langList = getLangList(goodIdList,lang);
GoodsLangConsumer goodsLangConsumer = new GoodsLangConsumer(langList);
goodsDOList.forEach(goodsLangConsumer);
return page;
}
}
public class GoodsLangConsumer implements Consumer<GoodsDO> {
private List<GoodsLang> langList;
public GoodsLangConsumer(List<GoodsLang> langList) {
this.langList = langList;
}
@Override
public void accept(GoodsDO goodsDO) {
GoodsLang goodsLang = langList.stream().filter(lang -> lang.getGoodsId().equals(goodsDO.getGoodsId())).findFirst().orElse(null);
if (goodsLang != null) {
BeanUtils.copyProperties(goodsLang, goodsDO);
}
}
}
规范
tip
这里以商品数据的国际化为例,来说明规范
数据库
- 表名规范:
数据表名
+_lang
- 字段规范:保持和原字段一直
如商品模块:
表名:es_goods_lang(商品数据语言包)
字段:
分支规范
使用i18n_dev
分支
包名及类规范
包名
主包名: com.enation.app.javashop.i18n
类规范
1、命名:XxxxI18nAspect
2、注解: @ConditionalOnProperty(value = "javashop.i18n", havingValue = "open")
3、语言包的渲染:
//单条:
BeanUtils.copyProperties(goodsLang, goodsDO);
//批量:
GoodsLangConsumer goodsLangConsumer = new GoodsLangConsumer(langList);
goodsDOList.forEach(goodsLangConsumer);
翻译接口
各国语言包翻译顺序是:自行维护的字典->机翻
接口地址
com.enation.app.javashop.i18n.core.Translator.translate
参数说明
方法 | 类型 | 说明 |
---|---|---|
text | 字串 | 要翻译的文字 |
langCode | 字串 | 文字对应的语种code |
返回值
Map类型
map的key为语种code
value为对应的翻译结果
地区上下文接口
接口地址
com.enation.app.javashop.i18n.LocaleContext
方法说明
方法 | 说明 |
---|---|
Locale getCurrentLocal() | 获取当前环境的地区 |
前后端参数规范
传参方式 | header |
---|---|
参数名 | language |