现在翻译API各种各样,非常多,在我看来,有道算是不错的一个,专做翻译有一手,所以便去有道平台开通了一个翻译功能。
需要验证手机,有50块免费额度,感觉能用蛮久的,等免费用完,换个平台继续用。
从这进入 有道平台入口
下面这个类是基于Laravel框架的,其他框架的话,自行改下curlApi 和 writeErrorLog 两个方法
把代码放入app的Service目录,把有道平台申请好的APP_ID和APP_KEY填入,就可以直接用了,非常方便
调用方法如下:
$translator = new \App\Service\YoudaoTranslator(); | |
$result = $translator->getTranslation('中国好地方', 'en'); | |
dd($result); |
namespace App\Service; | |
use Illuminate\Support\Facades\Http; | |
use Illuminate\Support\Facades\Log; | |
class YoudaoTranslator | |
{ | |
const APP_ID = '';//请填入申请的APP_ID | |
const APP_KEY = '';//请填入申请的APP_KEY | |
const API_TIMEOUT = 1; | |
const API_URL = 'https://openapi.youdao.com/api'; | |
const KEY_QUERY = 'q'; | |
const KEY_FROM = 'from'; | |
const KEY_TO = 'to'; | |
const KEY_APPID = 'appKey'; | |
const KEY_SALT = 'salt'; | |
const KEY_SIGN = 'sign'; | |
const KEY_SIGN_TYPE = 'signType'; | |
const KEY_CURTIME = 'curtime'; | |
const KEY_ERROR_CODE = 'errorCode'; | |
const KEY_TRANSLATION = 'translation'; | |
const KEY_LANG = 'l'; | |
const DEFAULT_SIGN_TYPE = 'v3'; | |
const ERROR_CODES_MAPPER = [ | |
101 => '缺少必填的参数,首先确保必填参数齐全,然后确认参数书写是否正确。', | |
102 => '不支持的语言类型', | |
103 => '翻译文本过长', | |
104 => '不支持的API类型', | |
105 => '不支持的签名类型', | |
106 => '不支持的响应类型', | |
107 => '不支持的传输加密类型', | |
108 => '应用ID无效,注册账号,登录后台创建应用和实例并完成绑定,可获得应用ID和应用密钥等信息', | |
109 => 'batchLog格式不正确', | |
110 => '无相关服务的有效实例,应用没有绑定服务实例,可以新建服务实例,绑定服务实例。注:某些服务的翻译结果发音需要tts实例,需要在控制台创建语音合成实例绑定应用后方能使用。', | |
111 => '开发者账号无效', | |
112 => '请求服务无效', | |
113 => 'q不能为空', | |
114 => '不支持的图片传输方式', | |
116 => 'strict字段取值无效,请参考文档填写正确参数值', | |
201 => '解密失败,可能为DES,BASE64,URLDecode的错误', | |
202 => '签名检验失败,如果确认应用ID和应用密钥的正确性,仍返回202,一般是编码问题。请确保翻译文本 q 为UTF-8编码.', | |
203 => '访问IP地址不在可访问IP列表', | |
205 => '请求的接口与应用的平台类型不一致,确保接入方式(Android SDK、IOS SDK、API)与创建的应用平台类型一致。如有疑问请参考入门指南', | |
206 => '因为时间戳无效导致签名校验失败', | |
207 => '重放请求', | |
301 => '辞典查询失败', | |
302 => '翻译查询失败', | |
303 => '服务端的其它异常', | |
304 => '会话闲置太久超时', | |
401 => '账户已经欠费,请进行账户充值', | |
402 => 'offlinesdk不可用', | |
411 => '访问频率受限,请稍后访问', | |
412 => '长请求过于频繁,请稍后访问', | |
1001 => '无效的OCR类型', | |
1002 => '不支持的OCR image类型', | |
1003 => '不支持的OCR Language类型', | |
1004 => '识别图片过大', | |
1201 => '图片base64解密失败', | |
1301 => 'OCR段落识别失败', | |
1411 => '访问频率受限', | |
1412 => '超过最大识别字节数', | |
2003 => '不支持的语言识别Language类型', | |
2004 => '合成字符过长', | |
2005 => '不支持的音频文件类型', | |
2006 => '不支持的发音类型', | |
2201 => '解密失败', | |
2301 => '服务的异常', | |
2411 => '访问频率受限,请稍后访问', | |
2412 => '超过最大请求字符数', | |
3001 => '不支持的语音格式', | |
3002 => '不支持的语音采样率', | |
3003 => '不支持的语音声道', | |
3004 => '不支持的语音上传类型', | |
3005 => '不支持的语言类型', | |
3006 => '不支持的识别类型', | |
3007 => '识别音频文件过大', | |
3008 => '识别音频时长过长', | |
3009 => '不支持的音频文件类型', | |
3010 => '不支持的发音类型', | |
3201 => '解密失败', | |
3301 => '语音识别失败', | |
3302 => '语音翻译失败', | |
3303 => '服务的异常', | |
3411 => '访问频率受限,请稍后访问', | |
3412 => '超过最大请求字符数', | |
4001 => '不支持的语音识别格式', | |
4002 => '不支持的语音识别采样率', | |
4003 => '不支持的语音识别声道', | |
4004 => '不支持的语音上传类型', | |
4005 => '不支持的语言类型', | |
4006 => '识别音频文件过大', | |
4007 => '识别音频时长过长', | |
4201 => '解密失败', | |
4301 => '语音识别失败', | |
4303 => '服务的异常', | |
4411 => '访问频率受限,请稍后访问', | |
4412 => '超过最大请求时长', | |
5001 => '无效的OCR类型', | |
5002 => '不支持的OCR image类型', | |
5003 => '不支持的语言类型', | |
5004 => '识别图片过大', | |
5005 => '不支持的图片类型', | |
5006 => '文件为空', | |
5201 => '解密错误,图片base64解密失败', | |
5301 => 'OCR段落识别失败', | |
5411 => '访问频率受限', | |
5412 => '超过最大识别流量', | |
9001 => '不支持的语音格式', | |
9002 => '不支持的语音采样率', | |
9003 => '不支持的语音声道', | |
9004 => '不支持的语音上传类型', | |
9005 => '不支持的语音识别 Language类型', | |
9301 => 'ASR识别失败', | |
9303 => '服务器内部错误', | |
9411 => '访问频率受限(超过最大调用次数)', | |
9412 => '超过最大处理语音长度', | |
10001 => '无效的OCR类型', | |
10002 => '不支持的OCR image类型', | |
10004 => '识别图片过大', | |
10201 => '图片base64解密失败', | |
10301 => 'OCR段落识别失败', | |
10411 => '访问频率受限', | |
10412 => '超过最大识别流量', | |
11001 => '不支持的语音识别格式', | |
11002 => '不支持的语音识别采样率', | |
11003 => '不支持的语音识别声道', | |
11004 => '不支持的语音上传类型', | |
11005 => '不支持的语言类型', | |
11006 => '识别音频文件过大', | |
11007 => '识别音频时长过长,最大支持30s', | |
11201 => '解密失败', | |
11301 => '语音识别失败', | |
11303 => '服务的异常', | |
11411 => '访问频率受限,请稍后访问', | |
11412 => '超过最大请求时长', | |
12001 => '图片尺寸过大', | |
12002 => '图片base64解密失败', | |
12003 => '引擎服务器返回错误', | |
12004 => '图片为空', | |
12005 => '不支持的识别图片类型', | |
12006 => '图片无匹配结果', | |
13001 => '不支持的角度类型', | |
13002 => '不支持的文件类型', | |
13003 => '表格识别图片过大', | |
13004 => '文件为空', | |
13301 => '表格识别失败', | |
15001 => '需要图片', | |
15002 => '图片过大(1M)', | |
15003 => '服务调用失败', | |
17001 => '需要图片', | |
17002 => '图片过大(1M)', | |
17003 => '识别类型未找到', | |
17004 => '不支持的识别类型', | |
17005 => '服务调用失败', | |
]; | |
/** | |
* get translation | |
* @param $string | |
* @param string $toLang | |
* @param string $fromLang | |
* @return mixed|null | |
*/ | |
public function getTranslation($string, $toLang = '', &$fromLang = '') | |
{ | |
$params = $this->getQueryParams($string, $toLang, $fromLang); | |
$response = $this->curlApi($params); | |
if ($response->failed()) { | |
$this->writeErrorLog(sprintf('curl api error, code: %d, error: %s', $response->status(), $response->body())); | |
return $string; | |
} else { | |
$result = $response->json(); | |
if (isset(self::ERROR_CODES_MAPPER[$result[self::KEY_ERROR_CODE]])) { | |
$errCode = $result[self::KEY_ERROR_CODE] ?? 0; | |
$errMsg = self::ERROR_CODES_MAPPER[$result[self::KEY_ERROR_CODE]] ?? 'translate api return error'; | |
$this->writeErrorLog(sprintf('translate api error, code: %d, error: %s', $errCode, $errMsg)); | |
return $string; | |
} | |
if (isset($result[self::KEY_LANG]) && $result[self::KEY_LANG]) { | |
$fromLang = explode('2', $result[self::KEY_LANG])[0] ?? ''; | |
} | |
if (isset($result[self::KEY_TRANSLATION])) { | |
if (is_array($result[self::KEY_TRANSLATION])) { | |
$trans = array_pop($result[self::KEY_TRANSLATION]); | |
return $trans; | |
} else { | |
return $result[self::KEY_TRANSLATION] ?? $string; | |
} | |
} | |
} | |
return $string; | |
} | |
/** | |
* if not using laravel framework, please change this | |
*/ | |
protected function curlApi($params) | |
{ | |
$params = is_array($params) ? http_build_query($params) : $params; | |
return Http::timeout(self::API_TIMEOUT) | |
->get(self::API_URL, $params); | |
} | |
/** | |
* if not using laravel framework, please change this | |
*/ | |
protected function writeErrorLog($msg) | |
{ | |
Log::error($msg); | |
} | |
protected function getQueryParams($string, $toLang = '', $fromLang = '') | |
{ | |
$salt = $this->createGuid(); | |
$args = [ | |
self::KEY_QUERY => $string, | |
self::KEY_APPID => self::APP_ID, | |
self::KEY_SALT => $salt, | |
]; | |
$args[self::KEY_FROM] = $fromLang; | |
$args[self::KEY_TO] = $toLang; | |
$args[self::KEY_SIGN_TYPE] = self::DEFAULT_SIGN_TYPE; | |
$curtime = time(); | |
$args[self::KEY_CURTIME] = $curtime; | |
$signStr = self::APP_ID . $this->truncateStr($string) . $salt . $curtime . self::APP_KEY; | |
$args[self::KEY_SIGN] = hash("sha256", $signStr); | |
return $args; | |
} | |
protected function createGuid() | |
{ | |
$microTime = microtime(); | |
list($a_dec, $a_sec) = explode(" ", $microTime); | |
$dec_hex = dechex($a_dec* 1000000); | |
$sec_hex = dechex($a_sec); | |
$this->ensureLength($dec_hex, 5); | |
$this->ensureLength($sec_hex, 6); | |
$guid = ""; | |
$guid .= $dec_hex; | |
$guid .= $this->createGuidSection(3); | |
$guid .= '-'; | |
$guid .= $this->createGuidSection(4); | |
$guid .= '-'; | |
$guid .= $this->createGuidSection(4); | |
$guid .= '-'; | |
$guid .= $this->createGuidSection(4); | |
$guid .= '-'; | |
$guid .= $sec_hex; | |
$guid .= $this->createGuidSection(6); | |
return $guid; | |
} | |
protected function ensureLength(&$string, $length) | |
{ | |
$strlen = strlen($string); | |
if($strlen < $length) { | |
$string = str_pad($string, $length, "0"); | |
} else if($strlen > $length) { | |
$string = substr($string, 0, $length); | |
} | |
} | |
protected function createGuidSection($characters) | |
{ | |
$return = ""; | |
for($i = 0; $i < $characters; $i++) { | |
$return .= dechex(mt_rand(0, 15)); | |
} | |
return $return; | |
} | |
protected function truncateStr($q) | |
{ | |
$len = mb_strlen($q,'utf-8'); | |
return $len <= 20 ? $q : (mb_substr($q, 0, 10) . $len . mb_substr($q, $len - 10, $len)); | |
} | |
} |