translation_api_cn/
baidu.rs1use crate::Limit;
2use serde::{Deserialize, Serialize};
3use std::borrow::Cow;
4
5pub const URL: &str = "https://fanyi-api.baidu.com/api/trans/vip/translate";
6
7#[derive(Debug)]
9pub struct Query<'q> {
10 pub q: &'q str,
15 pub from: &'q str,
19 pub to: &'q str,
23 pub sign: String,
25}
26
27#[derive(Debug, Deserialize)]
29#[serde(rename = "baidu")] pub struct User {
31 pub appid: String,
33 pub key: String,
35 #[serde(default = "default_salt")]
37 pub salt: String,
38 #[serde(default = "default_qps")]
41 pub qps: u8,
42 #[serde(default = "default_limit")]
44 pub limit: Limit,
46}
47
48fn default_qps() -> u8 { 1 }
49fn default_salt() -> String { String::from("0") }
50fn default_limit() -> Limit { Limit::Byte(6000) }
51
52impl Default for User {
53 fn default() -> Self {
54 Self { appid: String::new(),
55 key: String::new(),
56 salt: default_salt(),
57 qps: default_qps(),
58 limit: default_limit(), }
59 }
60}
61
62impl<'q> Query<'q> {
63 pub fn new(q: &'q str, from: &'q str, to: &'q str) -> Self {
65 Self { q, from, to, sign: "".into() }
66 }
67
68 pub fn sign<'f>(&'f mut self, user: &'f User) -> Form<'f> {
77 let data = format!("{}{}{}{}", &user.appid, self.q, &user.salt, &user.key);
78 self.sign = format!("{:x}", md5::compute(data));
79 Form::from_user_query(user, self)
80 }
81}
82
83#[derive(Debug, Serialize)]
85pub struct Form<'f> {
86 pub q: &'f str,
87 pub from: &'f str,
88 pub to: &'f str,
89 pub appid: &'f str,
90 pub salt: &'f str,
91 pub sign: &'f str,
92}
93
94impl<'f> Form<'f> {
95 pub fn from_user_query(user: &'f User, query: &'f Query) -> Self {
96 Self { q: query.q,
97 from: query.from,
98 to: query.to,
99 appid: &user.appid,
100 salt: &user.salt,
101 sign: &query.sign, }
102 }
103}
104
105#[derive(Debug, Deserialize)]
107#[serde(untagged)]
108pub enum Response<'r> {
109 Ok {
110 from: &'r str,
111 to: &'r str,
112 #[serde(rename = "trans_result")]
114 #[serde(borrow)]
115 res: Vec<SrcDst<'r>>,
116 },
117 Err(Error),
118}
119
120impl<'r> Response<'r> {
121 pub fn dst(&self) -> Result<impl Iterator<Item = &str>, Error> {
127 match self {
128 Response::Ok { res, .. } => Ok(res.iter().map(|x| x.dst.as_ref())),
129 Response::Err(e) => Err(e.clone()),
130 }
131 }
132
133 pub fn dst_owned(self) -> Result<Vec<String>, Error> {
135 match self {
136 Response::Ok { res, .. } => Ok(res.into_iter().map(|x| x.dst.into()).collect()),
137 Response::Err(e) => Err(e),
138 }
139 }
140
141 pub fn is_borrowed(&self) -> Option<bool> {
160 match self {
161 Response::Ok { res, .. } if !res.is_empty() => {
162 Some(matches!(res[0].dst, Cow::Borrowed(_)))
163 }
164 _ => None,
165 }
166 }
167}
168
169#[derive(Debug, Deserialize)]
177pub struct SrcDst<'r> {
178 #[serde(borrow)]
180 pub dst: Cow<'r, str>,
181}
182
183#[derive(Debug, Clone, Deserialize)]
185pub struct Error {
186 #[serde(rename = "error_code")]
187 pub code: String,
188 #[serde(rename = "error_msg")]
189 pub msg: String,
190}
191
192impl std::error::Error for Error {}
193impl std::fmt::Display for Error {
194 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
195 write!(f,
196 "错误码:`{}`\n错误信息:`{}`\n错误含义:{}\n以上内容由百度翻译 API 返回",
197 self.code,
198 self.msg,
199 self.solution())
200 }
201}
202
203impl Error {
204 pub fn solution(&self) -> &str {
206 match self.code.as_bytes() {
207 b"52000" => "成功。",
208 b"52001" => "请求超时。\n解决方法:请重试。",
209 b"52002" => "系统错误。\n解决方法:请重试。",
210 b"52003" => "未授权用户。\n解决方法:请检查appid是否正确或者服务是否开通。",
211 b"54000" => "必填参数为空。\n解决方法:请检查是否少传参数。",
212 b"54001" => "签名错误。\n解决方法:请检查您的签名生成方法。",
213 b"54003" => {
214 "访问频率受限。\n解决方法:请降低您的调用频率,或进行身份认证后切换为高级版/\
215 尊享版。"
216 }
217 b"54004" => "账户余额不足。\n解决方法:请前往管理控制台为账户充值。",
218 b"54005" => "长 query 请求频繁。\n解决方法:请降低长 query 的发送频率,3s后再试。",
219 b"58000" => {
220 "客户端 IP 非法。\n解决方法:检查个人资料里填写的 IP \
221 地址是否正确,可前往开发者信息-基本信息修改。"
222 }
223 b"58001" => "译文语言方向不支持。\n解决方法:检查译文语言是否在语言列表里。",
224 b"58002" => "服务当前已关闭。\n解决方法:请前往管理控制台开启服务。",
225 b"90107" => "认证未通过或未生效。\n解决方法:请前往我的认证查看认证进度。",
226 _ => "未知错误。",
227 }
228 }
229}