最近在学习的小玩意,发现腾讯的文档十分坑爹,里面有很多错误的指示。
不过腾讯的机器翻译还是很牛的,我觉得翻译水准比谷歌好很多。
腾讯的机器翻译貌似在试用阶段,不收费,用QQ或微信登录即可申请使用。
首先获得SecretId和SecretKey,最好是创建一个子用户,因为这两个“秘密”都要明文写在js里。创建一个工程,这样就有了ProjectId。
准备好如下的参数:
var reqParams = [ [ "Action", "TextTranslate" ], [ "Nonce", Nonce ], // 随机整数 [ "ProjectId", ProjectId], ["Region", "ap-beijing"], ["SecretId", SecretId], ["Source","auto"], // 自动检测要翻译的文本的语种 ["SourceText", sourceText], // 要翻译的文本。生成签名时,必须使用原文本,即没有做uri编码的 ["Target","zh"], // 翻译成哪个语种,这里是翻译成中文 ["Timestamp",timestamp ], // 时间戳,以秒为单位,而js里用Date对象获取的时间戳是毫秒的,注意。腾讯文档说时间戳是0时区的,但其实就是东八区(北京时区) ["Version","2018-03-21"] ];
上面是一个嵌套的数组,或者说二维数组,这是为了方便排序(上面的顺序已经是排好了的)。必须先按参数的字母顺序排序后,拼成字符串,再做签名。
参数对转字符串函数:
// 参数对转成字符串 function paramsToStr(params) { // 按参数名的字典序排序 params.sort(function(a,b){ if(a[0] < b[0]) return -1; else if(a[0] > b[0]) return 1; return 0; }); // 连成字符串 var parPairStrArr = []; for (var i in params) { var par = params[i]; var parStr = par.join("="); parPairStrArr.push(parStr); } var str = parPairStrArr.join("&"); return str; }
有了参数字符串,再构造签名用的字符串,它需要包含请求方法、请求路径、请求参数。
// 签名原文字符串 var signStr = reqMethod + makeBaseUrl(host, hostPath) + "?" + paramsStr; // reqMethod 就是 GET 或 POST // makeBaseUrl 只是简单的返回了腾讯翻译的域名(不包括https://),在这里是tmt.tencentcloudapi.com // 签名 var hs = CryptoJS.HmacSHA1(signStr, SecretKey); var rawSig = CryptoJS.enc.Base64.stringify(hs); console.log("rawSig=" + rawSig); var sig = encodeURIComponent(rawSig); // 必须使用 encodeURIComponent,对base64字符串中的特殊字符也做uri编码 return sig;
获取到 sig 后,下面要生成真正用于http请求的url,在这里使用 GET 方法,所以参数都直接附在Url中。这时,sourceText,也就是待翻译文本,需要先把空格替换成+号、在做uri编码。
var iSourceText = reqParams.findIndex((p)=>(p[0]=="SourceText")); reqParams[iSourceText][1] = encodeURI(sourceText.replace(/\ /g,"+")); var paramsStr = paramsToStr(reqParams); var url = "https://" + makeBaseUrl(host, hostPath) + "?" + paramsStr + "&Signature=" + sig; console.log("url=" + url);
接下来就是使用 XMLHttpRequest 做http请求了。但是腾讯翻译服务器那边没有允许跨域。可以装个插件解决此问题。
允许浏览器跨域请求http的插件:https://chrome.google.com/webstore/detail/allow-control-allow-origi/nlfbmbojpeacfghkpbjhddihlkkiljbi
完整代码:
1 // 参数对转成字符串 2 function paramsToStr(params) 3 { 4 // 按参数名的字典序排序 5 6 params.sort(function(a,b){ 7 if(a[0] < b[0]) return -1; 8 else if(a[0] > b[0]) return 1; 9 return 0; 10 }); 11 12 // 连成字符串 13 14 var parPairStrArr = []; 15 for (var i in params) 16 { 17 var par = params[i]; 18 var parStr = par.join("="); 19 parPairStrArr.push(parStr); 20 } 21 var str = parPairStrArr.join("&"); 22 return str; 23 } 24 25 function makeBaseUrl(host, hostPath) 26 { 27 return host + hostPath; 28 } 29 30 // 声称签名 31 function makeSignature(reqMethod, host, hostPath, reqParams) 32 { 33 var paramsStr = paramsToStr(reqParams); 34 35 // 签名原文字符串 36 var signStr = reqMethod + makeBaseUrl(host, hostPath) + "?" + paramsStr; 37 38 // 签名 39 var hs = CryptoJS.HmacSHA1(signStr, SecretKey); 40 var rawSig = CryptoJS.enc.Base64.stringify(hs); 41 console.log("rawSig=" + rawSig); 42 var sig = encodeURIComponent(rawSig); 43 return sig; 44 } 45 46 // 发送翻译请求 47 function sendTrans(sourceText, cb) 48 { 49 if(sourceText == null || sourceText == "") 50 { 51 cb(""); 52 return; 53 } 54 55 var SecretId = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; 56 var SecretKey = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; 57 58 var reqMethod = "GET"; 59 var host = "tmt.tencentcloudapi.com"; 60 var hostPath = "/"; 61 62 var Nonce = Math.floor(Math.random() * 1000000000); 63 var date = new Date(); 64 var timestamp = Math.floor(date.getTime() / 1000); 65 66 var reqParams = [ 67 [ "Action", "TextTranslate" ], 68 [ "Nonce", Nonce ], 69 [ "ProjectId", xxxxxxxx], 70 ["Region", "ap-beijing"], 71 ["SecretId", SecretId], 72 ["Source","auto"], 73 ["SourceText", sourceText], // 生成签名时,使用原文本 74 ["Target","zh"], 75 ["Timestamp",timestamp ], 76 ["Version","2018-03-21"] 77 ]; 78 79 // 生成签名 80 var sig = makeSignature(reqMethod, host, hostPath, reqParams); 81 82 // 原文本中所有的空格替换成+号,然后uri编码 83 var iSourceText = reqParams.findIndex((p)=>(p[0]=="SourceText")); 84 reqParams[iSourceText][1] = encodeURI(sourceText.replace(/\ /g,"+")); 85 var paramsStr = paramsToStr(reqParams); 86 87 var url = "https://" + makeBaseUrl(host, hostPath) + "?" + paramsStr + "&Signature=" + sig; 88 console.log("url=" + url); 89 90 var xhr = new XMLHttpRequest(); 91 xhr.timeout = 3000; 92 xhr.ontimeout = function() 93 { 94 cb("超时,翻译失败"); 95 }; 96 xhr.onerror = function() 97 { 98 cb("错误,翻译失败"); 99 }; 100 101 xhr.open(reqMethod, url, true); 102 xhr.responseType = "json"; 103 var sendRet = xhr.send(); 104 xhr.onreadystatechange = function() 105 { 106 if(xhr.readyState == 4) 107 { 108 if(xhr.status == 200 || xhr.status == 304) 109 { 110 var ret = xhr.response; 111 cb(ret.Response.TargetText); 112 } 113 else 114 { 115 cb(xhr.responseText); 116 } 117 } 118 }; 119 }
原文:https://www.cnblogs.com/Dolaham/p/10594059.html