Textractor/extensions/googletranslate.cpp

128 lines
3.4 KiB
C++
Raw Normal View History

2019-02-10 21:46:39 -05:00
#include "extension.h"
#include "network.h"
2019-06-13 04:01:29 -04:00
#include "util.h"
2018-11-03 23:26:53 -04:00
#include <ctime>
2019-06-13 04:01:29 -04:00
#include <QStringList>
2018-11-03 23:26:53 -04:00
2019-02-27 11:33:17 -05:00
extern const wchar_t* TRANSLATION_ERROR;
extern Synchronized<std::wstring> translateTo;
2019-06-13 04:01:29 -04:00
const char* TRANSLATION_PROVIDER = "Google";
2018-11-03 23:26:53 -04:00
QStringList languages
{
"Afrikaans: af",
"Arabic: ar",
"Albanian: sq",
"Belarusian: be",
"Bengali: bn",
"Bosnian: bs",
"Bulgarian: bg",
"Catalan: ca",
"Chinese(Simplified): zh-CH",
"Chinese(Traditional): zh-TW",
"Croatian: hr",
"Czech: cs",
"Danish: da",
"Dutch: nl",
"English: en",
2018-11-03 23:26:53 -04:00
"Esperanto: eo",
"Estonian: et",
"Filipino: tl",
"Finnish: fi",
"French: fr",
"Galician: gl",
"German: de",
"Greek: el",
"Hebrew: iw",
"Hindi: hi",
"Hungarian: hu",
"Icelandic: is",
"Indonesian: id",
"Irish: ga",
"Italian: it",
"Japanese: ja",
"Klingon: tlh",
"Korean: ko",
"Latin: la",
"Latvian: lv",
"Lithuanian: lt",
"Macedonian: mk",
"Malay: ms",
"Maltese: mt",
"Norwegian: no",
"Persian: fa",
"Polish: pl",
"Portuguese: pt",
"Romanian: ro",
"Russian: ru",
"Serbian: sr",
"Slovak: sk",
"Slovenian: sl",
"Somali: so",
"Spanish: es",
"Swahili: sw",
"Swedish: sv",
"Thai: th",
"Turkish: tr",
"Ukranian: uk",
"Urdu: ur",
"Vietnamese: vi",
"Welsh: cy",
"Yiddish: yi",
"Zulu: zu"
};
2019-09-10 18:53:55 -04:00
unsigned TKK = 0;
std::wstring GetTranslationUri(const std::wstring& text)
2018-11-03 23:26:53 -04:00
{
2018-11-08 05:51:20 -05:00
// If no TKK available, use this uri. Can't use too much or google will detect unauthorized access
2019-06-13 04:01:29 -04:00
if (!TKK) return FormatString(L"/translate_a/single?client=gtx&dt=ld&dt=rm&dt=t&tl=%s&q=%s", translateTo->c_str(), text);
2018-11-03 23:26:53 -04:00
// Artikash 8/19/2018: reverse engineered from translate.google.com
2019-02-10 21:46:39 -05:00
std::wstring escapedText;
2019-09-10 18:53:55 -04:00
unsigned a = time(NULL) / 3600, b = a; // the first part of TKK
2019-02-10 21:46:39 -05:00
for (unsigned char ch : WideStringToString(text))
2018-11-03 23:26:53 -04:00
{
2019-06-13 04:01:29 -04:00
escapedText += FormatString(L"%%%02X", (int)ch);
2019-02-10 21:46:39 -05:00
a += ch;
2018-11-03 23:26:53 -04:00
a += a << 10;
a ^= a >> 6;
}
a += a << 3;
a ^= a >> 11;
a += a << 15;
a ^= TKK;
a %= 1000000;
2019-09-10 18:53:55 -04:00
return FormatString(L"/translate_a/single?client=webapp&dt=ld&dt=rm&dt=t&sl=auto&tl=%s&tk=%u.%u&q=%s", translateTo->c_str(), a, a ^ b, escapedText);
2018-11-03 23:26:53 -04:00
}
2019-06-21 23:16:23 -04:00
bool IsHash(const std::wstring& result)
{
return result.size() == 32 && std::all_of(result.begin(), result.end(), [](char ch) { return (ch >= L'0' && ch <= L'9') || (ch >= L'a' && ch <= L'z'); });
2019-06-21 23:16:23 -04:00
}
2019-06-13 04:01:29 -04:00
std::pair<bool, std::wstring> Translate(const std::wstring& text)
2018-11-03 23:26:53 -04:00
{
2019-06-13 04:01:29 -04:00
if (!TKK)
if (HttpRequest httpRequest{ L"Mozilla/5.0 Textractor", L"translate.google.com", L"GET", L"/" })
if (std::wsmatch results; std::regex_search(httpRequest.response, results, std::wregex(L"(\\d{7,})'")))
_InterlockedCompareExchange(&TKK, stoll(results[1]), 0);
2018-11-03 23:26:53 -04:00
2019-09-10 18:53:55 -04:00
if (HttpRequest httpRequest{ L"Mozilla/5.0 Textractor", L"translate.googleapis.com", L"GET", GetTranslationUri(text).c_str() })
2018-11-03 23:26:53 -04:00
{
2019-06-13 04:01:29 -04:00
// Response formatted as JSON: starts with "[[[" and translation is enclosed in quotes followed by a comma
if (httpRequest.response[0] == L'[')
{
std::wstring translation;
for (std::wsmatch results; std::regex_search(httpRequest.response, results, std::wregex(L"\\[\"(.*?)\",[n\"]")); httpRequest.response = results.suffix())
2019-06-21 23:16:23 -04:00
if (!IsHash(results[1])) translation += std::wstring(results[1]) + L" ";
2019-06-13 04:01:29 -04:00
if (!translation.empty()) return { true, translation };
}
return { false, FormatString(L"%s (TKK=%u)", TRANSLATION_ERROR, _InterlockedExchange(&TKK, 0)) };
2018-11-03 23:26:53 -04:00
}
2019-06-13 04:01:29 -04:00
else return { false, FormatString(L"%s (code=%u)", TRANSLATION_ERROR, httpRequest.errorCode) };
2018-12-18 16:32:28 -05:00
}