C#使用Google实现在线翻译

本文部分参考了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&amp;sl={0}&amp;tl={1}&amp;hl=zh-CN&amp;dt=at&amp;dt=bd&amp;dt=ex&amp;dt=ld&amp;dt=md&amp;dt=qca&amp;dt=rw&amp;dt=rm&amp;dt=sos&amp;dt=ss&amp;dt=t&amp;otf=1&amp;pc=1&amp;ssel=3&amp;tsel=0&amp;xid=45662847&amp;kc=2&amp;tk={2}&amp;q={3}"></add>
    <add key="GoogleTranslate_tkkRegex" value="(?&lt;=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);
}

在这里插入图片描述

posted @ 2020-08-25 18:01  Hi-Jimmy  阅读(431)  评论(0编辑  收藏  举报