跳到主要内容

概述

需求

一、当切换语言时,可以切换如下数据

数据国际化:所有用户录入的数据,商品、会员、店铺、订单等

二、国际化字典

数据国际化字典:用户可自行增加key,录入文字,比如录入 中文'牛腱',英文'niujian',西文'xxx'

架构思路

数据库入库时,根据用户录入的字典,翻译各种语言

数据查询时,根据当前语言国别,查询相应语言并显示

语言包的写入

image-20221225214845425

  • 数据的保存分为两种:添加修改,都需要对数据生成语言包
  • 语言包需要有客户录入的字典中获取,参加数据语言包字典接口

语言包保存

@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(商品数据语言包)

字段:

image-20221225221352089

分支规范

使用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