最近我们一个商城项目涉及多语言切换,默认中文。用户切换语言可选英语和阿拉伯语言,前端APP和后端返回动态数据都要根据用户选择语言来展示。前端静态内容都做了三套语言,后端商品为了适用这种多语言我们也进行了改造。每一件商品名称,图片,价格等等 分别都有三中语言对应字段,根据前端公共参数(放请求header中的语言标识) 返回不同语言的字段值。
所以在商品的新增,修改等等地方商品名称,介绍等等就需要 根据中文翻译成英文和阿拉伯语保存下来。通过多方对比,最终发现阿里云机器翻译专业版还是最准确的,可能是阿里本来就有海量商品他们翻译引擎训练的比较智能。
接下来我们梳理下整个对接流程,官方文档:
什么是机器翻译JavaSDK_机器翻译(Machine Translation)-阿里云帮助中心
1,引入官方提供的java 版本 maven sdk
<!-- 阿里云翻译sdk -->
<!-- https://mvnrepository.com/artifact/com.aliyun/alimt20181012 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>alimt20181012</artifactId>
<version>1.3.1</version>
<exclusions>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>openplatform20191219</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>tea-openapi</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>credentials-java</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>tea-openapi</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>openapiutil</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>oss-util</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>tea</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>tea-rpc</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>tea-util</artifactId>
</exclusion>
<exclusion>
<groupId>com.aliyun</groupId>
<artifactId>tea-rpc</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 商品图片搜索 -->
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>imagesearch20201214</artifactId>
<version>4.0.2</version>
</dependency>
因为我们后面又使用了阿里的图片搜索,所以里面很多jar和图像搜索中的有冲突,如果只接入翻译实际上不需要排除。
2,定义配置:
建议使用一个ram账号 拿ram的accessKeyId 和secret,给这个子账号开通对应权限
public class AliYunTranslateConfig {
private String accessKeyId;
private String accessKeySecret;
/**
* 华南深圳 mt.aliyuncs.com
* 阿联酋(迪拜) mt.aliyuncs.com
*
*/
private String endpoint;
}
3,封装 核心翻译方法
public class AliTranslamt20181012 {
private AliYunTranslateConfig aliYunTranslateConfig;
public AliTranslamt20181012(AliYunTranslateConfig aliYunTranslateConfig) {
this.aliYunTranslateConfig = aliYunTranslateConfig;
}
/**
* <b>description</b> :
* <p>使用AK&SK初始化账号Client</p>
* @return Client
*
* @throws Exception
*/
public com.aliyun.alimt20181012.Client createClient() {
com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_ID
.setAccessKeyId(aliYunTranslateConfig.getAccessKeyId())
// 必填,请确保代码运行环境设置了环境变量 ALIBABA_CLOUD_ACCESS_KEY_SECRET。
.setAccessKeySecret(aliYunTranslateConfig.getAccessKeySecret());
// Endpoint 请参考 https://api.aliyun.com/product/alimt
config.endpoint = aliYunTranslateConfig.getEndpoint(); // 深圳
// 阿联酋(迪拜) mt.aliyuncs.com
Client client = null;
try {
client = new Client(config);
} catch (Exception e) {
log.error("调用阿里云 翻译 初始化失败cause:{},。,errorMsg:{}",e.getCause().getMessage(),e.getMessage());
e.printStackTrace();
}
return client;
}
/**
* 翻译api
*
* @return
*/
public List<TranslateResponseBodyDataFromThirdPartDTO> translate(List<AliYunTranslateDTO> dtoList) {
StopWatch stopWatch = new StopWatch();
stopWatch.start("thirdPart_wordFromZh2ArAndEn");
com.aliyun.alimt20181012.Client client = this.createClient();
List<TranslateResponseBodyDataFromThirdPartDTO> resultList = new java.util.ArrayList<>(dtoList.size());
dtoList.forEach(dto -> {
com.aliyun.alimt20181012.models.TranslateRequest translateRequest = new com.aliyun.alimt20181012.models.TranslateRequest()
.setFormatType(dto.getFormatType())
.setTargetLanguage(dto.getTargetLanguage())
.setSourceLanguage(dto.getSourceLanguage())
.setSourceText(dto.getSourceText())
.setScene(dto.getScene())
.setContext(dto.getContext());
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
TranslateResponseBodyDataFromThirdPartDTO result = new TranslateResponseBodyDataFromThirdPartDTO();
result.setRequestKey(dto.getRequestKey());
resultList.add(result);
try {
TranslateResponse translateResponse = client.translateWithOptions(translateRequest, runtime);
log.info("调用翻译 输入参数:{}",JSONUtil.parse(dto));
if(ObjectUtil.isNotNull(translateResponse)){
log.info("调用翻译 得到的结果为:{}", JSONUtil.parse(translateResponse.getBody()));
if(200==translateResponse.getStatusCode()){
TranslateResponseBody.TranslateResponseBodyData data = translateResponse.getBody().getData();
BeanUtils.copyProperties(data, result);
}else {
log.error("调用翻译出错了,statusCode:{}",translateResponse.getStatusCode());
}
}
} catch (TeaException error) {
log.error("调用阿里云翻译出错了,errorMsg:{}",error.getMessage());
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
System.out.println(error.getMessage());
log.error("调用阿里云翻译出错了 exception ,msg:{}",error.getMessage());
com.aliyun.teautil.Common.assertAsString(error.message);
}
});
stopWatch.stop();
log.info(stopWatch.getLastTaskName()+"耗时:{} 毫秒",stopWatch.getLastTaskTimeMillis());
return resultList;
}
}
其中 请求的dto结构如下:其中,scene是识别翻译的使用场景,是商品标题还是描述异或者是客服沟通过程中的交流文字?不同场景的设置使翻译更贴近我们的预期翻译结果。
context也是很有用的,上下文语境,我们翻译某一段内容在不同场景下,可能前后与其相搭配的额外词汇。比如title 下我们可以加上 "我在网上商城搜索了 商品标题是"+****+"的商品"。
总之这两个参数的设置都是为了设置商品不同属性, 指定其大概范围的,从而能更准确的获得翻译结果。可以自己多调试下,找到适合自己业务的一些词汇。
public class AliYunTranslateDTO implements Serializable {
public static String FROMTYPE_HTML ="html";
public static String FROMTYPE_TEXT ="text";
// from 语言
public static String SOURCELANGUAGE_ZH ="zh";
// 翻译目标语言
public static String TARGETLANGUAGE_EN ="en";
public static String TARGETLANGUAGE_AR ="ar";
// 场景可选取值:商品标题(title),商品描述(description),商品沟通(communication),医疗(medical),社交(social),金融(finance)
public static String SCENE_TITLE ="title";
public static String SCENE_DESCRIPTION ="description";
public static String SCENE_COMMUNICATION ="communication";
public static String SCENE_MEDICAL ="medical";
public static String SCENE_SOCIAL ="social";
public static String SCENE_FINANCE ="finance";
/**
* 用于标注 翻译的请求唯一标识
*
*/
@ApiModelProperty(hidden = true)
private String requestKey = "";
/**
* 翻译文本的格式,html( 网页格式。设置此参数将对待翻译文本以及翻译后文本按照 html 格式进行处理)、text(文本格式。设置此参数将对传入待翻译文本以及翻译后结果不做文本格式处理,统一按纯文本格式处理。
*
*/
@ApiModelProperty(name = "译文本的格式html 或text")
private String FormatType;
/**
*
* 原文语言-from
* 英语 - en
* 中文 - zh
* 阿拉伯语 - ar
*
*/
@ApiModelProperty(name = "原文语言-from")
private String SourceLanguage;
/**
* 译文语言 -to
* 英语 - en
* 中文 - zh
* 阿拉伯语 - ar
*
*/
@ApiModelProperty(name = "译文语言 -to")
private String TargetLanguage;
/**
* 待翻译内容
*
*/
@ApiModelProperty(name = "待翻译内容")
private String SourceText;
/**
* 场景可选取值:商品标题(title),商品描述(description),商品沟通(communication),医疗(medical),社交(social),金融(finance)
*
*/
@ApiModelProperty(name = "场景可选取值:商品标题(title),商品描述(description),商品沟通(communication),医疗(medical),社交(social),金融(finance)")
private String Scene;
/**
* 上下文信息,可选填 (语境)
* 如 我在商城买了一件
*/
@ApiModelProperty(name = "上下文信息,可选填 (语境)")
private String Context;
}
返回结果 dto
public class TranslateResponseBodyDataFromThirdPartDTO {
/**
* 请求中携带的请求唯一标识,这是我们自定义的一个批次id
*
*/
private String requestKey;
/**
* zh 源语言传入auto时,语种识别后的源语言代码
*/
public String detectedLanguage;
/**
* 翻译结果
*/
public String translated;
/**
* 总单词数
*/
public String wordCount;
}