improve translation extension ui, add language detection for papago and systran, add more languages to systran, improve deepl translation and bing error handling
This commit is contained in:
parent
444974ee8a
commit
ac95d873f1
@ -1,100 +1,212 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
|
#include "translatewrapper.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
|
|
||||||
extern const wchar_t* TRANSLATION_ERROR;
|
extern const wchar_t* TRANSLATION_ERROR;
|
||||||
|
|
||||||
extern Synchronized<std::wstring> translateTo, translateFrom, authKey;
|
|
||||||
|
|
||||||
const char* TRANSLATION_PROVIDER = "Bing Translate";
|
const char* TRANSLATION_PROVIDER = "Bing Translate";
|
||||||
const char* GET_API_KEY_FROM = "https://www.microsoft.com/en-us/translator/business/trial/#get-started";
|
const char* GET_API_KEY_FROM = "https://www.microsoft.com/en-us/translator/business/trial/#get-started";
|
||||||
QStringList languages
|
extern const QStringList languagesTo
|
||||||
{
|
{
|
||||||
"Afrikaans: af",
|
"Afrikaans",
|
||||||
"Arabic: ar",
|
"Albanian",
|
||||||
"Bangla: bn",
|
"Amharic",
|
||||||
"Bosnian: bs",
|
"Arabic",
|
||||||
"Bulgarian: bg",
|
"Armenian",
|
||||||
"Cantonese (traditional): yue",
|
"Assamese",
|
||||||
"Catalan: ca",
|
"Azerbaijani",
|
||||||
"Chinese (simplified): zh-Hans",
|
"Bangla",
|
||||||
"Chinese (traditional): zh-Hant",
|
"Bosnian (Latin)",
|
||||||
"Croatian: hr",
|
"Bulgarian",
|
||||||
"Czech: cs",
|
"Cantonese (Traditional)",
|
||||||
"Danish: da",
|
"Catalan",
|
||||||
"Dutch: nl",
|
"Chinese (Simplified)",
|
||||||
"English: en",
|
"Chinese (Traditional)",
|
||||||
"Estonian: et",
|
"Croatian",
|
||||||
"Fijian: fj",
|
"Czech",
|
||||||
"Filipino: fil",
|
"Danish",
|
||||||
"Finnish: fi",
|
"Dari",
|
||||||
"French: fr",
|
"Dutch",
|
||||||
"German: de",
|
"English",
|
||||||
"Greek: el",
|
"Estonian",
|
||||||
"Haitian Creole: ht",
|
"Fijian",
|
||||||
"Hebrew: he",
|
"Filipino",
|
||||||
"Hindi: hi",
|
"Finnish",
|
||||||
"Hmong Daw: mww",
|
"French",
|
||||||
"Hungarian: hu",
|
"French (Canada)",
|
||||||
"Icelandic: is",
|
"German",
|
||||||
"Indonesian: id",
|
"Greek",
|
||||||
"Irish: ga",
|
"Gujarati",
|
||||||
"Italian: it",
|
"Haitian Creole",
|
||||||
"Japanese: ja",
|
"Hebrew",
|
||||||
"Kannada: kn",
|
"Hindi",
|
||||||
"Klingon: tlh",
|
"Hmong Daw",
|
||||||
"Korean: ko",
|
"Hungarian",
|
||||||
"Latvian: lv",
|
"Icelandic",
|
||||||
"Lithuanian: lt",
|
"Indonesian",
|
||||||
"Malagasy: mg",
|
"Inuktitut",
|
||||||
"Malay: ms",
|
"Irish",
|
||||||
"Malayalam: ml",
|
"Italian",
|
||||||
"Maltese: mt",
|
"Japanese",
|
||||||
"Maori: mi",
|
"Kannada",
|
||||||
"Norwegian: nb",
|
"Kazakh",
|
||||||
"Persian: fa",
|
"Khmer",
|
||||||
"Polish: pl",
|
"Klingon",
|
||||||
"Portuguese (Brazil): pt",
|
"Korean",
|
||||||
"Portuguese (Portugal): pt-pt",
|
"Kurdish (Central)",
|
||||||
"Punjabi: pa",
|
"Kurdish (Northern)",
|
||||||
"Romanian: ro",
|
"Lao",
|
||||||
"Russian: ru",
|
"Latvian",
|
||||||
"Samoan: sm",
|
"Lithuanian",
|
||||||
"Serbian (Cyrillic): sr-Cyrl",
|
"Malagasy",
|
||||||
"Serbian (Latin): sr-Latn",
|
"Malay",
|
||||||
"Slovak: sk",
|
"Malayalam",
|
||||||
"Slovenian: sl",
|
"Maltese",
|
||||||
"Spanish: es",
|
"Maori",
|
||||||
"Swahili: sw",
|
"Marathi",
|
||||||
"Swedish: sv",
|
"Myanmar",
|
||||||
"Tahitian: ty",
|
"Nepali",
|
||||||
"Tamil: ta",
|
"Norwegian",
|
||||||
"Telugu: te",
|
"Odia",
|
||||||
"Thai: th",
|
"Pashto",
|
||||||
"Tongan: to",
|
"Persian",
|
||||||
"Turkish: tr",
|
"Polish",
|
||||||
"Ukrainian: uk",
|
"Portuguese (Brazil)",
|
||||||
"Urdu: ur",
|
"Portuguese (Portugal)",
|
||||||
"Vietnamese: vi",
|
"Punjabi",
|
||||||
"Welsh: cy",
|
"Queretaro Otomi",
|
||||||
"Yucatec Maya: yua"
|
"Romanian",
|
||||||
|
"Russian",
|
||||||
|
"Samoan",
|
||||||
|
"Serbian (Cyrillic)",
|
||||||
|
"Serbian (Latin)",
|
||||||
|
"Slovak",
|
||||||
|
"Slovenian",
|
||||||
|
"Spanish",
|
||||||
|
"Swahili",
|
||||||
|
"Swedish",
|
||||||
|
"Tahitian",
|
||||||
|
"Tamil",
|
||||||
|
"Telugu",
|
||||||
|
"Thai",
|
||||||
|
"Tigrinya",
|
||||||
|
"Tongan",
|
||||||
|
"Turkish",
|
||||||
|
"Ukrainian",
|
||||||
|
"Urdu",
|
||||||
|
"Vietnamese",
|
||||||
|
"Welsh",
|
||||||
|
"Yucatec Maya"
|
||||||
|
}, languagesFrom = languagesTo;
|
||||||
|
extern const std::unordered_map<std::wstring, std::wstring> codes
|
||||||
|
{
|
||||||
|
{ { L"Afrikaans" }, { L"af" } },
|
||||||
|
{ { L"Albanian" }, { L"sq" } },
|
||||||
|
{ { L"Amharic" }, { L"am" } },
|
||||||
|
{ { L"Arabic" }, { L"ar" } },
|
||||||
|
{ { L"Armenian" }, { L"hy" } },
|
||||||
|
{ { L"Assamese" }, { L"as" } },
|
||||||
|
{ { L"Azerbaijani" }, { L"az" } },
|
||||||
|
{ { L"Bangla" }, { L"bn" } },
|
||||||
|
{ { L"Bosnian (Latin)" }, { L"bs" } },
|
||||||
|
{ { L"Bulgarian" }, { L"bg" } },
|
||||||
|
{ { L"Cantonese (Traditional)" }, { L"yue" } },
|
||||||
|
{ { L"Catalan" }, { L"ca" } },
|
||||||
|
{ { L"Chinese (Simplified)" }, { L"zh-Hans" } },
|
||||||
|
{ { L"Chinese (Traditional)" }, { L"zh-Hant" } },
|
||||||
|
{ { L"Croatian" }, { L"hr" } },
|
||||||
|
{ { L"Czech" }, { L"cs" } },
|
||||||
|
{ { L"Danish" }, { L"da" } },
|
||||||
|
{ { L"Dari" }, { L"prs" } },
|
||||||
|
{ { L"Dutch" }, { L"nl" } },
|
||||||
|
{ { L"English" }, { L"en" } },
|
||||||
|
{ { L"Estonian" }, { L"et" } },
|
||||||
|
{ { L"Fijian" }, { L"fj" } },
|
||||||
|
{ { L"Filipino" }, { L"fil" } },
|
||||||
|
{ { L"Finnish" }, { L"fi" } },
|
||||||
|
{ { L"French" }, { L"fr" } },
|
||||||
|
{ { L"French (Canada)" }, { L"fr-ca" } },
|
||||||
|
{ { L"German" }, { L"de" } },
|
||||||
|
{ { L"Greek" }, { L"el" } },
|
||||||
|
{ { L"Gujarati" }, { L"gu" } },
|
||||||
|
{ { L"Haitian Creole" }, { L"ht" } },
|
||||||
|
{ { L"Hebrew" }, { L"he" } },
|
||||||
|
{ { L"Hindi" }, { L"hi" } },
|
||||||
|
{ { L"Hmong Daw" }, { L"mww" } },
|
||||||
|
{ { L"Hungarian" }, { L"hu" } },
|
||||||
|
{ { L"Icelandic" }, { L"is" } },
|
||||||
|
{ { L"Indonesian" }, { L"id" } },
|
||||||
|
{ { L"Inuktitut" }, { L"iu" } },
|
||||||
|
{ { L"Irish" }, { L"ga" } },
|
||||||
|
{ { L"Italian" }, { L"it" } },
|
||||||
|
{ { L"Japanese" }, { L"ja" } },
|
||||||
|
{ { L"Kannada" }, { L"kn" } },
|
||||||
|
{ { L"Kazakh" }, { L"kk" } },
|
||||||
|
{ { L"Khmer" }, { L"km" } },
|
||||||
|
{ { L"Klingon" }, { L"tlh-Latn" } },
|
||||||
|
{ { L"Korean" }, { L"ko" } },
|
||||||
|
{ { L"Kurdish (Central)" }, { L"ku" } },
|
||||||
|
{ { L"Kurdish (Northern)" }, { L"kmr" } },
|
||||||
|
{ { L"Lao" }, { L"lo" } },
|
||||||
|
{ { L"Latvian" }, { L"lv" } },
|
||||||
|
{ { L"Lithuanian" }, { L"lt" } },
|
||||||
|
{ { L"Malagasy" }, { L"mg" } },
|
||||||
|
{ { L"Malay" }, { L"ms" } },
|
||||||
|
{ { L"Malayalam" }, { L"ml" } },
|
||||||
|
{ { L"Maltese" }, { L"mt" } },
|
||||||
|
{ { L"Maori" }, { L"mi" } },
|
||||||
|
{ { L"Marathi" }, { L"mr" } },
|
||||||
|
{ { L"Myanmar" }, { L"my" } },
|
||||||
|
{ { L"Nepali" }, { L"ne" } },
|
||||||
|
{ { L"Norwegian" }, { L"nb" } },
|
||||||
|
{ { L"Odia" }, { L"or" } },
|
||||||
|
{ { L"Pashto" }, { L"ps" } },
|
||||||
|
{ { L"Persian" }, { L"fa" } },
|
||||||
|
{ { L"Polish" }, { L"pl" } },
|
||||||
|
{ { L"Portuguese (Brazil)" }, { L"pt" } },
|
||||||
|
{ { L"Portuguese (Portugal)" }, { L"pt-pt" } },
|
||||||
|
{ { L"Punjabi" }, { L"pa" } },
|
||||||
|
{ { L"Queretaro Otomi" }, { L"otq" } },
|
||||||
|
{ { L"Romanian" }, { L"ro" } },
|
||||||
|
{ { L"Russian" }, { L"ru" } },
|
||||||
|
{ { L"Samoan" }, { L"sm" } },
|
||||||
|
{ { L"Serbian (Cyrillic)" }, { L"sr-Cyrl" } },
|
||||||
|
{ { L"Serbian (Latin)" }, { L"sr-Latn" } },
|
||||||
|
{ { L"Slovak" }, { L"sk" } },
|
||||||
|
{ { L"Slovenian" }, { L"sl" } },
|
||||||
|
{ { L"Spanish" }, { L"es" } },
|
||||||
|
{ { L"Swahili" }, { L"sw" } },
|
||||||
|
{ { L"Swedish" }, { L"sv" } },
|
||||||
|
{ { L"Tahitian" }, { L"ty" } },
|
||||||
|
{ { L"Tamil" }, { L"ta" } },
|
||||||
|
{ { L"Telugu" }, { L"te" } },
|
||||||
|
{ { L"Thai" }, { L"th" } },
|
||||||
|
{ { L"Tigrinya" }, { L"ti" } },
|
||||||
|
{ { L"Tongan" }, { L"to" } },
|
||||||
|
{ { L"Turkish" }, { L"tr" } },
|
||||||
|
{ { L"Ukrainian" }, { L"uk" } },
|
||||||
|
{ { L"Urdu" }, { L"ur" } },
|
||||||
|
{ { L"Vietnamese" }, { L"vi" } },
|
||||||
|
{ { L"Welsh" }, { L"cy" } },
|
||||||
|
{ { L"Yucatec Maya" }, { L"yua" } },
|
||||||
|
{ { L"?" }, { L"auto-detect" } }
|
||||||
};
|
};
|
||||||
std::wstring autoDetectLanguage = L"auto-detect";
|
|
||||||
|
|
||||||
bool translateSelectedOnly = false, rateLimitAll = true, rateLimitSelected = false, useCache = true, useFilter = true;
|
bool translateSelectedOnly = false, rateLimitAll = true, rateLimitSelected = false, useCache = true, useFilter = true;
|
||||||
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
|
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
|
||||||
|
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
std::pair<bool, std::wstring> Translate(const std::wstring& text, TranslationParam tlp)
|
||||||
{
|
{
|
||||||
if (!authKey->empty())
|
if (!tlp.authKey.empty())
|
||||||
{
|
{
|
||||||
std::wstring translateFromComponent = translateFrom.Copy() == autoDetectLanguage ? L"" : L"&from=" + translateFrom.Copy();
|
std::wstring translateFromComponent = tlp.translateFrom == L"?" ? L"" : L"&from=" + codes.at(tlp.translateFrom);
|
||||||
if (HttpRequest httpRequest{
|
if (HttpRequest httpRequest{
|
||||||
L"Mozilla/5.0 Textractor",
|
L"Mozilla/5.0 Textractor",
|
||||||
L"api.cognitive.microsofttranslator.com",
|
L"api.cognitive.microsofttranslator.com",
|
||||||
L"POST",
|
L"POST",
|
||||||
FormatString(L"/translate?api-version=3.0&to=%s%s", translateTo.Copy(), translateFromComponent).c_str(),
|
FormatString(L"/translate?api-version=3.0&to=%s%s", codes.at(tlp.translateTo), translateFromComponent).c_str(),
|
||||||
FormatString(R"([{"text":"%s"}])", JSON::Escape(WideStringToString(text))),
|
FormatString(R"([{"text":"%s"}])", JSON::Escape(WideStringToString(text))),
|
||||||
FormatString(L"Content-Type: application/json; charset=UTF-8\r\nOcp-Apim-Subscription-Key:%s", authKey.Copy()).c_str()
|
FormatString(L"Content-Type: application/json; charset=UTF-8\r\nOcp-Apim-Subscription-Key:%s", tlp.authKey).c_str()
|
||||||
})
|
})
|
||||||
if (auto translation = Copy(JSON::Parse(httpRequest.response)[0][L"translations"][0][L"text"].String())) return { true, translation.value() };
|
if (auto translation = Copy(JSON::Parse(httpRequest.response)[0][L"translations"][0][L"text"].String())) return { true, translation.value() };
|
||||||
else return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, httpRequest.response) };
|
else return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, httpRequest.response) };
|
||||||
@ -102,15 +214,17 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Synchronized<std::wstring> token;
|
static Synchronized<std::wstring> token;
|
||||||
if (token->empty()) if (HttpRequest httpRequest{ L"Mozilla/5.0 Textractor", L"www.bing.com", L"GET", L"translator" })
|
if (token->empty())
|
||||||
if (auto tokenPos = httpRequest.response.find(L"[" + std::to_wstring(time(nullptr) / 10)); tokenPos != std::string::npos)
|
if (HttpRequest httpRequest{ L"Mozilla/5.0 Textractor", L"www.bing.com", L"GET", L"translator" })
|
||||||
token->assign(FormatString(L"&key=%s&token=%s", httpRequest.response.substr(tokenPos + 1, 13), httpRequest.response.substr(tokenPos + 16, 32)));
|
if (auto tokenPos = httpRequest.response.find(L"[" + std::to_wstring(time(nullptr) / 100)); tokenPos != std::string::npos)
|
||||||
if (token->empty()) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, L"token missing") };
|
token->assign(FormatString(L"&key=%s&token=%s", httpRequest.response.substr(tokenPos + 1, 13), httpRequest.response.substr(tokenPos + 16, 32)));
|
||||||
|
else return { false, FormatString(L"%s: %s\ntoken not found", TRANSLATION_ERROR, httpRequest.response) };
|
||||||
|
else return { false, FormatString(L"%s: could not acquire token", TRANSLATION_ERROR) };
|
||||||
if (HttpRequest httpRequest{
|
if (HttpRequest httpRequest{
|
||||||
L"Mozilla/5.0 Textractor",
|
L"Mozilla/5.0 Textractor",
|
||||||
L"www.bing.com",
|
L"www.bing.com",
|
||||||
L"POST",
|
L"POST",
|
||||||
FormatString(L"/ttranslatev3?fromLang=%s&to=%s&text=%s%s", translateFrom.Copy(), translateTo.Copy(), Escape(text), token.Copy()).c_str()
|
FormatString(L"/ttranslatev3?fromLang=%s&to=%s&text=%s%s", codes.at(tlp.translateFrom), codes.at(tlp.translateTo), Escape(text), token.Copy()).c_str()
|
||||||
})
|
})
|
||||||
if (auto translation = Copy(JSON::Parse(httpRequest.response)[0][L"translations"][0][L"text"].String())) return { true, translation.value() };
|
if (auto translation = Copy(JSON::Parse(httpRequest.response)[0][L"translations"][0][L"text"].String())) return { true, translation.value() };
|
||||||
else return { false, FormatString(L"%s (token=%s): %s", TRANSLATION_ERROR, std::exchange(token.Acquire().contents, L""), httpRequest.response) };
|
else return { false, FormatString(L"%s (token=%s): %s", TRANSLATION_ERROR, std::exchange(token.Acquire().contents, L""), httpRequest.response) };
|
||||||
|
@ -1,75 +1,126 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
|
#include "translatewrapper.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
extern const wchar_t* TRANSLATION_ERROR;
|
extern const wchar_t* TRANSLATION_ERROR;
|
||||||
|
|
||||||
extern Synchronized<std::wstring> translateTo, translateFrom, authKey;
|
|
||||||
|
|
||||||
const char* TRANSLATION_PROVIDER = "DeepL Translate";
|
const char* TRANSLATION_PROVIDER = "DeepL Translate";
|
||||||
const char* GET_API_KEY_FROM = "https://www.deepl.com/pro.html";
|
const char* GET_API_KEY_FROM = "https://www.deepl.com/pro.html";
|
||||||
QStringList languages
|
extern const QStringList languagesTo
|
||||||
{
|
{
|
||||||
"Bulgarian: BG",
|
"Bulgarian",
|
||||||
"Chinese: ZH",
|
"Chinese (Simplified)",
|
||||||
"Czech: CS",
|
"Czech",
|
||||||
"Danish: DA",
|
"Danish",
|
||||||
"Dutch: NL",
|
"Dutch",
|
||||||
"English: EN",
|
"English (American)",
|
||||||
"Estonian: ET",
|
"English (British)",
|
||||||
"Finnish: FI",
|
"Estonian",
|
||||||
"French: FR",
|
"Finnish",
|
||||||
"German: DE",
|
"French",
|
||||||
"Greek: EL",
|
"German",
|
||||||
"Hungarian: HU",
|
"Greek",
|
||||||
"Italian: IT",
|
"Hungarian",
|
||||||
"Japanese: JA",
|
"Italian",
|
||||||
"Latvian: LV",
|
"Japanese",
|
||||||
"Lithuanian: LT",
|
"Latvian",
|
||||||
"Polish: PL",
|
"Lithuanian",
|
||||||
"Portuguese: PT",
|
"Polish",
|
||||||
"Romanian: RO",
|
"Portuguese (Brazil)",
|
||||||
"Russian: RU",
|
"Portuguese (Portugal)",
|
||||||
"Slovak: SK",
|
"Romanian",
|
||||||
"Slovenian: SL",
|
"Russian",
|
||||||
"Spanish: ES",
|
"Slovak",
|
||||||
"Swedish: SV"
|
"Slovenian",
|
||||||
|
"Spanish",
|
||||||
|
"Swedish"
|
||||||
|
},
|
||||||
|
languagesFrom
|
||||||
|
{
|
||||||
|
"Bulgarian",
|
||||||
|
"Chinese",
|
||||||
|
"Czech",
|
||||||
|
"Danish",
|
||||||
|
"Dutch",
|
||||||
|
"English",
|
||||||
|
"Estonian",
|
||||||
|
"Finnish",
|
||||||
|
"French",
|
||||||
|
"German",
|
||||||
|
"Greek",
|
||||||
|
"Hungarian",
|
||||||
|
"Italian",
|
||||||
|
"Japanese",
|
||||||
|
"Latvian",
|
||||||
|
"Lithuanian",
|
||||||
|
"Polish",
|
||||||
|
"Portuguese",
|
||||||
|
"Romanian",
|
||||||
|
"Russian",
|
||||||
|
"Slovak",
|
||||||
|
"Slovenian",
|
||||||
|
"Spanish",
|
||||||
|
"Swedish"
|
||||||
|
};
|
||||||
|
extern const std::unordered_map<std::wstring, std::wstring> codes
|
||||||
|
{
|
||||||
|
{ { L"Bulgarian" }, { L"BG" } },
|
||||||
|
{ { L"Chinese" }, { L"ZH" } },
|
||||||
|
{ { L"Chinese (Simplified)" }, { L"ZH" } },
|
||||||
|
{ { L"Czech" }, { L"CS" } },
|
||||||
|
{ { L"Danish" }, { L"DA" } },
|
||||||
|
{ { L"Dutch" }, { L"NL" } },
|
||||||
|
{ { L"English" }, { L"EN" } },
|
||||||
|
{ { L"English (American)" }, { L"EN-US" } },
|
||||||
|
{ { L"English (British)" }, { L"EN-GB" } },
|
||||||
|
{ { L"Estonian" }, { L"ET" } },
|
||||||
|
{ { L"Finnish" }, { L"FI" } },
|
||||||
|
{ { L"French" }, { L"FR" } },
|
||||||
|
{ { L"German" }, { L"DE" } },
|
||||||
|
{ { L"Greek" }, { L"EL" } },
|
||||||
|
{ { L"Hungarian" }, { L"HU" } },
|
||||||
|
{ { L"Italian" }, { L"IT" } },
|
||||||
|
{ { L"Japanese" }, { L"JA" } },
|
||||||
|
{ { L"Latvian" }, { L"LV" } },
|
||||||
|
{ { L"Lithuanian" }, { L"LT" } },
|
||||||
|
{ { L"Polish" }, { L"PL" } },
|
||||||
|
{ { L"Portuguese" }, { L"PT" } },
|
||||||
|
{ { L"Portuguese (Brazil)" }, { L"PT-BR" } },
|
||||||
|
{ { L"Portuguese (Portugal)" }, { L"PT-PT" } },
|
||||||
|
{ { L"Romanian" }, { L"RO" } },
|
||||||
|
{ { L"Russian" }, { L"RU" } },
|
||||||
|
{ { L"Slovak" }, { L"SK" } },
|
||||||
|
{ { L"Slovenian" }, { L"SL" } },
|
||||||
|
{ { L"Spanish" }, { L"ES" } },
|
||||||
|
{ { L"Swedish" }, { L"SV" } },
|
||||||
|
{ { L"?" }, { L"auto" } }
|
||||||
};
|
};
|
||||||
std::wstring autoDetectLanguage = L"auto";
|
|
||||||
|
|
||||||
bool translateSelectedOnly = true, rateLimitAll = true, rateLimitSelected = true, useCache = true, useFilter = true;
|
bool translateSelectedOnly = true, rateLimitAll = true, rateLimitSelected = true, useCache = true, useFilter = true;
|
||||||
int tokenCount = 10, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
|
int tokenCount = 10, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
|
||||||
|
|
||||||
enum KeyType { CAT, REST };
|
enum KeyType { CAT, REST };
|
||||||
int keyType = REST;
|
int keyType = REST;
|
||||||
enum PlanLevel { FREE, PAID };
|
|
||||||
int planLevel = PAID;
|
|
||||||
|
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
std::pair<bool, std::wstring> Translate(const std::wstring& text, TranslationParam tlp)
|
||||||
{
|
{
|
||||||
if (!authKey->empty())
|
if (!tlp.authKey.empty())
|
||||||
{
|
{
|
||||||
std::string translateFromComponent = translateFrom.Copy() == autoDetectLanguage ? "" : "&source_lang=" + WideStringToString(translateFrom.Copy());
|
std::string translateFromComponent = tlp.translateFrom == L"?" ? "" : "&source_lang=" + WideStringToString(codes.at(tlp.translateFrom));
|
||||||
if (HttpRequest httpRequest{
|
if (HttpRequest httpRequest{
|
||||||
L"Mozilla/5.0 Textractor",
|
L"Mozilla/5.0 Textractor",
|
||||||
planLevel == PAID ? L"api.deepl.com" : L"api-free.deepl.com",
|
tlp.authKey.find(L":fx") == std::string::npos ? L"api.deepl.com" : L"api-free.deepl.com",
|
||||||
L"POST",
|
L"POST",
|
||||||
keyType == CAT ? L"/v1/translate" : L"/v2/translate",
|
keyType == CAT ? L"/v1/translate" : L"/v2/translate",
|
||||||
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()) + translateFromComponent,
|
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), tlp.authKey, codes.at(tlp.translateTo)) + translateFromComponent,
|
||||||
L"Content-Type: application/x-www-form-urlencoded"
|
L"Content-Type: application/x-www-form-urlencoded"
|
||||||
}; httpRequest && (!httpRequest.response.empty() || (httpRequest = HttpRequest{
|
}; httpRequest && (httpRequest.response.find(L"translations") != std::string::npos || (httpRequest = HttpRequest{
|
||||||
L"Mozilla/5.0 Textractor",
|
L"Mozilla/5.0 Textractor",
|
||||||
planLevel == PAID ? L"api.deepl.com" : L"api-free.deepl.com",
|
tlp.authKey.find(L":fx") == std::string::npos ? L"api.deepl.com" : L"api-free.deepl.com",
|
||||||
L"POST",
|
L"POST",
|
||||||
(keyType = !keyType) == CAT ? L"/v1/translate" : L"/v2/translate",
|
(keyType = !keyType) == CAT ? L"/v1/translate" : L"/v2/translate",
|
||||||
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()) + translateFromComponent,
|
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), tlp.authKey, codes.at(tlp.translateTo)) + translateFromComponent,
|
||||||
L"Content-Type: application/x-www-form-urlencoded"
|
|
||||||
})) && (httpRequest.response.find(L"Wrong endpoint. Use") == std::string::npos || (httpRequest = HttpRequest{
|
|
||||||
L"Mozilla/5.0 Textractor",
|
|
||||||
(planLevel = !planLevel) == PAID ? L"api.deepl.com" : L"api-free.deepl.com",
|
|
||||||
L"POST",
|
|
||||||
keyType == CAT ? L"/v1/translate" : L"/v2/translate",
|
|
||||||
FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()) + translateFromComponent,
|
|
||||||
L"Content-Type: application/x-www-form-urlencoded"
|
L"Content-Type: application/x-www-form-urlencoded"
|
||||||
})))
|
})))
|
||||||
// Response formatted as JSON: translation starts with text":" and ends with "}]
|
// Response formatted as JSON: translation starts with text":" and ends with "}]
|
||||||
@ -92,7 +143,7 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
|||||||
"priority": -1,
|
"priority": -1,
|
||||||
"timestamp": %lld,
|
"timestamp": %lld,
|
||||||
"lang": {
|
"lang": {
|
||||||
"target_lang": "%S",
|
"target_lang": "%.2S",
|
||||||
"source_lang_user_selected": "%S"
|
"source_lang_user_selected": "%S"
|
||||||
},
|
},
|
||||||
"jobs": [{
|
"jobs": [{
|
||||||
@ -105,7 +156,7 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
|||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)", id, r + (n - r % n), translateTo.Copy(), translateFrom.Copy(), JSON::Escape(WideStringToString(text)));
|
)", id, r + (n - r % n), codes.at(tlp.translateTo), codes.at(tlp.translateFrom), JSON::Escape(WideStringToString(text)));
|
||||||
// missing accept-encoding header since it fucks up HttpRequest
|
// missing accept-encoding header since it fucks up HttpRequest
|
||||||
if (HttpRequest httpRequest{
|
if (HttpRequest httpRequest{
|
||||||
L"Mozilla/5.0 Textractor",
|
L"Mozilla/5.0 Textractor",
|
||||||
|
@ -1,45 +1,105 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
|
#include "translatewrapper.h"
|
||||||
#include "devtools.h"
|
#include "devtools.h"
|
||||||
|
|
||||||
extern const wchar_t* ERROR_START_CHROME;
|
extern const wchar_t* ERROR_START_CHROME;
|
||||||
extern const wchar_t* TRANSLATION_ERROR;
|
extern const wchar_t* TRANSLATION_ERROR;
|
||||||
|
|
||||||
extern Synchronized<std::wstring> translateTo, translateFrom;
|
|
||||||
|
|
||||||
const char* TRANSLATION_PROVIDER = "DevTools DeepL Translate";
|
const char* TRANSLATION_PROVIDER = "DevTools DeepL Translate";
|
||||||
const char* GET_API_KEY_FROM = nullptr;
|
const char* GET_API_KEY_FROM = nullptr;
|
||||||
|
|
||||||
|
extern const QStringList languagesTo
|
||||||
|
{
|
||||||
|
"Bulgarian",
|
||||||
|
"Chinese (Simplified)",
|
||||||
|
"Czech",
|
||||||
|
"Danish",
|
||||||
|
"Dutch",
|
||||||
|
"English (American)",
|
||||||
|
"English (British)",
|
||||||
|
"Estonian",
|
||||||
|
"Finnish",
|
||||||
|
"French",
|
||||||
|
"German",
|
||||||
|
"Greek",
|
||||||
|
"Hungarian",
|
||||||
|
"Italian",
|
||||||
|
"Japanese",
|
||||||
|
"Latvian",
|
||||||
|
"Lithuanian",
|
||||||
|
"Polish",
|
||||||
|
"Portuguese",
|
||||||
|
"Portuguese (Brazilian)",
|
||||||
|
"Romanian",
|
||||||
|
"Russian",
|
||||||
|
"Slovak",
|
||||||
|
"Slovenian",
|
||||||
|
"Spanish",
|
||||||
|
"Swedish"
|
||||||
|
},
|
||||||
|
languagesFrom =
|
||||||
|
{
|
||||||
|
"Bulgarian",
|
||||||
|
"Chinese",
|
||||||
|
"Czech",
|
||||||
|
"Danish",
|
||||||
|
"Dutch",
|
||||||
|
"English",
|
||||||
|
"Estonian",
|
||||||
|
"Finnish",
|
||||||
|
"French",
|
||||||
|
"German",
|
||||||
|
"Greek",
|
||||||
|
"Hungarian",
|
||||||
|
"Italian",
|
||||||
|
"Japanese",
|
||||||
|
"Latvian",
|
||||||
|
"Lithuanian",
|
||||||
|
"Polish",
|
||||||
|
"Portuguese",
|
||||||
|
"Romanian",
|
||||||
|
"Russian",
|
||||||
|
"Slovak",
|
||||||
|
"Slovenian",
|
||||||
|
"Spanish",
|
||||||
|
"Swedish"
|
||||||
|
};
|
||||||
|
extern const std::unordered_map<std::wstring, std::wstring> codes
|
||||||
|
{
|
||||||
|
{ { L"Bulgarian" }, { L"Bulgarian" } },
|
||||||
|
{ { L"Chinese" }, { L"Chinese" } },
|
||||||
|
{ { L"Chinese (Simplified)" }, { L"Chinese (simplified)" } },
|
||||||
|
{ { L"Czech" }, { L"Czech" } },
|
||||||
|
{ { L"Danish" }, { L"Danish" } },
|
||||||
|
{ { L"Dutch" }, { L"Dutch" } },
|
||||||
|
{ { L"English" }, { L"English" } },
|
||||||
|
{ { L"English (American)" }, { L"English (American)" } },
|
||||||
|
{ { L"English (British)" }, { L"English (British)" } },
|
||||||
|
{ { L"Estonian" }, { L"Estonian" } },
|
||||||
|
{ { L"Finnish" }, { L"Finnish" } },
|
||||||
|
{ { L"French" }, { L"French" } },
|
||||||
|
{ { L"German" }, { L"German" } },
|
||||||
|
{ { L"Greek" }, { L"Greek" } },
|
||||||
|
{ { L"Hungarian" }, { L"Hungarian" } },
|
||||||
|
{ { L"Italian" }, { L"Italian" } },
|
||||||
|
{ { L"Japanese" }, { L"Japanese" } },
|
||||||
|
{ { L"Latvian" }, { L"Latvian" } },
|
||||||
|
{ { L"Lithuanian" }, { L"Lithuanian" } },
|
||||||
|
{ { L"Polish" }, { L"Polish" } },
|
||||||
|
{ { L"Portuguese" }, { L"Portuguese" } },
|
||||||
|
{ { L"Portuguese (Brazilian)" }, { L"Portuguese (Brazilian)" } },
|
||||||
|
{ { L"Romanian" }, { L"Romanian" } },
|
||||||
|
{ { L"Russian" }, { L"Russian" } },
|
||||||
|
{ { L"Slovak" }, { L"Slovak" } },
|
||||||
|
{ { L"Slovenian" }, { L"Slovenian" } },
|
||||||
|
{ { L"Spanish" }, { L"Spanish" } },
|
||||||
|
{ { L"Swedish" }, { L"Swedish" } },
|
||||||
|
{ { L"?" }, { L"Any language (detect)" } }
|
||||||
|
};
|
||||||
|
|
||||||
bool translateSelectedOnly = true, rateLimitAll = false, rateLimitSelected = false, useCache = true, useFilter = true;
|
bool translateSelectedOnly = true, rateLimitAll = false, rateLimitSelected = false, useCache = true, useFilter = true;
|
||||||
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 2500;
|
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 2500;
|
||||||
|
|
||||||
QStringList languages
|
|
||||||
{
|
|
||||||
"Bulgarian: BG",
|
|
||||||
"Chinese: ZH",
|
|
||||||
"Czech: CS",
|
|
||||||
"Danish: DA",
|
|
||||||
"Dutch: NL",
|
|
||||||
"English: EN",
|
|
||||||
"Estonian: ET",
|
|
||||||
"Finnish: FI",
|
|
||||||
"French: FR",
|
|
||||||
"German: DE",
|
|
||||||
"Greek: EL",
|
|
||||||
"Hungarian: HU",
|
|
||||||
"Italian: IT",
|
|
||||||
"Japanese: JA",
|
|
||||||
"Latvian: LV",
|
|
||||||
"Lithuanian: LT",
|
|
||||||
"Polish: PL",
|
|
||||||
"Portuguese: PT",
|
|
||||||
"Romanian: RO",
|
|
||||||
"Russian: RU",
|
|
||||||
"Slovak: SK",
|
|
||||||
"Slovenian: SL",
|
|
||||||
"Spanish: ES",
|
|
||||||
"Swedish: SV"
|
|
||||||
};
|
|
||||||
std::wstring autoDetectLanguage = L"auto";
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||||
{
|
{
|
||||||
switch (ul_reason_for_call)
|
switch (ul_reason_for_call)
|
||||||
@ -58,19 +118,22 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
std::pair<bool, std::wstring> Translate(const std::wstring& text, TranslationParam tlp)
|
||||||
{
|
{
|
||||||
if (!DevTools::Connected()) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, ERROR_START_CHROME) };
|
if (!DevTools::Connected()) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, ERROR_START_CHROME) };
|
||||||
// DevTools can't handle concurrent translations yet
|
// DevTools can't handle concurrent translations yet
|
||||||
static std::mutex translationMutex;
|
static std::mutex translationMutex;
|
||||||
std::scoped_lock lock(translationMutex);
|
std::scoped_lock lock(translationMutex);
|
||||||
DevTools::SendRequest("Page.navigate", FormatString(LR"({"url":"https://www.deepl.com/en/translator#%s/%s/%s"})", translateTo.Copy(), translateTo.Copy(), Escape(text)));
|
DevTools::SendRequest("Page.navigate", FormatString(LR"({"url":"https://www.deepl.com/en/translator#en/en/%s"})", Escape(text)));
|
||||||
|
for (int retry = 0; ++retry < 20; Sleep(100))
|
||||||
|
if (Copy(DevTools::SendRequest("Runtime.evaluate", LR"({"expression":"document.readyState"})")[L"result"][L"value"].String()) == L"complete") break;
|
||||||
|
|
||||||
if (translateFrom.Copy() != autoDetectLanguage)
|
DevTools::SendRequest("Runtime.evaluate", FormatString(LR"({"expression":"
|
||||||
DevTools::SendRequest("Runtime.evaluate", FormatString(LR"({"expression":"
|
document.querySelector('.lmt__language_select--source').querySelector('button').click();
|
||||||
document.querySelector('.lmt__language_select--source').querySelector('button').click();
|
document.evaluate(`//button[text()='%s']`,document.querySelector('.lmt__language_select__menu'),null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue.click();
|
||||||
document.evaluate(`//button[contains(text(),'%s')]`,document.querySelector('.lmt__language_select__menu'),null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue.click();
|
document.querySelector('.lmt__language_select--target').querySelector('button').click();
|
||||||
"})", S(std::find_if(languages.begin(), languages.end(), [end = S(translateFrom.Copy())](const QString& language) { return language.endsWith(end); })->split(":")[0])));
|
document.evaluate(`//button[text()='%s']`,document.querySelector('.lmt__language_select__menu'),null,XPathResult.FIRST_ORDERED_NODE_TYPE,null).singleNodeValue.click();
|
||||||
|
"})", codes.at(tlp.translateFrom), codes.at(tlp.translateTo)));
|
||||||
|
|
||||||
for (int retry = 0; ++retry < 100; Sleep(100))
|
for (int retry = 0; ++retry < 100; Sleep(100))
|
||||||
if (auto translation = Copy(DevTools::SendRequest("Runtime.evaluate",
|
if (auto translation = Copy(DevTools::SendRequest("Runtime.evaluate",
|
||||||
|
@ -1,36 +1,54 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
|
#include "translatewrapper.h"
|
||||||
#include "devtools.h"
|
#include "devtools.h"
|
||||||
|
|
||||||
extern const wchar_t* ERROR_START_CHROME;
|
extern const wchar_t* ERROR_START_CHROME;
|
||||||
extern const wchar_t* TRANSLATION_ERROR;
|
extern const wchar_t* TRANSLATION_ERROR;
|
||||||
|
|
||||||
extern Synchronized<std::wstring> translateTo, translateFrom;
|
|
||||||
|
|
||||||
const char* TRANSLATION_PROVIDER = "DevTools Papago Translate";
|
const char* TRANSLATION_PROVIDER = "DevTools Papago Translate";
|
||||||
const char* GET_API_KEY_FROM = nullptr;
|
const char* GET_API_KEY_FROM = nullptr;
|
||||||
|
|
||||||
|
extern const QStringList languagesTo
|
||||||
|
{
|
||||||
|
"Chinese (Simplified)",
|
||||||
|
"Chinese (Traditional)",
|
||||||
|
"English",
|
||||||
|
"French",
|
||||||
|
"German",
|
||||||
|
"Hindi",
|
||||||
|
"Indonesian",
|
||||||
|
"Italian",
|
||||||
|
"Japanese",
|
||||||
|
"Korean",
|
||||||
|
"Portuguese",
|
||||||
|
"Russian",
|
||||||
|
"Spanish",
|
||||||
|
"Thai",
|
||||||
|
"Vietnamese",
|
||||||
|
}, languagesFrom = languagesTo;
|
||||||
|
extern const std::unordered_map<std::wstring, std::wstring> codes
|
||||||
|
{
|
||||||
|
{ { L"Chinese (Simplified)" }, { L"zh-CN" } },
|
||||||
|
{ { L"Chinese (Traditional)" }, { L"zt-TW" } },
|
||||||
|
{ { L"English" }, { L"en" } },
|
||||||
|
{ { L"French" }, { L"fr" } },
|
||||||
|
{ { L"German" }, { L"de" } },
|
||||||
|
{ { L"Hindi" }, { L"hi" } },
|
||||||
|
{ { L"Indonesian" }, { L"id" } },
|
||||||
|
{ { L"Italian" }, { L"it" } },
|
||||||
|
{ { L"Japanese" }, { L"ja" } },
|
||||||
|
{ { L"Korean" }, { L"ko" } },
|
||||||
|
{ { L"Portuguese" }, { L"pt" } },
|
||||||
|
{ { L"Russian" }, { L"ru" } },
|
||||||
|
{ { L"Spanish" }, { L"es" } },
|
||||||
|
{ { L"Thai" }, { L"th" } },
|
||||||
|
{ { L"Vietnamese" }, { L"vi" } },
|
||||||
|
{ { L"?" }, { L"auto" } }
|
||||||
|
};
|
||||||
|
|
||||||
bool translateSelectedOnly = true, rateLimitAll = false, rateLimitSelected = false, useCache = true, useFilter = true;
|
bool translateSelectedOnly = true, rateLimitAll = false, rateLimitSelected = false, useCache = true, useFilter = true;
|
||||||
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 2500;
|
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 2500;
|
||||||
|
|
||||||
QStringList languages
|
|
||||||
{
|
|
||||||
"Chinese (simplified): zh-CN",
|
|
||||||
"Chinese (traditional): zt-TW",
|
|
||||||
"English: en",
|
|
||||||
"French: fr",
|
|
||||||
"German: de",
|
|
||||||
"Hindi: hi",
|
|
||||||
"Indonesian: id",
|
|
||||||
"Italian: it",
|
|
||||||
"Japanese: ja",
|
|
||||||
"Korean: ko",
|
|
||||||
"Portuguese: pt",
|
|
||||||
"Russian: ru",
|
|
||||||
"Spanish: es",
|
|
||||||
"Thai: th",
|
|
||||||
"Vietnamese: vi",
|
|
||||||
};
|
|
||||||
std::wstring autoDetectLanguage = L"auto";
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||||
{
|
{
|
||||||
switch (ul_reason_for_call)
|
switch (ul_reason_for_call)
|
||||||
@ -49,13 +67,13 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
std::pair<bool, std::wstring> Translate(const std::wstring& text, TranslationParam tlp)
|
||||||
{
|
{
|
||||||
if (!DevTools::Connected()) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, ERROR_START_CHROME) };
|
if (!DevTools::Connected()) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, ERROR_START_CHROME) };
|
||||||
// DevTools can't handle concurrent translations yet
|
// DevTools can't handle concurrent translations yet
|
||||||
static std::mutex translationMutex;
|
static std::mutex translationMutex;
|
||||||
std::scoped_lock lock(translationMutex);
|
std::scoped_lock lock(translationMutex);
|
||||||
DevTools::SendRequest("Page.navigate", FormatString(LR"({"url":"https://papago.naver.com/?sk=%s&tk=%s&st=%s"})", translateFrom.Copy(), translateTo.Copy(), Escape(text)));
|
DevTools::SendRequest("Page.navigate", FormatString(LR"({"url":"https://papago.naver.com/?sk=%s&tk=%s&st=%s"})", codes.at(tlp.translateFrom), codes.at(tlp.translateTo), Escape(text)));
|
||||||
for (int retry = 0; ++retry < 100; Sleep(100))
|
for (int retry = 0; ++retry < 100; Sleep(100))
|
||||||
if (auto translation = Copy(DevTools::SendRequest("Runtime.evaluate",
|
if (auto translation = Copy(DevTools::SendRequest("Runtime.evaluate",
|
||||||
LR"({"expression":"document.querySelector('#txtTarget').textContent.trim() ","returnByValue":true})"
|
LR"({"expression":"document.querySelector('#txtTarget').textContent.trim() ","returnByValue":true})"
|
||||||
|
@ -1,34 +1,120 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
|
#include "translatewrapper.h"
|
||||||
#include "devtools.h"
|
#include "devtools.h"
|
||||||
|
|
||||||
extern const wchar_t* ERROR_START_CHROME;
|
extern const wchar_t* ERROR_START_CHROME;
|
||||||
extern const wchar_t* TRANSLATION_ERROR;
|
extern const wchar_t* TRANSLATION_ERROR;
|
||||||
|
|
||||||
extern Synchronized<std::wstring> translateTo, translateFrom;
|
|
||||||
extern QFormLayout* display;
|
|
||||||
extern Settings settings;
|
|
||||||
|
|
||||||
const char* TRANSLATION_PROVIDER = "DevTools Systran Translate";
|
const char* TRANSLATION_PROVIDER = "DevTools Systran Translate";
|
||||||
const char* GET_API_KEY_FROM = nullptr;
|
const char* GET_API_KEY_FROM = nullptr;
|
||||||
|
|
||||||
|
extern const QStringList languagesTo
|
||||||
|
{
|
||||||
|
"Albanian",
|
||||||
|
"Arabic",
|
||||||
|
"Bengali",
|
||||||
|
"Bulgarian",
|
||||||
|
"Burmese",
|
||||||
|
"Catalan",
|
||||||
|
"Chinese (Simplified)",
|
||||||
|
"Chinese (Traditional)",
|
||||||
|
"Croatian",
|
||||||
|
"Czech",
|
||||||
|
"Danish",
|
||||||
|
"Dutch",
|
||||||
|
"English",
|
||||||
|
"Estonian",
|
||||||
|
"Finnish",
|
||||||
|
"French",
|
||||||
|
"German",
|
||||||
|
"Greek",
|
||||||
|
"Hebrew",
|
||||||
|
"Hindi",
|
||||||
|
"Hungarian",
|
||||||
|
"Indonesian",
|
||||||
|
"Italian",
|
||||||
|
"Japanese",
|
||||||
|
"Korean",
|
||||||
|
"Latvian",
|
||||||
|
"Lithuanian",
|
||||||
|
"Malay",
|
||||||
|
"Norwegian",
|
||||||
|
"Pashto",
|
||||||
|
"Persian",
|
||||||
|
"Polish",
|
||||||
|
"Portuguese",
|
||||||
|
"Romanian",
|
||||||
|
"Russian",
|
||||||
|
"Serbian",
|
||||||
|
"Slovak",
|
||||||
|
"Slovenian",
|
||||||
|
"Somali",
|
||||||
|
"Spanish",
|
||||||
|
"Swedish",
|
||||||
|
"Tagalog",
|
||||||
|
"Tamil",
|
||||||
|
"Thai",
|
||||||
|
"Turkish",
|
||||||
|
"Ukrainian",
|
||||||
|
"Urdu",
|
||||||
|
"Vietnamese"
|
||||||
|
}, languagesFrom = languagesTo;
|
||||||
|
extern const std::unordered_map<std::wstring, std::wstring> codes
|
||||||
|
{
|
||||||
|
{ { L"Albanian" }, { L"sq" } },
|
||||||
|
{ { L"Arabic" }, { L"ar" } },
|
||||||
|
{ { L"Bengali" }, { L"bn" } },
|
||||||
|
{ { L"Bulgarian" }, { L"bg" } },
|
||||||
|
{ { L"Burmese" }, { L"my" } },
|
||||||
|
{ { L"Catalan" }, { L"ca" } },
|
||||||
|
{ { L"Chinese (Simplified)" }, { L"zh" } },
|
||||||
|
{ { L"Chinese (Traditional)" }, { L"zt" } },
|
||||||
|
{ { L"Croatian" }, { L"hr" } },
|
||||||
|
{ { L"Czech" }, { L"cs" } },
|
||||||
|
{ { L"Danish" }, { L"da" } },
|
||||||
|
{ { L"Dutch" }, { L"nl" } },
|
||||||
|
{ { L"English" }, { L"en" } },
|
||||||
|
{ { L"Estonian" }, { L"et" } },
|
||||||
|
{ { L"Finnish" }, { L"fi" } },
|
||||||
|
{ { L"French" }, { L"fr" } },
|
||||||
|
{ { L"German" }, { L"de" } },
|
||||||
|
{ { L"Greek" }, { L"el" } },
|
||||||
|
{ { L"Hebrew" }, { L"he" } },
|
||||||
|
{ { L"Hindi" }, { L"hi" } },
|
||||||
|
{ { L"Hungarian" }, { L"hu" } },
|
||||||
|
{ { L"Indonesian" }, { L"id" } },
|
||||||
|
{ { L"Italian" }, { L"it" } },
|
||||||
|
{ { L"Japanese" }, { L"ja" } },
|
||||||
|
{ { L"Korean" }, { L"ko" } },
|
||||||
|
{ { L"Latvian" }, { L"lv" } },
|
||||||
|
{ { L"Lithuanian" }, { L"lt" } },
|
||||||
|
{ { L"Malay" }, { L"ms" } },
|
||||||
|
{ { L"Norwegian" }, { L"no" } },
|
||||||
|
{ { L"Pashto" }, { L"ps" } },
|
||||||
|
{ { L"Persian" }, { L"fa" } },
|
||||||
|
{ { L"Polish" }, { L"pl" } },
|
||||||
|
{ { L"Portuguese" }, { L"pt" } },
|
||||||
|
{ { L"Romanian" }, { L"ro" } },
|
||||||
|
{ { L"Russian" }, { L"ru" } },
|
||||||
|
{ { L"Serbian" }, { L"sr" } },
|
||||||
|
{ { L"Slovak" }, { L"sk" } },
|
||||||
|
{ { L"Slovenian" }, { L"sl" } },
|
||||||
|
{ { L"Somali" }, { L"so" } },
|
||||||
|
{ { L"Spanish" }, { L"es" } },
|
||||||
|
{ { L"Swedish" }, { L"sv" } },
|
||||||
|
{ { L"Tagalog" }, { L"tl" } },
|
||||||
|
{ { L"Tamil" }, { L"ta" } },
|
||||||
|
{ { L"Thai" }, { L"th" } },
|
||||||
|
{ { L"Turkish" }, { L"tr" } },
|
||||||
|
{ { L"Ukrainian" }, { L"uk" } },
|
||||||
|
{ { L"Urdu" }, { L"ur" } },
|
||||||
|
{ { L"Vietnamese" }, { L"vi" } },
|
||||||
|
{ { L"?" }, { L"autodetect" } }
|
||||||
|
};
|
||||||
|
|
||||||
bool translateSelectedOnly = true, rateLimitAll = false, rateLimitSelected = false, useCache = true, useFilter = true;
|
bool translateSelectedOnly = true, rateLimitAll = false, rateLimitSelected = false, useCache = true, useFilter = true;
|
||||||
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 2500;
|
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 2500;
|
||||||
|
|
||||||
QStringList languages
|
|
||||||
{
|
|
||||||
"Chinese: zh",
|
|
||||||
"Chinese (traditional): zt",
|
|
||||||
"English: en",
|
|
||||||
"French: fr",
|
|
||||||
"German: de",
|
|
||||||
"Italian: it",
|
|
||||||
"Japanese: ja",
|
|
||||||
"Korean: ko",
|
|
||||||
"Portuguese: pt",
|
|
||||||
"Spanish: es",
|
|
||||||
"Thai: th",
|
|
||||||
};
|
|
||||||
std::wstring autoDetectLanguage = L"auto";
|
|
||||||
|
|
||||||
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
||||||
{
|
{
|
||||||
switch (ul_reason_for_call)
|
switch (ul_reason_for_call)
|
||||||
@ -47,14 +133,17 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
std::pair<bool, std::wstring> Translate(const std::wstring& text, TranslationParam tlp)
|
||||||
{
|
{
|
||||||
if (!DevTools::Connected()) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, ERROR_START_CHROME) };
|
if (!DevTools::Connected()) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, ERROR_START_CHROME) };
|
||||||
// DevTools can't handle concurrent translations yet
|
// DevTools can't handle concurrent translations yet
|
||||||
static std::mutex translationMutex;
|
static std::mutex translationMutex;
|
||||||
std::scoped_lock lock(translationMutex);
|
std::scoped_lock lock(translationMutex);
|
||||||
|
|
||||||
DevTools::SendRequest("Page.navigate", FormatString(LR"({"url":"https://translate.systran.net/?&source=%s&target=%s&input=%s"})", translateFrom.Copy(), translateTo.Copy(), Escape(text)));
|
DevTools::SendRequest(
|
||||||
|
"Page.navigate",
|
||||||
|
FormatString(LR"({"url":"https://translate.systran.net/?source=%s&target=%s&input=%s"})", codes.at(tlp.translateFrom), codes.at(tlp.translateTo), Escape(text))
|
||||||
|
);
|
||||||
for (int retry = 0; ++retry < 100; Sleep(100))
|
for (int retry = 0; ++retry < 100; Sleep(100))
|
||||||
if (auto translation = Copy(DevTools::SendRequest("Runtime.evaluate",
|
if (auto translation = Copy(DevTools::SendRequest("Runtime.evaluate",
|
||||||
LR"({"expression":"document.querySelector('#outputEditor').textContent.trim() ","returnByValue":true})"
|
LR"({"expression":"document.querySelector('#outputEditor').textContent.trim() ","returnByValue":true})"
|
||||||
|
@ -1,140 +1,250 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
|
#include "translatewrapper.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include <ctime>
|
|
||||||
|
|
||||||
extern const wchar_t* TRANSLATION_ERROR;
|
extern const wchar_t* TRANSLATION_ERROR;
|
||||||
|
|
||||||
extern Synchronized<std::wstring> translateTo, translateFrom, authKey;
|
|
||||||
|
|
||||||
const char* TRANSLATION_PROVIDER = "Google Translate";
|
const char* TRANSLATION_PROVIDER = "Google Translate";
|
||||||
const char* GET_API_KEY_FROM = "https://codelabs.developers.google.com/codelabs/cloud-translation-intro";
|
const char* GET_API_KEY_FROM = "https://codelabs.developers.google.com/codelabs/cloud-translation-intro";
|
||||||
QStringList languages
|
extern const QStringList languagesTo
|
||||||
{
|
{
|
||||||
"Afrikaans: af",
|
"Afrikaans",
|
||||||
"Albanian: sq",
|
"Albanian",
|
||||||
"Amharic: am",
|
"Amharic",
|
||||||
"Arabic: ar",
|
"Arabic",
|
||||||
"Armenian: hy",
|
"Armenian",
|
||||||
"Azerbaijani: az",
|
"Azerbaijani",
|
||||||
"Basque: eu",
|
"Basque",
|
||||||
"Belarusian: be",
|
"Belarusian",
|
||||||
"Bengali: bn",
|
"Bengali",
|
||||||
"Bosnian: bs",
|
"Bosnian",
|
||||||
"Bulgarian: bg",
|
"Bulgarian",
|
||||||
"Catalan: ca",
|
"Catalan",
|
||||||
"Cebuano: ceb",
|
"Cebuano",
|
||||||
"Chichewa: ny",
|
"Chichewa",
|
||||||
"Chinese (simplified): zh",
|
"Chinese (Simplified)",
|
||||||
"Chinese (traditional): zh-TW",
|
"Chinese (Traditional)",
|
||||||
"Corsican: co",
|
"Corsican",
|
||||||
"Croatian: hr",
|
"Croatian",
|
||||||
"Czech: cs",
|
"Czech",
|
||||||
"Danish: da",
|
"Danish",
|
||||||
"Dutch: nl",
|
"Dutch",
|
||||||
"English: en",
|
"English",
|
||||||
"Esperanto: eo",
|
"Esperanto",
|
||||||
"Estonian: et",
|
"Estonian",
|
||||||
"Filipino: tl",
|
"Filipino",
|
||||||
"Finnish: fi",
|
"Finnish",
|
||||||
"French: fr",
|
"French",
|
||||||
"Frisian: fy",
|
"Frisian",
|
||||||
"Galician: gl",
|
"Galician",
|
||||||
"Georgian: ka",
|
"Georgian",
|
||||||
"German: de",
|
"German",
|
||||||
"Greek: el",
|
"Greek",
|
||||||
"Gujarati: gu",
|
"Gujarati",
|
||||||
"Haitian Creole: ht",
|
"Haitian Creole",
|
||||||
"Hausa: ha",
|
"Hausa",
|
||||||
"Hawaiian: haw",
|
"Hawaiian",
|
||||||
"Hebrew: iw",
|
"Hebrew",
|
||||||
"Hindi: hi",
|
"Hindi",
|
||||||
"Hmong: hmn",
|
"Hmong",
|
||||||
"Hungarian: hu",
|
"Hungarian",
|
||||||
"Icelandic: is",
|
"Icelandic",
|
||||||
"Igbo: ig",
|
"Igbo",
|
||||||
"Indonesian: id",
|
"Indonesian",
|
||||||
"Irish: ga",
|
"Irish",
|
||||||
"Italian: it",
|
"Italian",
|
||||||
"Japanese: ja",
|
"Japanese",
|
||||||
"Javanese: jw",
|
"Javanese",
|
||||||
"Kannada: kn",
|
"Kannada",
|
||||||
"Kazakh: kk",
|
"Kazakh",
|
||||||
"Khmer: km",
|
"Khmer",
|
||||||
"Kinyarwanda: rw",
|
"Kinyarwanda",
|
||||||
"Korean: ko",
|
"Korean",
|
||||||
"Kurdish (Kurmanji): ku",
|
"Kurdish (Kurmanji)",
|
||||||
"Kyrgyz: ky",
|
"Kyrgyz",
|
||||||
"Lao: lo",
|
"Lao",
|
||||||
"Latin: la",
|
"Latin",
|
||||||
"Latvian: lv",
|
"Latvian",
|
||||||
"Lithuanian: lt",
|
"Lithuanian",
|
||||||
"Luxembourgish: lb",
|
"Luxembourgish",
|
||||||
"Macedonian: mk",
|
"Macedonian",
|
||||||
"Malagasy: mg",
|
"Malagasy",
|
||||||
"Malay: ms",
|
"Malay",
|
||||||
"Malayalam: ml",
|
"Malayalam",
|
||||||
"Maltese: mt",
|
"Maltese",
|
||||||
"Maori: mi",
|
"Maori",
|
||||||
"Marathi: mr",
|
"Marathi",
|
||||||
"Mongolian: mn",
|
"Mongolian",
|
||||||
"Myanmar (Burmese): my",
|
"Myanmar (Burmese)",
|
||||||
"Nepali: ne",
|
"Nepali",
|
||||||
"Norwegian: no",
|
"Norwegian",
|
||||||
"Odia (Oriya): or",
|
"Odia (Oriya)",
|
||||||
"Pashto: ps",
|
"Pashto",
|
||||||
"Persian: fa",
|
"Persian",
|
||||||
"Polish: pl",
|
"Polish",
|
||||||
"Portuguese: pt",
|
"Portuguese",
|
||||||
"Punjabi: pa",
|
"Punjabi",
|
||||||
"Romanian: ro",
|
"Romanian",
|
||||||
"Russian: ru",
|
"Russian",
|
||||||
"Samoan: sm",
|
"Samoan",
|
||||||
"Scots Gaelic: gd",
|
"Scots Gaelic",
|
||||||
"Serbian: sr",
|
"Serbian",
|
||||||
"Sesotho: st",
|
"Sesotho",
|
||||||
"Shona: sn",
|
"Shona",
|
||||||
"Sindhi: sd",
|
"Sindhi",
|
||||||
"Sinhala: si",
|
"Sinhala",
|
||||||
"Slovak: sk",
|
"Slovak",
|
||||||
"Slovenian: sl",
|
"Slovenian",
|
||||||
"Somali: so",
|
"Somali",
|
||||||
"Spanish: es",
|
"Spanish",
|
||||||
"Sundanese: su",
|
"Sundanese",
|
||||||
"Swahili: sw",
|
"Swahili",
|
||||||
"Swedish: sv",
|
"Swedish",
|
||||||
"Tajik: tg",
|
"Tajik",
|
||||||
"Tamil: ta",
|
"Tamil",
|
||||||
"Tatar: tt",
|
"Tatar",
|
||||||
"Telugu: te",
|
"Telugu",
|
||||||
"Thai: th",
|
"Thai",
|
||||||
"Turkish: tr",
|
"Turkish",
|
||||||
"Turkmen: tk",
|
"Turkmen",
|
||||||
"Ukrainian: uk",
|
"Ukrainian",
|
||||||
"Urdu: ur",
|
"Urdu",
|
||||||
"Uyghur: ug",
|
"Uyghur",
|
||||||
"Uzbek: uz",
|
"Uzbek",
|
||||||
"Vietnamese: vi",
|
"Vietnamese",
|
||||||
"Welsh: cy",
|
"Welsh",
|
||||||
"Xhosa: xh",
|
"Xhosa",
|
||||||
"Yiddish: yi",
|
"Yiddish",
|
||||||
"Yoruba: yo",
|
"Yoruba",
|
||||||
"Zulu: zu"
|
"Zulu",
|
||||||
|
}, languagesFrom = languagesTo;
|
||||||
|
extern const std::unordered_map<std::wstring, std::wstring> codes
|
||||||
|
{
|
||||||
|
{ { L"Afrikaans" }, { L"af" } },
|
||||||
|
{ { L"Albanian" }, { L"sq" } },
|
||||||
|
{ { L"Amharic" }, { L"am" } },
|
||||||
|
{ { L"Arabic" }, { L"ar" } },
|
||||||
|
{ { L"Armenian" }, { L"hy" } },
|
||||||
|
{ { L"Azerbaijani" }, { L"az" } },
|
||||||
|
{ { L"Basque" }, { L"eu" } },
|
||||||
|
{ { L"Belarusian" }, { L"be" } },
|
||||||
|
{ { L"Bengali" }, { L"bn" } },
|
||||||
|
{ { L"Bosnian" }, { L"bs" } },
|
||||||
|
{ { L"Bulgarian" }, { L"bg" } },
|
||||||
|
{ { L"Catalan" }, { L"ca" } },
|
||||||
|
{ { L"Cebuano" }, { L"ceb" } },
|
||||||
|
{ { L"Chichewa" }, { L"ny" } },
|
||||||
|
{ { L"Chinese (Simplified)" }, { L"zh-CN" } },
|
||||||
|
{ { L"Chinese (Traditional)" }, { L"zh-TW" } },
|
||||||
|
{ { L"Corsican" }, { L"co" } },
|
||||||
|
{ { L"Croatian" }, { L"hr" } },
|
||||||
|
{ { L"Czech" }, { L"cs" } },
|
||||||
|
{ { L"Danish" }, { L"da" } },
|
||||||
|
{ { L"Dutch" }, { L"nl" } },
|
||||||
|
{ { L"English" }, { L"en" } },
|
||||||
|
{ { L"Esperanto" }, { L"eo" } },
|
||||||
|
{ { L"Estonian" }, { L"et" } },
|
||||||
|
{ { L"Filipino" }, { L"tl" } },
|
||||||
|
{ { L"Finnish" }, { L"fi" } },
|
||||||
|
{ { L"French" }, { L"fr" } },
|
||||||
|
{ { L"Frisian" }, { L"fy" } },
|
||||||
|
{ { L"Galician" }, { L"gl" } },
|
||||||
|
{ { L"Georgian" }, { L"ka" } },
|
||||||
|
{ { L"German" }, { L"de" } },
|
||||||
|
{ { L"Greek" }, { L"el" } },
|
||||||
|
{ { L"Gujarati" }, { L"gu" } },
|
||||||
|
{ { L"Haitian Creole" }, { L"ht" } },
|
||||||
|
{ { L"Hausa" }, { L"ha" } },
|
||||||
|
{ { L"Hawaiian" }, { L"haw" } },
|
||||||
|
{ { L"Hebrew" }, { L"iw" } },
|
||||||
|
{ { L"Hindi" }, { L"hi" } },
|
||||||
|
{ { L"Hmong" }, { L"hmn" } },
|
||||||
|
{ { L"Hungarian" }, { L"hu" } },
|
||||||
|
{ { L"Icelandic" }, { L"is" } },
|
||||||
|
{ { L"Igbo" }, { L"ig" } },
|
||||||
|
{ { L"Indonesian" }, { L"id" } },
|
||||||
|
{ { L"Irish" }, { L"ga" } },
|
||||||
|
{ { L"Italian" }, { L"it" } },
|
||||||
|
{ { L"Japanese" }, { L"ja" } },
|
||||||
|
{ { L"Javanese" }, { L"jw" } },
|
||||||
|
{ { L"Kannada" }, { L"kn" } },
|
||||||
|
{ { L"Kazakh" }, { L"kk" } },
|
||||||
|
{ { L"Khmer" }, { L"km" } },
|
||||||
|
{ { L"Kinyarwanda" }, { L"rw" } },
|
||||||
|
{ { L"Korean" }, { L"ko" } },
|
||||||
|
{ { L"Kurdish (Kurmanji)" }, { L"ku" } },
|
||||||
|
{ { L"Kyrgyz" }, { L"ky" } },
|
||||||
|
{ { L"Lao" }, { L"lo" } },
|
||||||
|
{ { L"Latin" }, { L"la" } },
|
||||||
|
{ { L"Latvian" }, { L"lv" } },
|
||||||
|
{ { L"Lithuanian" }, { L"lt" } },
|
||||||
|
{ { L"Luxembourgish" }, { L"lb" } },
|
||||||
|
{ { L"Macedonian" }, { L"mk" } },
|
||||||
|
{ { L"Malagasy" }, { L"mg" } },
|
||||||
|
{ { L"Malay" }, { L"ms" } },
|
||||||
|
{ { L"Malayalam" }, { L"ml" } },
|
||||||
|
{ { L"Maltese" }, { L"mt" } },
|
||||||
|
{ { L"Maori" }, { L"mi" } },
|
||||||
|
{ { L"Marathi" }, { L"mr" } },
|
||||||
|
{ { L"Mongolian" }, { L"mn" } },
|
||||||
|
{ { L"Myanmar (Burmese)" }, { L"my" } },
|
||||||
|
{ { L"Nepali" }, { L"ne" } },
|
||||||
|
{ { L"Norwegian" }, { L"no" } },
|
||||||
|
{ { L"Odia (Oriya)" }, { L"or" } },
|
||||||
|
{ { L"Pashto" }, { L"ps" } },
|
||||||
|
{ { L"Persian" }, { L"fa" } },
|
||||||
|
{ { L"Polish" }, { L"pl" } },
|
||||||
|
{ { L"Portuguese" }, { L"pt" } },
|
||||||
|
{ { L"Punjabi" }, { L"pa" } },
|
||||||
|
{ { L"Romanian" }, { L"ro" } },
|
||||||
|
{ { L"Russian" }, { L"ru" } },
|
||||||
|
{ { L"Samoan" }, { L"sm" } },
|
||||||
|
{ { L"Scots Gaelic" }, { L"gd" } },
|
||||||
|
{ { L"Serbian" }, { L"sr" } },
|
||||||
|
{ { L"Sesotho" }, { L"st" } },
|
||||||
|
{ { L"Shona" }, { L"sn" } },
|
||||||
|
{ { L"Sindhi" }, { L"sd" } },
|
||||||
|
{ { L"Sinhala" }, { L"si" } },
|
||||||
|
{ { L"Slovak" }, { L"sk" } },
|
||||||
|
{ { L"Slovenian" }, { L"sl" } },
|
||||||
|
{ { L"Somali" }, { L"so" } },
|
||||||
|
{ { L"Spanish" }, { L"es" } },
|
||||||
|
{ { L"Sundanese" }, { L"su" } },
|
||||||
|
{ { L"Swahili" }, { L"sw" } },
|
||||||
|
{ { L"Swedish" }, { L"sv" } },
|
||||||
|
{ { L"Tajik" }, { L"tg" } },
|
||||||
|
{ { L"Tamil" }, { L"ta" } },
|
||||||
|
{ { L"Tatar" }, { L"tt" } },
|
||||||
|
{ { L"Telugu" }, { L"te" } },
|
||||||
|
{ { L"Thai" }, { L"th" } },
|
||||||
|
{ { L"Turkish" }, { L"tr" } },
|
||||||
|
{ { L"Turkmen" }, { L"tk" } },
|
||||||
|
{ { L"Ukrainian" }, { L"uk" } },
|
||||||
|
{ { L"Urdu" }, { L"ur" } },
|
||||||
|
{ { L"Uyghur" }, { L"ug" } },
|
||||||
|
{ { L"Uzbek" }, { L"uz" } },
|
||||||
|
{ { L"Vietnamese" }, { L"vi" } },
|
||||||
|
{ { L"Welsh" }, { L"cy" } },
|
||||||
|
{ { L"Xhosa" }, { L"xh" } },
|
||||||
|
{ { L"Yiddish" }, { L"yi" } },
|
||||||
|
{ { L"Yoruba" }, { L"yo" } },
|
||||||
|
{ { L"Zulu" }, { L"zu" } },
|
||||||
|
{ { L"?" }, { L"auto" } }
|
||||||
};
|
};
|
||||||
std::wstring autoDetectLanguage = L"auto";
|
|
||||||
|
|
||||||
bool translateSelectedOnly = false, rateLimitAll = true, rateLimitSelected = false, useCache = true, useFilter = true;
|
bool translateSelectedOnly = false, rateLimitAll = true, rateLimitSelected = false, useCache = true, useFilter = true;
|
||||||
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
|
int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
|
||||||
|
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
std::pair<bool, std::wstring> Translate(const std::wstring& text, TranslationParam tlp)
|
||||||
{
|
{
|
||||||
if (!authKey->empty())
|
if (!tlp.authKey.empty())
|
||||||
{
|
{
|
||||||
std::wstring translateFromComponent = translateFrom.Copy() == autoDetectLanguage ? L"" : L"&source=" + translateFrom.Copy();
|
std::wstring translateFromComponent = tlp.translateFrom == L"?" ? L"" : L"&source=" + codes.at(tlp.translateFrom);
|
||||||
if (HttpRequest httpRequest{
|
if (HttpRequest httpRequest{
|
||||||
L"Mozilla/5.0 Textractor",
|
L"Mozilla/5.0 Textractor",
|
||||||
L"translation.googleapis.com",
|
L"translation.googleapis.com",
|
||||||
L"POST",
|
L"POST",
|
||||||
FormatString(L"/language/translate/v2?format=text&target=%s&key=%s%s", translateTo.Copy(), authKey.Copy(), translateFromComponent).c_str(),
|
FormatString(L"/language/translate/v2?format=text&target=%s&key=%s%s", codes.at(tlp.translateTo), tlp.authKey, translateFromComponent).c_str(),
|
||||||
FormatString(R"({"q":["%s"]})", JSON::Escape(WideStringToString(text)))
|
FormatString(R"({"q":["%s"]})", JSON::Escape(WideStringToString(text)))
|
||||||
})
|
})
|
||||||
if (auto translation = Copy(JSON::Parse(httpRequest.response)[L"data"][L"translations"][0][L"translatedText"].String())) return { true, translation.value() };
|
if (auto translation = Copy(JSON::Parse(httpRequest.response)[L"data"][L"translations"][0][L"translatedText"].String())) return { true, translation.value() };
|
||||||
@ -146,7 +256,7 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
|
|||||||
L"Mozilla/5.0 Textractor",
|
L"Mozilla/5.0 Textractor",
|
||||||
L"translate.google.com",
|
L"translate.google.com",
|
||||||
L"GET",
|
L"GET",
|
||||||
FormatString(L"/m?sl=%s&tl=%s&q=%s", translateFrom.Copy(), translateTo.Copy(), Escape(text)).c_str()
|
FormatString(L"/m?sl=%s&tl=%s&q=%s", codes.at(tlp.translateFrom), codes.at(tlp.translateTo), Escape(text)).c_str()
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
auto start = httpRequest.response.find(L"result-container\">"), end = httpRequest.response.find(L'<', start);
|
auto start = httpRequest.response.find(L"result-container\">"), end = httpRequest.response.find(L'<', start);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include "qtcommon.h"
|
#include "qtcommon.h"
|
||||||
#include "extension.h"
|
#include "extension.h"
|
||||||
|
#include "translatewrapper.h"
|
||||||
#include "blockmarkup.h"
|
#include "blockmarkup.h"
|
||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -22,22 +23,19 @@ extern const wchar_t* TOO_MANY_TRANS_REQUESTS;
|
|||||||
|
|
||||||
extern const char* TRANSLATION_PROVIDER;
|
extern const char* TRANSLATION_PROVIDER;
|
||||||
extern const char* GET_API_KEY_FROM;
|
extern const char* GET_API_KEY_FROM;
|
||||||
extern QStringList languages;
|
extern const QStringList languagesTo, languagesFrom;
|
||||||
extern std::wstring autoDetectLanguage;
|
|
||||||
extern bool translateSelectedOnly, rateLimitAll, rateLimitSelected, useCache, useFilter;
|
extern bool translateSelectedOnly, rateLimitAll, rateLimitSelected, useCache, useFilter;
|
||||||
extern int tokenCount, tokenRestoreDelay, maxSentenceSize;
|
extern int tokenCount, tokenRestoreDelay, maxSentenceSize;
|
||||||
std::pair<bool, std::wstring> Translate(const std::wstring& text);
|
std::pair<bool, std::wstring> Translate(const std::wstring& text, TranslationParam tlp);
|
||||||
|
|
||||||
// backwards compatibility
|
|
||||||
const char* LANGUAGE = u8"Language";
|
|
||||||
const std::string TRANSLATION_CACHE_FILE = FormatString("%s Translation Cache.txt", TRANSLATION_PROVIDER);
|
const std::string TRANSLATION_CACHE_FILE = FormatString("%s Translation Cache.txt", TRANSLATION_PROVIDER);
|
||||||
|
|
||||||
QFormLayout* display;
|
QFormLayout* display;
|
||||||
Settings settings;
|
Settings settings;
|
||||||
Synchronized<std::wstring> translateTo = L"en", translateFrom = L"auto", authKey;
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
Synchronized<TranslationParam> tlp;
|
||||||
Synchronized<std::map<std::wstring, std::wstring>> translationCache;
|
Synchronized<std::map<std::wstring, std::wstring>> translationCache;
|
||||||
int savedSize;
|
int savedSize;
|
||||||
void SaveCache()
|
void SaveCache()
|
||||||
@ -60,23 +58,22 @@ public:
|
|||||||
settings.beginGroup(TRANSLATION_PROVIDER);
|
settings.beginGroup(TRANSLATION_PROVIDER);
|
||||||
|
|
||||||
auto translateToCombo = new QComboBox(this);
|
auto translateToCombo = new QComboBox(this);
|
||||||
translateToCombo->addItems(languages);
|
translateToCombo->addItems(languagesTo);
|
||||||
int language = -1;
|
int i = -1;
|
||||||
if (settings.contains(LANGUAGE)) language = translateToCombo->findText(settings.value(LANGUAGE).toString(), Qt::MatchEndsWith);
|
if (settings.contains(TRANSLATE_TO)) i = translateToCombo->findText(settings.value(TRANSLATE_TO).toString());
|
||||||
if (settings.contains(TRANSLATE_TO)) language = translateToCombo->findText(settings.value(TRANSLATE_TO).toString(), Qt::MatchEndsWith);
|
if (i < 0) i = translateToCombo->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
|
||||||
if (language < 0) language = translateToCombo->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
|
if (i < 0) i = translateToCombo->findText("English", Qt::MatchStartsWith);
|
||||||
if (language < 0) language = translateToCombo->findText("English", Qt::MatchStartsWith);
|
translateToCombo->setCurrentIndex(i);
|
||||||
translateToCombo->setCurrentIndex(language);
|
|
||||||
SaveTranslateTo(translateToCombo->currentText());
|
SaveTranslateTo(translateToCombo->currentText());
|
||||||
display->addRow(TRANSLATE_TO, translateToCombo);
|
display->addRow(TRANSLATE_TO, translateToCombo);
|
||||||
connect(translateToCombo, &QComboBox::currentTextChanged, this, &Window::SaveTranslateTo);
|
connect(translateToCombo, &QComboBox::currentTextChanged, this, &Window::SaveTranslateTo);
|
||||||
languages.push_front("?: " + S(autoDetectLanguage));
|
|
||||||
auto translateFromCombo = new QComboBox(this);
|
auto translateFromCombo = new QComboBox(this);
|
||||||
translateFromCombo->addItems(languages);
|
translateFromCombo->addItem("?");
|
||||||
language = -1;
|
translateFromCombo->addItems(languagesFrom);
|
||||||
if (settings.contains(TRANSLATE_FROM)) language = translateFromCombo->findText(settings.value(TRANSLATE_FROM).toString(), Qt::MatchEndsWith);
|
i = -1;
|
||||||
if (language < 0) language = translateFromCombo->findText("?", Qt::MatchStartsWith);
|
if (settings.contains(TRANSLATE_FROM)) i = translateFromCombo->findText(settings.value(TRANSLATE_FROM).toString());
|
||||||
translateFromCombo->setCurrentIndex(language);
|
if (i < 0) i = 0;
|
||||||
|
translateFromCombo->setCurrentIndex(i);
|
||||||
SaveTranslateFrom(translateFromCombo->currentText());
|
SaveTranslateFrom(translateFromCombo->currentText());
|
||||||
display->addRow(TRANSLATE_FROM, translateFromCombo);
|
display->addRow(TRANSLATE_FROM, translateFromCombo);
|
||||||
connect(translateFromCombo, &QComboBox::currentTextChanged, this, &Window::SaveTranslateFrom);
|
connect(translateFromCombo, &QComboBox::currentTextChanged, this, &Window::SaveTranslateFrom);
|
||||||
@ -110,8 +107,8 @@ public:
|
|||||||
if (GET_API_KEY_FROM)
|
if (GET_API_KEY_FROM)
|
||||||
{
|
{
|
||||||
auto keyEdit = new QLineEdit(settings.value(API_KEY).toString(), this);
|
auto keyEdit = new QLineEdit(settings.value(API_KEY).toString(), this);
|
||||||
authKey->assign(S(keyEdit->text()));
|
tlp->authKey = S(keyEdit->text());
|
||||||
QObject::connect(keyEdit, &QLineEdit::textChanged, [](QString key) { settings.setValue(API_KEY, S(authKey->assign(S(key)))); });
|
QObject::connect(keyEdit, &QLineEdit::textChanged, [](QString key) { settings.setValue(API_KEY, S(tlp->authKey = S(key))); });
|
||||||
auto keyLabel = new QLabel(QString("<a href=\"%1\">%2</a>").arg(GET_API_KEY_FROM, API_KEY), this);
|
auto keyLabel = new QLabel(QString("<a href=\"%1\">%2</a>").arg(GET_API_KEY_FROM, API_KEY), this);
|
||||||
keyLabel->setOpenExternalLinks(true);
|
keyLabel->setOpenExternalLinks(true);
|
||||||
display->addRow(keyLabel, keyEdit);
|
display->addRow(keyLabel, keyEdit);
|
||||||
@ -139,11 +136,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
void SaveTranslateTo(QString language)
|
void SaveTranslateTo(QString language)
|
||||||
{
|
{
|
||||||
settings.setValue(TRANSLATE_TO, S(translateTo->assign(S(language.split(": ")[1]))));
|
settings.setValue(TRANSLATE_TO, S(tlp->translateTo = S(language)));
|
||||||
}
|
}
|
||||||
void SaveTranslateFrom(QString language)
|
void SaveTranslateFrom(QString language)
|
||||||
{
|
{
|
||||||
settings.setValue(TRANSLATE_FROM, S(translateFrom->assign(S(language.split(": ")[1]))));
|
settings.setValue(TRANSLATE_FROM, S(tlp->translateFrom = S(language)));
|
||||||
}
|
}
|
||||||
} window;
|
} window;
|
||||||
|
|
||||||
@ -186,7 +183,7 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
|
|||||||
if (auto it = translationCache->find(sentence); it != translationCache->end()) translation = it->second + L"\x200b"; // dumb hack to not try to translate if stored empty translation
|
if (auto it = translationCache->find(sentence); it != translationCache->end()) translation = it->second + L"\x200b"; // dumb hack to not try to translate if stored empty translation
|
||||||
}
|
}
|
||||||
if (translation.empty() && (!translateSelectedOnly || sentenceInfo["current select"]))
|
if (translation.empty() && (!translateSelectedOnly || sentenceInfo["current select"]))
|
||||||
if (rateLimiter.Request() || !rateLimitAll || (!rateLimitSelected && sentenceInfo["current select"])) std::tie(cache, translation) = Translate(sentence);
|
if (rateLimiter.Request() || !rateLimitAll || (!rateLimitSelected && sentenceInfo["current select"])) std::tie(cache, translation) = Translate(sentence, tlp.Copy());
|
||||||
else translation = TOO_MANY_TRANS_REQUESTS;
|
else translation = TOO_MANY_TRANS_REQUESTS;
|
||||||
if (useFilter) Trim(translation);
|
if (useFilter) Trim(translation);
|
||||||
if (cache) translationCache->try_emplace(sentence, translation);
|
if (cache) translationCache->try_emplace(sentence, translation);
|
||||||
@ -197,4 +194,13 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(assert(Translate(L"こんにちは").second.find(L"ello") != std::string::npos));
|
extern const std::unordered_map<std::wstring, std::wstring> codes;
|
||||||
|
TEST(
|
||||||
|
{
|
||||||
|
assert(Translate(L"こんにちは", { L"English", L"?", L"" }).second.find(L"ello") == 1 || strstr(TRANSLATION_PROVIDER, "DevTools"));
|
||||||
|
|
||||||
|
for (auto languages : { languagesFrom, languagesTo }) for (auto language : languages)
|
||||||
|
assert(codes.count(S(language)));
|
||||||
|
assert(codes.count(L"?"));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
6
extensions/translatewrapper.h
Normal file
6
extensions/translatewrapper.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
struct TranslationParam
|
||||||
|
{
|
||||||
|
std::wstring translateTo, translateFrom, authKey;
|
||||||
|
};
|
2
text.cpp
2
text.cpp
@ -324,7 +324,7 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
|
|||||||
#endif // SPANISH
|
#endif // SPANISH
|
||||||
|
|
||||||
#ifdef SIMPLIFIED_CHINESE
|
#ifdef SIMPLIFIED_CHINESE
|
||||||
NATIVE_LANGUAGE = "Chinese (simplified)";
|
NATIVE_LANGUAGE = "Chinese (Simplified)";
|
||||||
ATTACH = u8"附加到游戏";
|
ATTACH = u8"附加到游戏";
|
||||||
LAUNCH = u8"启动游戏";
|
LAUNCH = u8"启动游戏";
|
||||||
CONFIG = u8"配置游戏";
|
CONFIG = u8"配置游戏";
|
||||||
|
Loading…
Reference in New Issue
Block a user