- 为什么要用百度翻译?
从前是百度粉,现在我是百度黑,百度要完!
但是(真香),在各种翻译App中,我真的觉得百度的翻译最准确~~
不过也可能是个人喜好吧,勿喷。
- 为啥要搞PC版?
因为英语能力有限,经常看外文的资料确实需要一个翻译软件,另一个,我记得以前是有PC端的百度翻译的,但是不知道为啥没有了。现在在用有道的,但是经常有比较智障。
所以,不如自己搞一个吧,先实现最简单的需求就好。
1、获取百度翻译API接口
网址:http://api.fanyi.baidu.com/api/trans/product/index
“通用”版本的功能基本够用,主要 免费!
注册个账号,然后你会得到属于你的 “AppID”和“密钥”
并且可以在“文档与支持”中找到Demo示例,有各种语言的。
2、创建程序并设计界面
简单点,搞一个WinForm程序
上下两个文本框,为了实现随着窗口大小自动变化,并且上下比例能随意拖动,是放在一个【SplitContainer】中的
3、翻译功能的实现
先贴代码,后面说明
using System;
using System.Text;
using System.Net;
using System.IO;
using System.Security.Cryptography;
using System.Web;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.Linq;
namespace Transink
{
//用于解析返回的Json数据
public class TransResult
{
public string src { get; set; }
public string dst { get; set; }
}
public class BDTrans
{
//错误代码
private KeyValuePair<string, string>[] ErroCodes;
private string appId; //AppID
private string secretKey; //密钥
private string apiAdd; //Api地址
public BDTrans()
{
appId = "20191016000342007";
secretKey = "uva6gEvgtMGAHHIhh0zK";
apiAdd = "https://fanyi-api.baidu.com/api/trans/vip/translate?";
InitErroCode();//把错误代码对应的信息加载一下
}
//src=原文本 from=原语言 to=目标语言
//将接受的返回以字符串返回
public string Translate(string src, string from, string to)
{
string url = apiAdd;
Random rd = new Random();
string salt = rd.Next(100000).ToString();
string sign = EncryptString(appId + src + salt + secretKey);
url += "q=" + HttpUtility.UrlEncode(src);
url += "&from=" + from;
url += "&to=" + to;
url += "&appid=" + appId;
url += "&salt=" + salt;
url += "&sign=" + sign;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.ContentType = "text/html;charset=UTF-8";
request.UserAgent = null;
request.Timeout = 6000;
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream myResponseStream = response.GetResponseStream();
StreamReader myStreamReader = new StreamReader(myResponseStream, Encoding.GetEncoding("utf-8"));
string retString = myStreamReader.ReadToEnd();
return ParseResponse(retString);
}
//解析反馈
private string ParseResponse(string resStr)
{
JObject retJson = JObject.Parse(resStr);
List<JToken> tokens = new List<JToken>();
List<TransResult> transResults = new List<TransResult>();
string res = "";
//如果有结果
if (resStr.Contains("trans_result"))
{
tokens = retJson["trans_result"].Children().ToList();
foreach (JToken token in tokens)
{
transResults.Add(token.ToObject<TransResult>());
res += token.ToObject<TransResult>().dst +"\r\n";
}
}
//如果错误
if (resStr.Contains("error_code"))
{
JToken token = retJson["error_code"];
string erroCode = token.ToObject<string>();
//根据错误代码查询对应信息
var ErroStauts = ErroCodes.Where<KeyValuePair<string, string>>(x => x.Key == erroCode);
if (ErroStauts.Count() == 0)
{
res = "Unknown Error";
}
else
{
res = "Error: " + ErroStauts.ToList()[0].Value;
}
}
return res;
}
//进行MD5加密
public static string EncryptString(string str)
{
MD5 md5 = MD5.Create();
// 将字符串转换成字节数组
byte[] byteOld = Encoding.UTF8.GetBytes(str);
// 调用加密方法
byte[] byteNew = md5.ComputeHash(byteOld);
// 将加密结果转换为字符串
StringBuilder sb = new StringBuilder();
foreach (byte b in byteNew)
{
// 将字节转换成16进制表示的字符串,
sb.Append(b.ToString("x2"));
}
// 返回加密的字符串
return sb.ToString();
}
//初始化错误代码映射字典
private void InitErroCode()
{
ErroCodes = new KeyValuePair<string, string>[]
{
new KeyValuePair<string, string>("52001", "请求超时"),
new KeyValuePair<string, string>("52002", "系统错误"),
new KeyValuePair<string, string>("52003", "未授权用户"),
new KeyValuePair<string, string>("54000", "必填参数为空 "),
new KeyValuePair<string, string>("54001", "签名错误"),
new KeyValuePair<string, string>("54003", "访问频率受限"),
new KeyValuePair<string, string>("54004", "账户余额不足"),
new KeyValuePair<string, string>("54005", "长query请求频繁"),
new KeyValuePair<string, string>("58000", "客户端IP非法 "),
new KeyValuePair<string, string>("58001", "译文语言方向不支持"),
new KeyValuePair<string, string>("58002", "服务当前已关闭"),
new KeyValuePair<string, string>("90107", "认证未通过或未生效")
};
}
//根据字符判断所属语言,只实现中(2)英(1)文,其他的的统一为一类(0)
private int detectLanguageChar(char c)
{
int index = Convert.ToInt32(c);
if (index > 13312 && index < 40895)
{
return 2;
}
else if (index > 65 && index < 122)
{
return 1;
}
else
{
return 0;
}
}
//判断原文本可能是什么语言(那种语言的字符占的多)
public string detectLanguage(string str)
{
byte[] bytes = Encoding.UTF8.GetBytes(str);
char[] chars = Encoding.UTF8.GetChars(bytes);
int[] langP = new int[3] { 0, 0, 0 };
for (int i = 0; i < chars.Length; i++)
{
langP[detectLanguageChar(chars[i])] += 1;
}
int lang = -1;int max = 0;
for (int i = 0; i < langP.Length; i++)
{
if (langP[i] > max)
{
max = langP[i];lang = i;
}
}
switch (lang)
{
case 1:
return "en";
case 2:
return "zh";
default:
return "auto";
}
}
}
}
首先
【Translate】方法: 就是执行翻译的主方法,进行url拼接、加密、发送请求,接收反馈,最后以字符串形式返回。具体可参考官方的文档。
【ParseResponse】方法: 就是解析反馈的内容,反馈是Json格式,使用了【Newtonsoft.Json】第三方包来解析Json字符串
【detectLanguage】方法: 检测当前输入的是什么语言,本来希望能识别出所有语言,但是发现貌似没那么简单,另外,我的需求也只是要自动识别中英文,把不是中文的翻译成中文,把中文自动翻译成英文,如果有需要,再指定语言就好。
具体怎么识别呢,调用【detectLanguageChar】方法,通过字符的UTF-8编码,中文大概是u4E00-u9FA5 和0x3400, 0x4DB5,取个大概,转换成10进制 (13312~40895)吧,英文26个大小写字母在41~5A和61~7A,取个大概,转换成10进制(65~122),然后根据输入的文本中,哪种字符占比多进行判断。
4、完成整个程序
也就是Form1.cs中的代码
4.1、窗口初始化和支持的语言列表
BDTrans trans;
//支持的语言映射列表
List<KeyValuePair<string, string>> LangList;
public Form1()
{
InitializeComponent();
//初始化语言列表
InitLangs();
trans = new BDTrans();
}
//初始化并给两个ComboBox添加
public void InitLangs()
{
LangList = new List<KeyValuePair<string, string>>();
KeyValuePair<string, string>[] langs = new KeyValuePair<string, string>[]
{
new KeyValuePair<string,string>("auto","自动检测"),
new KeyValuePair<string,string>("zh","中文"),
new KeyValuePair<string,string>("en","英语"),
new KeyValuePair<string,string>("yue","粤语"),
new KeyValuePair<string,string>("wyw","文言文"),
new KeyValuePair<string,string>("jp","日语"),
new KeyValuePair<string,string>("kor","韩语"),
new KeyValuePair<string,string>("fra","法语"),
new KeyValuePair<string,string>("spa","西班牙语"),
new KeyValuePair<string,string>("th","泰语"),
new KeyValuePair<string,string>("ara","阿拉伯语"),
new KeyValuePair<string,string>("ru","俄语"),
new KeyValuePair<string,string>("pt","葡萄牙语"),
new KeyValuePair<string,string>("de","德语"),
new KeyValuePair<string,string>("it","意大利语"),
new KeyValuePair<string,string>("el","希腊语"),
new KeyValuePair<string,string>("nl","荷兰语"),
new KeyValuePair<string,string>("pl","波兰语"),
new KeyValuePair<string,string>("bul","保加利亚语"),
new KeyValuePair<string,string>("est","爱沙尼亚语"),
new KeyValuePair<string,string>("dan","丹麦语"),
new KeyValuePair<string,string>("fin","芬兰语"),
new KeyValuePair<string,string>("cs","捷克语"),
new KeyValuePair<string,string>("rom","罗马尼亚语"),
new KeyValuePair<string,string>("slo","斯洛文尼亚语"),
new KeyValuePair<string,string>("swe","瑞典语"),
new KeyValuePair<string,string>("hu","匈牙利语"),
new KeyValuePair<string,string>("cht","繁体中文"),
new KeyValuePair<string,string>("vie","越南语")
};
for (int i = 0; i < langs.Length; i++)
{
LangList.Add(langs[i]);
coBox_SrcLang.Items.Add(langs[i].Value);
coBox_DstLang.Items.Add(langs[i].Value);
}
coBox_SrcLang.SelectedIndex = 0;
coBox_DstLang.SelectedIndex = 1;
}
4.2、 自动翻译
给【tBox_Src】编辑框添加【TextChanged】事件
//中英文自动翻译
private void tBox_Src_TextChanged(object sender, EventArgs e)
{
string src = tBox_Src.Text;
string from = "en";
string to = "zh";
if (src != "")
{
///判断原语言
from = trans.detectLanguage(tBox_Src.Text);
if (from == "zh")
{ to = "en"; }
//根据检测到的语言 更新一下 comBox_SrcLang和comBox_DstLang
coBox_SrcLang.SelectedItem = LangList.Where<KeyValuePair<string, string>>(x => x.Key == from).ToList()[0].Value;
coBox_DstLang.SelectedItem = LangList.Where<KeyValuePair<string, string>>(x => x.Key == to).ToList()[0].Value;
string dst = trans.Translate(src, from, to);
tBox_Dst.Text = dst;
}
else
{
tBox_Dst.Text = "";
}
}
4.3、 手动指定语言翻译
给【btn_Trans】按钮添加click事件:
private void btn_Trans_Click(object sender, EventArgs e)
{
string from = LangList[coBox_SrcLang.SelectedIndex].Key;
string to = LangList[coBox_DstLang.SelectedIndex].Key;
string src = tBox_Src.Text;
if (src != "")
{
string dst = trans.Translate(src, from, to);
tBox_Dst.Text = dst;
}
else
{
tBox_Dst.Text = "";
}
}
4.4、让程序常驻
不能翻译两句,一不小心点关闭,又得重新开,
所以上一篇就用上了,让程序点关闭时,缩小到右下角通知栏
5、大功告成
翻译一下看看~