本文部分參考了GitHub中wadereye的代碼,在源代碼基礎上修改了部分針對tkk的篩選及使用邏輯。
由於谷歌的tkk值規則一直在變,且api的url也不是固定的,所以做了配置類,方便修改。
全部代碼
GoogleTranslate主類:
public static class GoogleTranslate { public static string TranslateChinese2English(string text) { return Translate(text, "zh-CN", "en"); } /// <summary> /// 谷歌翻譯 /// </summary> /// <param name="text">待翻譯文本</param> /// <param name="fromLanguage">自動檢測:auto</param> /// <param name="toLanguage">中文:zh-CN,英文:en</param> /// <returns>翻譯后文本</returns> public static string Translate(string text, string fromLanguage, string toLanguage) { CookieContainer cc = new CookieContainer(); string GoogleTransBaseUrl = ConfigManager.Instance.GetGoogleTranslate_Url(); var BaseResultHtml = GetResultHtml(GoogleTransBaseUrl, cc, ""); Regex re = new Regex(ConfigManager.Instance.GetGoogleTranslate_tkkRegex()); var TKK = re.Match(BaseResultHtml).ToString();//在返回的HTML中正則匹配TKK的值 //通過js獲取tkk值,本js源碼在根目錄放置,源碼在后文 var GetTkkJS = File.ReadAllText("./gettk.js"); var tk = ExecuteScript("tk(\"" + text + "\",\"" + TKK + "\")", GetTkkJS); string googleTransUrl = string.Format(ConfigManager.Instance.GetGoogleTranslate_API(), fromLanguage, toLanguage, tk, HttpUtility.UrlEncode(text)); var ResultHtml = GetResultHtml(googleTransUrl, cc, ConfigManager.Instance.GetGoogleTranslate_Url()); return GetResultContent(ResultHtml); } /// <summary> /// 解析返回值(重要) /// </summary> /// <param name="resultHtml"></param> /// <returns></returns> private static string GetResultContent(string resultHtml) { string resultContent = ""; if (!string.IsNullOrWhiteSpace(resultHtml)) { JToken tmp = Newtonsoft.Json.JsonConvert.DeserializeObject<JToken>(resultHtml); var mainTranslationInfo = tmp[0]; //originalTextTranscription,translatedTextTranscription 留作備用,根據自己需求判斷是否使用 string originalTextTranscription = null, translatedTextTranscription = null; string[] translation = null; GetMainTranslationInfo(mainTranslationInfo, out translation, ref originalTextTranscription, ref translatedTextTranscription); if (translation.Length > 0) resultContent = string.Join("", translation); } return resultContent; } private static void GetMainTranslationInfo(JToken translationInfo, out string[] translate, ref string originalTextTranscription, ref string translatedTextTranscription) { List<string> translations = new List<string>(); foreach (var item in translationInfo) { if (item.Count() >= 5) translations.Add(item.First.Value<string>()); else { var transcriptionInfo = item; int elementsCount = transcriptionInfo.Count(); if (elementsCount == 3) { translatedTextTranscription = (string)transcriptionInfo[elementsCount - 1]; } else { if (transcriptionInfo[elementsCount - 2] != null) translatedTextTranscription = (string)transcriptionInfo[elementsCount - 2]; else translatedTextTranscription = (string)transcriptionInfo[elementsCount - 1]; originalTextTranscription = (string)transcriptionInfo[elementsCount - 1]; } } } translate = translations.ToArray(); } private static string GetResultHtml(string url, CookieContainer cookie, string referer) { var html = ""; var webRequest = WebRequest.Create(url) as HttpWebRequest; webRequest.Method = "GET"; webRequest.CookieContainer = cookie; webRequest.Referer = referer; webRequest.Timeout = 20000; webRequest.Headers.Add("X-Requested-With:XMLHttpRequest"); webRequest.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"; webRequest.UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36"; using (var webResponse = (HttpWebResponse)webRequest.GetResponse()) { using (var reader = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8)) { html = reader.ReadToEnd(); reader.Close(); webResponse.Close(); } } return html; } /// <summary> /// 執行JS /// </summary> /// <param name="sExpression">參數體</param> /// <param name="sCode">JavaScript代碼的字符串</param> /// <returns></returns> private static string ExecuteScript(string sExpression, string sCode) { MSScriptControl.ScriptControl scriptControl = new MSScriptControl.ScriptControl(); scriptControl.UseSafeSubset = true; scriptControl.Language = "JScript"; scriptControl.AddCode(sCode); try { string str = scriptControl.Eval(sExpression).ToString(); return str; } catch (Exception ex) { string str = ex.Message; } return null; } }
配置類
通過讀取配置文件給主類傳值,方便修改:
public class ConfigHelper { ///<summary> ///返回*.exe.config文件中appSettings配置節的value項 ///</summary> ///<param name="strKey"></param> ///<returns></returns> public string GetAppConfig(string strKey) { string file = System.Windows.Forms.Application.ExecutablePath; Configuration config = ConfigurationManager.OpenExeConfiguration(file); foreach (string key in config.AppSettings.Settings.AllKeys) { if (key == strKey) { return config.AppSettings.Settings[strKey].Value.ToString(); } } return null; } ///<summary> ///在*.exe.config文件中appSettings配置節增加一對鍵值對 ///</summary> ///<param name="newKey"></param> ///<param name="newValue"></param> public void AddAppConfig(string newKey, string newValue) { string file = System.Windows.Forms.Application.ExecutablePath; Configuration config = ConfigurationManager.OpenExeConfiguration(file); bool exist = false; foreach (string key in config.AppSettings.Settings.AllKeys) { if (key == newKey) { exist = true; } } if (exist) { config.AppSettings.Settings.Remove(newKey); } config.AppSettings.Settings.Add(newKey, newValue); config.Save(ConfigurationSaveMode.Modified); ConfigurationManager.RefreshSection("appSettings"); } } public class ConfigManager : ConfigHelper { public static ConfigManager Instance = new ConfigManager(); public string GetGoogleTranslate_Url() { string value= GetAppConfig("GoogleTranslate_Url"); if (string.IsNullOrWhiteSpace(value)) value = "https://translate.google.cn/"; return value; } public string GetGoogleTranslate_API() { string value = GetAppConfig("GoogleTranslate_API"); if (string.IsNullOrWhiteSpace(value)) value = "https://translate.google.cn/translate_a/single?client=webapp&sl={0}&tl={1}&hl=zh-CN&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=sos&dt=ss&dt=t&otf=1&pc=1&ssel=3&tsel=0&xid=45662847&kc=2&tk={2}&q={3}"; return value; } public string GetGoogleTranslate_tkkRegex() { string value = GetAppConfig("GoogleTranslate_tkkRegex"); if (string.IsNullOrWhiteSpace(value)) value = "(?<=tkk:')(.*?)(?=')"; return value; } }
App.config配置:
<appSettings>
<add key="GoogleTranslate_Url" value="https://translate.google.cn/"></add> <add key="GoogleTranslate_API" value="https://translate.google.cn/translate_a/single?client=webapp&sl={0}&tl={1}&hl=zh-CN&dt=at&dt=bd&dt=ex&dt=ld&dt=md&dt=qca&dt=rw&dt=rm&dt=sos&dt=ss&dt=t&otf=1&pc=1&ssel=3&tsel=0&xid=45662847&kc=2&tk={2}&q={3}"></add> <add key="GoogleTranslate_tkkRegex" value="(?<=tkk:')(.*?)(?=')"></add> </appSettings>
gettk.js
本js文件保存在根目錄(文件名:gettk.js),供GoogleTranslate類調用,獲取tkk:
//該文件用來獲取谷歌翻譯tkk值,不能刪除,根據谷歌服務的變化有可能需要修改部分代碼 var b = function (a, b) { for (var d = 0; d < b.length - 2; d += 3) { var c = b.charAt(d + 2), c = "a" <= c ? c.charCodeAt(0) - 87 : Number(c), c = "+" == b.charAt(d + 1) ? a >>> c : a << c; a = "+" == b.charAt(d) ? a + c & 4294967295 : a ^ c } return a } var tk = function (a, TKK) { for (var e = TKK.split("."), h = Number(e[0]) || 0, g = [], d = 0, f = 0; f < a.length; f++) { var c = a.charCodeAt(f); 128 > c ? g[d++] = c : (2048 > c ? g[d++] = c >> 6 | 192 : (55296 == (c & 64512) && f + 1 < a.length && 56320 == (a.charCodeAt(f + 1) & 64512) ? (c = 65536 + ((c & 1023) << 10) + (a.charCodeAt(++f) & 1023), g[d++] = c >> 18 | 240, g[d++] = c >> 12 & 63 | 128) : g[d++] = c >> 12 | 224, g[d++] = c >> 6 & 63 | 128), g[d++] = c & 63 | 128) } a = h; for (d = 0; d < g.length; d++) a += g[d], a = b(a, "+-a^+6"); a = b(a, "+-3^+b+-f"); a ^= Number(e[1]) || 0; 0 > a && (a = (a & 2147483647) + 2147483648); a %= 1E6; return a.toString() + "." + (a ^ h) }
使用
直接調用主類的公用方法即可:
GoogleTranslate.TranslateChinese2English("需要翻譯內容");
示例:
private void button1_Click(object sender, EventArgs e) { richTextBox2.Text = GoogleTranslate.TranslateChinese2English(richTextBox1.Text); }
作者:Mr.Jimmy
出處:https://www.cnblogs.com/JHelius
聯系:yanyangzhihuo@foxmail.com
如有疑問歡迎討論,轉載請注明出處