本文部分参考了GitHub中wadereye的代码,在源代码基础上修改了部分针对tkk的筛选及使用逻辑。
由于谷歌的tkk值规则一直在变,且api的url也不是固定的,所以做了配置类,方便修改。
public static class GoogleTranslate
{
public static string TranslateChinese2English(string text)
{
return Translate(text, "zh-CN", "en");
}
///
/// 谷歌翻译
///
/// 待翻译文本
/// 自动检测:auto
/// 中文:zh-CN,英文:en
/// 翻译后文本
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);
}
///
/// 解析返回值(重要)
///
///
///
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;
}
///
/// 执行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
{
///
///返回*.exe.config文件中appSettings配置节的value项
///
///
///
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;
}
///
///在*.exe.config文件中appSettings配置节增加一对键值对
///
///
///
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;
}
}
<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>
本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);
}