add source language selection and rename variables

Added source language selection since autodetect fails sometimes
Refactored names of variables
This commit is contained in:
zeheyler 2020-11-04 01:23:20 +03:00
parent 4b46057800
commit 9bb7fbff06
4 changed files with 259 additions and 171 deletions

View File

@ -2,8 +2,8 @@
DevTools::DevTools(QObject* parent) : DevTools::DevTools(QObject* parent) :
QObject(parent), QObject(parent),
idcounter(0), idCounter(0),
idmethod(0), idMethod(0),
status("Stopped"), status("Stopped"),
session(0) session(0)
{ {
@ -29,19 +29,19 @@ void DevTools::startDevTools(QString path, bool headless, int port)
{ {
if (GetJsonfromHTTP(doc, "/json/version", port)) if (GetJsonfromHTTP(doc, "/json/version", port))
{ {
useragent = doc.object().value("User-Agent").toString(); userAgent = doc.object().value("User-Agent").toString();
} }
webSocket.open(webSocketDebuggerUrl); webSocket.open(webSocketDebuggerUrl);
session += 1; session += 1;
return; return;
} }
} }
status = "Failed to find chrome debug port!"; status = "Failed to find Chrome debug port!";
emit statusChanged(status); emit statusChanged(status);
} }
else else
{ {
status = "Failed to start chrome!"; status = "Failed to start Chrome!";
emit statusChanged(status); emit statusChanged(status);
} }
} }
@ -58,7 +58,7 @@ QString DevTools::getStatus()
QString DevTools::getUserAgent() QString DevTools::getUserAgent()
{ {
return useragent; return userAgent;
} }
DevTools::~DevTools() DevTools::~DevTools()
@ -136,7 +136,7 @@ bool DevTools::SendRequest(QString method, QJsonObject params, QJsonObject& root
QJsonDocument doc(json); QJsonDocument doc(json);
QString message(doc.toJson(QJsonDocument::Compact)); QString message(doc.toJson(QJsonDocument::Compact));
mutex.lock(); mutex.lock();
mapqueue.insert(std::make_pair(id, response)); mapQueue.insert(std::make_pair(id, response));
mutex.unlock(); mutex.unlock();
webSocket.sendTextMessage(message); webSocket.sendTextMessage(message);
webSocket.flush(); webSocket.flush();
@ -171,19 +171,19 @@ long DevTools::methodToReceive(QString method, QJsonObject params)
json.insert("method", method); json.insert("method", method);
json.insert("params", params); json.insert("params", params);
mutex.lock(); mutex.lock();
mapmethod.insert(std::make_pair(id, json)); mapMethod.insert(std::make_pair(id, json));
mutex.unlock(); mutex.unlock();
return id; return id;
} }
long DevTools::idIncrement() long DevTools::idIncrement()
{ {
return ++idcounter; return ++idCounter;
} }
long DevTools::idmIncrement() long DevTools::idmIncrement()
{ {
return ++idmethod; return ++idMethod;
} }
bool DevTools::isConnected() bool DevTools::isConnected()
@ -194,25 +194,30 @@ bool DevTools::isConnected()
return false; return false;
} }
bool DevTools::compareJson(QJsonValue storedparams, QJsonValue params) bool DevTools::compareJson(QJsonValue stored, QJsonValue params)
{ {
if (storedparams.isObject()) if (stored.isObject())
{ {
foreach(const QString & key, storedparams.toObject().keys()) foreach(const QString & key, stored.toObject().keys())
{ {
QJsonValue storedvalue = storedparams.toObject().value(key); QJsonValue storedvalue = stored.toObject().value(key);
QJsonValue value = params.toObject().value(key); QJsonValue value = params.toObject().value(key);
if (!compareJson(storedvalue, value)) if (!compareJson(storedvalue, value))
return false; return false;
} }
} }
else if (storedparams.isArray()) else if (stored.isArray())
{ {
for (int i = 0; i < storedparams.toArray().size(); i++) for (int i = 0; i < stored.toArray().size(); i++)
if (!compareJson(storedparams.toArray()[i], params.toArray()[i])) if (!compareJson(stored.toArray()[i], params.toArray()[i]))
return false; return false;
} }
else if (storedparams.toVariant() != params.toVariant()) else if (stored.isString())
{
if (!stored.toString().contains(params.toString()))
return false;
}
else if (stored.toVariant() != params.toVariant())
return false; return false;
return true; return true;
@ -220,8 +225,8 @@ bool DevTools::compareJson(QJsonValue storedparams, QJsonValue params)
bool DevTools::checkMethod(long id) bool DevTools::checkMethod(long id)
{ {
MapMethod::iterator iter = mapmethod.find(id); MapMethod::iterator iter = mapMethod.find(id);
if (iter == mapmethod.end()) if (iter == mapMethod.end())
return true; return true;
else else
return false; return false;
@ -235,13 +240,13 @@ void DevTools::onTextMessageReceived(QString message)
QJsonObject root = doc.object(); QJsonObject root = doc.object();
if (root.contains("method")) if (root.contains("method"))
{ {
for (auto iter = mapmethod.cbegin(); iter != mapmethod.cend();) for (auto iter = mapMethod.cbegin(); iter != mapMethod.cend();)
{ {
if (iter->second.value("method") == root.value("method") if (iter->second.value("method") == root.value("method")
&& compareJson(iter->second.value("params"), root.value("params"))) && compareJson(iter->second.value("params"), root.value("params")))
{ {
mutex.lock(); mutex.lock();
mapmethod.erase(iter++); mapMethod.erase(iter++);
mutex.unlock(); mutex.unlock();
} }
++iter; ++iter;
@ -251,12 +256,12 @@ void DevTools::onTextMessageReceived(QString message)
if (root.contains("id")) if (root.contains("id"))
{ {
long id = root.value("id").toInt(); long id = root.value("id").toInt();
MapResponse::iterator request = mapqueue.find(id); MapResponse::iterator request = mapQueue.find(id);
if (request != mapqueue.end()) if (request != mapQueue.end())
{ {
request->second.set(root); request->second.set(root);
mutex.lock(); mutex.lock();
mapqueue.erase(request); mapQueue.erase(request);
mutex.unlock(); mutex.unlock();
} }
return; return;
@ -266,20 +271,20 @@ void DevTools::onTextMessageReceived(QString message)
void DevTools::closeDevTools() void DevTools::closeDevTools()
{ {
if (this->mapqueue.size() > 0) if (this->mapQueue.size() > 0)
{ {
MapResponse::iterator iter = mapqueue.begin(); MapResponse::iterator iter = mapQueue.begin();
MapResponse::iterator iend = mapqueue.end(); MapResponse::iterator iend = mapQueue.end();
for (; iter != iend; iter++) for (; iter != iend; iter++)
{ {
iter->second.set_exception("exception"); iter->second.set_exception("exception");
} }
} }
webSocket.close(); webSocket.close();
mapmethod.clear(); mapMethod.clear();
mapqueue.clear(); mapQueue.clear();
idcounter = 0; idCounter = 0;
idmethod = 0; idMethod = 0;
DWORD exitCode = 0; DWORD exitCode = 0;
if (GetExitCodeProcess(processInfo.hProcess, &exitCode) != FALSE) if (GetExitCodeProcess(processInfo.hProcess, &exitCode) != FALSE)
{ {

View File

@ -37,15 +37,15 @@ private:
bool GetJsonfromHTTP(QJsonDocument& doc, QString object, int port = 9222); bool GetJsonfromHTTP(QJsonDocument& doc, QString object, int port = 9222);
long idIncrement(); long idIncrement();
long idmIncrement(); long idmIncrement();
bool compareJson(QJsonValue storedparams, QJsonValue params); bool compareJson(QJsonValue stored, QJsonValue params);
int session; int session;
QWebSocket webSocket; QWebSocket webSocket;
std::mutex mutex; std::mutex mutex;
MapResponse mapqueue; MapResponse mapQueue;
MapMethod mapmethod; MapMethod mapMethod;
long idcounter; long idCounter;
long idmethod; long idMethod;
PROCESS_INFORMATION processInfo; PROCESS_INFORMATION processInfo;
QString status; QString status;
QString useragent; QString userAgent;
}; };

View File

@ -3,21 +3,21 @@
#include "devtools.h" #include "devtools.h"
extern const wchar_t* TRANSLATION_ERROR; extern const wchar_t* TRANSLATION_ERROR;
extern Synchronized<std::wstring> translateTo; extern Synchronized<std::wstring> translateTo, translateFrom;
bool useCache = true, autostartchrome = false, headlesschrome = true; bool useCache = true, autoStartChrome = false, headlessChrome = true;
int maxSentenceSize = 500, chromeport = 9222; int maxSentenceSize = 500, chromePort = 9222;
const char* TRANSLATION_PROVIDER = "DevTools DeepL Translate"; const char* TRANSLATION_PROVIDER = "DevTools DeepL Translate";
const wchar_t* ERROR_CHROME = L"Error: chrome not started"; const wchar_t* ERROR_CHROME = L"Error: Chrome not started";
const wchar_t* ERROR_START_CHROME = L"Error: failed to start chrome or to connect to it"; const wchar_t* ERROR_START_CHROME = L"Error: failed to start Chrome or to connect to it";
const wchar_t* ERROR_GOT_TIMEOUT = L"Error: timeout (s)"; const wchar_t* ERROR_GOT_TIMEOUT = L"Error: timeout (s)";
const wchar_t* ERROR_COMMAND_FAIL = L"Error: command failed"; const wchar_t* ERROR_COMMAND_FAIL = L"Error: command failed";
const wchar_t* ERROR_LANGUAGE = L"Error: target languages do not match"; const wchar_t* ERROR_LANGUAGE = L"Error: target languages do not match";
const wchar_t* ERROR_NOTE = L"Error: notification"; const wchar_t* ERROR_NOTE = L"Error: notification";
QString URL = "https://www.deepl.com/en/translator"; QString URL = "https://www.deepl.com/en/translator";
QStringList languages QStringList languagesTo
{ {
"Chinese (simplified): zh", "Chinese (simplified): zh",
"Dutch: nl", "Dutch: nl",
@ -32,21 +32,37 @@ QStringList languages
"Spanish: es", "Spanish: es",
}; };
int docfound = -1, targetNodeId = -1, session = -1, pageenabled = -1, useragentflag = -1, backup = -1; QStringList languagesFrom
long update = -1, callnumber = 0; {
std::vector<long> callqueue; "Any language: ",
"Chinese: zh",
"Dutch: nl",
"English: en",
"French: fr",
"German: de",
"Italian: it",
"Japanese: ja",
"Polish: pl",
"Portuguese: pt",
"Russian: ru",
"Spanish: es",
};
std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devtools) int docFound = -1, targetNodeId = -1, session = -1, pageEnabled = -1, userAgentFlag = -1, backup = -1, sourceLangId = -1;
long update = -1, callNumber = 0;
std::vector<long> callQueue;
std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devTools)
{ {
QString qtext = S(text); QString qtext = S(text);
qtext.remove(QString(12288)); // japanese space (no need for translator) qtext.remove(QString(12288)); // japanese space (no need for translator)
// Remove quotes // Remove quotes
bool checkquote = false; bool checkQuote = false;
if ((qtext.front() == QString(12300) && qtext.back() == QString(12301)) // japanese quotation marks if ((qtext.front() == QString(12300) && qtext.back() == QString(12301)) // japanese quotation marks
|| (qtext.front() == "\"" && qtext.back() == "\"")) || (qtext.front() == "\"" && qtext.back() == "\""))
{ {
checkquote = true; checkQuote = true;
qtext.remove(0, 1); qtext.remove(0, 1);
qtext.chop(1); qtext.chop(1);
} }
@ -65,29 +81,30 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devt
} }
// Put quotes back // Put quotes back
if (checkquote) if (checkQuote)
{ {
qtext = "\"" + qtext + "\""; qtext = "\"" + qtext + "\"";
} }
// Check status // Check status
if (devtools->getStatus() == "Stopped") if (devTools->getStatus() == "Stopped")
{ {
return { false, FormatString(L"%s", ERROR_CHROME) }; return { false, FormatString(L"%s", ERROR_CHROME) };
} }
if (devtools->getStatus().startsWith("Fail") || devtools->getStatus().startsWith("Unconnected")) if (devTools->getStatus().startsWith("Fail") || devTools->getStatus().startsWith("Unconnected"))
{ {
return { false, FormatString(L"%s", ERROR_START_CHROME) }; return { false, FormatString(L"%s", ERROR_START_CHROME) };
} }
if (session != devtools->getSession()) if (session != devTools->getSession())
{ {
session = devtools->getSession(); session = devTools->getSession();
docfound = -1; docFound = -1;
targetNodeId = -1; targetNodeId = -1;
pageenabled = -1; sourceLangId = -1;
useragentflag = -1; pageEnabled = -1;
userAgentFlag = -1;
update = -1; update = -1;
callnumber = 0; callNumber = 0;
backup = -1; backup = -1;
} }
@ -97,98 +114,112 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devt
// Enable page feedback // Enable page feedback
QJsonObject root; QJsonObject root;
int errorcode = 0; int errorCode = 0;
if (pageenabled == -1) if (pageEnabled == -1)
{ {
if (!devtools->SendRequest("Page.enable", {}, root)) if (!devTools->SendRequest("Page.enable", {}, root))
errorcode = 1; errorCode = 1;
else else
pageenabled = 1; pageEnabled = 1;
} }
// Change user-agent if in headless mode // Change user-agent if in headless mode
if (useragentflag == -1 && errorcode == 0) if (userAgentFlag == -1 && errorCode == 0)
{ {
QString useragent = devtools->getUserAgent(); QString userAgent = devTools->getUserAgent();
if (!useragent.isEmpty()) if (!userAgent.isEmpty())
{ {
useragent.replace("HeadlessChrome", "Chrome"); userAgent.replace("HeadlessChrome", "Chrome");
if (!devtools->SendRequest("Network.setUserAgentOverride", { {"userAgent", useragent} }, root)) if (!devTools->SendRequest("Network.setUserAgentOverride", { {"userAgent", userAgent} }, root))
errorcode = 1; errorCode = 1;
else else
useragentflag = 1; userAgentFlag = 1;
} }
} }
// Increase queue counter and wait until previous calls are done // Increase queue counter and wait until previous calls are done
float timer = 0; float timer = 0;
int timer_stop = 10; int timerStop = 10;
long calltag = ++callnumber; long callTag = ++callNumber;
callqueue.insert(callqueue.begin(), calltag); callQueue.insert(callQueue.begin(), callTag);
while (errorcode == 0 && callqueue.back() != calltag && timer < 2 * timer_stop) while (errorCode == 0 && callQueue.back() != callTag && timer < 2 * timerStop)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
timer += 0.1; timer += 0.1;
} }
if (timer >= timer_stop) if (timer >= timerStop)
errorcode = 5; errorCode = 5;
// Set methods to receive // Set methods to receive
long navigate = devtools->methodToReceive("Page.navigatedWithinDocument"); long navigate = devTools->methodToReceive("Page.navigatedWithinDocument");
long target; long target;
if (backup == -1) if (backup == -1)
target = devtools->methodToReceive("DOM.attributeModified", { { "value" , "lmt__mobile_share_container lmt--mobile-hidden" } }); target = devTools->methodToReceive("DOM.attributeModified", { { "value" , "lmt__mobile_share_container lmt--mobile-hidden" } });
else else
target = devtools->methodToReceive("DOM.childNodeCountUpdated"); target = devTools->methodToReceive("DOM.childNodeCountUpdated");
if (update == -1) if (update == -1)
update = devtools->methodToReceive("DOM.documentUpdated"); update = devTools->methodToReceive("DOM.documentUpdated");
// Navigate to site and wait until it is loaded // Navigate to site and wait until it is loaded
QString fullurl = URL + "#ja/" + S(translateTo.Copy()) + "/" + qtext; QString checkFrom = translateFrom.Copy().empty() ? "ja" : S(translateFrom.Copy());
if (errorcode == 0 && !devtools->SendRequest("Page.navigate", { {"url", fullurl} }, root)) QString fullUrl = URL + "#" + checkFrom + "/" + S(translateTo.Copy()) + "/" + qtext;
errorcode = 1; if (errorCode == 0 && !devTools->SendRequest("Page.navigate", { {"url", fullUrl} }, root))
errorCode = 1;
timer = 0; timer = 0;
while (errorcode == 0 && !devtools->checkMethod(navigate) && timer < timer_stop) while (errorCode == 0 && !devTools->checkMethod(navigate) && timer < timerStop)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
timer += 0.1; timer += 0.1;
} }
if (timer >= timer_stop) if (timer >= timerStop)
errorcode = 2; errorCode = 2;
// Check if document is outdated // Check if document is outdated
if (devtools->checkMethod(update)) if (devTools->checkMethod(update))
{ {
docfound = -1; docFound = -1;
targetNodeId = -1; targetNodeId = -1;
update = -1; update = -1;
} }
// Get document // Get document
if (docfound == -1 && errorcode == 0) if (docFound == -1 && errorCode == 0)
{ {
if (!devtools->SendRequest("DOM.getDocument", {}, root)) if (!devTools->SendRequest("DOM.getDocument", {}, root))
errorcode = 1; errorCode = 1;
else else
docfound = root.value("result").toObject().value("root").toObject().value("nodeId").toInt(); docFound = root.value("result").toObject().value("root").toObject().value("nodeId").toInt();
} }
// Get target selector // Get target selector
if (targetNodeId == -1 && errorcode == 0) if (targetNodeId == -1 && errorCode == 0)
{ {
if (!devtools->SendRequest("DOM.querySelector", { {"nodeId", docfound}, {"selector", "textarea.lmt__target_textarea"} }, root) if (!devTools->SendRequest("DOM.querySelector", { {"nodeId", docFound}, {"selector", "textarea.lmt__target_textarea"} }, root)
|| root.value("result").toObject().value("nodeId").toInt() == 0) || root.value("result").toObject().value("nodeId").toInt() == 0)
{ {
docfound = -1; docFound = -1;
errorcode = 1; errorCode = 1;
} }
else else
targetNodeId = root.value("result").toObject().value("nodeId").toInt(); targetNodeId = root.value("result").toObject().value("nodeId").toInt();
} }
// Get source language selector
if (sourceLangId == -1 && errorCode == 0)
{
if (!devTools->SendRequest("DOM.querySelector", { {"nodeId", docFound}, {"selector", "div.lmt__language_select--source"} }, root)
|| root.value("result").toObject().value("nodeId").toInt() == 0)
{
docFound = -1;
errorCode = 1;
}
else
sourceLangId = root.value("result").toObject().value("nodeId").toInt();
}
// Wait for the translation to appear on the web page // Wait for the translation to appear on the web page
timer = 0; timer = 0;
while (errorcode == 0 && !devtools->checkMethod(target) && timer < timer_stop) while (errorCode == 0 && !devTools->checkMethod(target) && timer < timerStop)
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(100)); std::this_thread::sleep_for(std::chrono::milliseconds(100));
timer += 0.1; timer += 0.1;
@ -196,10 +227,10 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devt
// Catch the translation // Catch the translation
QString OuterHTML; QString OuterHTML;
if (errorcode == 0 && !devtools->SendRequest("DOM.getOuterHTML", { {"nodeId", targetNodeId + 1} }, root)) if (errorCode == 0 && !devTools->SendRequest("DOM.getOuterHTML", { {"nodeId", targetNodeId + 1} }, root))
{ {
targetNodeId = -1; targetNodeId = -1;
errorcode = 1; errorCode = 1;
} }
else else
{ {
@ -209,57 +240,90 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devt
{ {
// Try to catch the notification // Try to catch the notification
int noteNodeId = -1; int noteNodeId = -1;
if (errorcode == 0 && (!devtools->SendRequest("DOM.querySelector", { {"nodeId", docfound}, {"selector", "div.lmt__system_notification"} }, root) if (errorCode == 0 && (!devTools->SendRequest("DOM.querySelector", { {"nodeId", docFound}, {"selector", "div.lmt__system_notification"} }, root)
|| root.value("result").toObject().value("nodeId").toInt() == 0) && timer >= timer_stop) || root.value("result").toObject().value("nodeId").toInt() == 0) && timer >= timerStop)
{ {
errorcode = 2; errorCode = 2;
} }
else else
{ {
noteNodeId = root.value("result").toObject().value("nodeId").toInt(); noteNodeId = root.value("result").toObject().value("nodeId").toInt();
if (errorcode == 0 && devtools->SendRequest("DOM.getOuterHTML", { {"nodeId", noteNodeId} }, root)) if (errorCode == 0 && devTools->SendRequest("DOM.getOuterHTML", { {"nodeId", noteNodeId} }, root))
{ {
OuterHTML = root.value("result").toObject().value("outerHTML").toString(); OuterHTML = root.value("result").toObject().value("outerHTML").toString();
} }
errorcode = 3; errorCode = 3;
} }
} }
OuterHTML.remove(QRegExp("<[^>]*>")); OuterHTML.remove(QRegExp("<[^>]*>"));
OuterHTML = OuterHTML.trimmed(); OuterHTML = OuterHTML.trimmed();
if (backup == -1 && errorcode == 0 && timer >= timer_stop) if (backup == -1 && errorCode == 0 && timer >= timerStop)
backup = 1; backup = 1;
// Check if the translator output language does not match the selected language // Check if the translator output language does not match the selected language
QString targetlang; QString targetLang;
if (errorcode == 0 && devtools->SendRequest("DOM.getAttributes", { {"nodeId", targetNodeId} }, root)) if (errorCode == 0 && devTools->SendRequest("DOM.getAttributes", { {"nodeId", targetNodeId} }, root))
{ {
QJsonArray attributes = root.value("result").toObject().value("attributes").toArray(); QJsonArray attributes = root.value("result").toObject().value("attributes").toArray();
for (size_t i = 0; i < attributes.size(); i++) for (size_t i = 0; i < attributes.size(); i++)
{ {
if (attributes[i].toString() == "lang") if (attributes[i].toString() == "lang")
{ {
targetlang = attributes[i + 1].toString().mid(0, 2); targetLang = attributes[i + 1].toString().mid(0, 2);
if (targetlang != S(translateTo.Copy())) if (targetLang != S(translateTo.Copy()))
{ {
errorcode = 4; errorCode = 4;
} }
} }
break;
}
}
// Check selected source language
if (errorCode == 0 && devTools->SendRequest("DOM.getAttributes", { {"nodeId", sourceLangId} }, root))
{
QJsonArray attributes = root.value("result").toObject().value("attributes").toArray();
for (size_t i = 0; i < attributes.size(); i++)
{
if (attributes[i].toString() == "dl-selected-lang"
&& attributes[i + 1].toString().mid(0, 2) != S(translateFrom.Copy()))
{
QStringList::const_iterator constIter;
for (constIter = languagesFrom.constBegin(); constIter != languagesFrom.constEnd(); ++constIter)
{
if (constIter->contains(": " + S(translateFrom.Copy())))
break;
}
devTools->SendRequest("Runtime.evaluate", { {"expression",
"document\
.querySelector('div.lmt__language_select--source')\
.querySelector('button.lmt__language_select__active')\
.click();\
document\
.evaluate(\"//button[contains(text(), '"
+ constIter->split(": ")[0] + "')]\", \
document.querySelector('div.lmt__language_select__menu'),\
null, XPathResult.FIRST_ORDERED_NODE_TYPE, null)\
.singleNodeValue\
.click();"
} }, root);
}
} }
} }
callqueue.pop_back(); callQueue.pop_back();
if (errorcode == 0) if (errorCode == 0)
return { true, S(OuterHTML) }; return { true, S(OuterHTML) };
else if (errorcode == 1) else if (errorCode == 1)
return { false, FormatString(L"%s", ERROR_COMMAND_FAIL) }; return { false, FormatString(L"%s", ERROR_COMMAND_FAIL) };
else if (errorcode == 2) else if (errorCode == 2)
return { false, FormatString(L"%s: %d", ERROR_GOT_TIMEOUT, timer_stop) }; return { false, FormatString(L"%s: %d", ERROR_GOT_TIMEOUT, timerStop) };
else if (errorcode == 3) else if (errorCode == 3)
return { false, FormatString(L"%s: %s", ERROR_NOTE, S(OuterHTML)) }; return { false, FormatString(L"%s: %s", ERROR_NOTE, S(OuterHTML)) };
else if (errorcode == 4) else if (errorCode == 4)
return { false, FormatString(L"%s (%s): %s", ERROR_LANGUAGE, S(targetlang), S(OuterHTML)) }; return { false, FormatString(L"%s (%s): %s", ERROR_LANGUAGE, S(targetLang), S(OuterHTML)) };
else if (errorcode == 5) else if (errorCode == 5)
return { false, FormatString(L"%s: %d", ERROR_GOT_TIMEOUT, 2*timer_stop) }; return { false, FormatString(L"%s: %d", ERROR_GOT_TIMEOUT, 2*timerStop) };
else else
return { false, FormatString(L"%s", TRANSLATION_ERROR) }; return { false, FormatString(L"%s", TRANSLATION_ERROR) };
} }

View File

@ -13,33 +13,37 @@ extern const char* TRANSLATE_SELECTED_THREAD_ONLY;
extern const char* USE_TRANS_CACHE; extern const char* USE_TRANS_CACHE;
extern const char* MAX_SENTENCE_SIZE; extern const char* MAX_SENTENCE_SIZE;
extern const char* TRANSLATION_PROVIDER; extern const char* TRANSLATION_PROVIDER;
extern QStringList languages; extern QStringList languagesTo;
const char* PATH_TO_CHROME = u8"Path to chrome"; extern QStringList languagesFrom;
const char* AUTO_START_CHROME = u8"Start chrome automatically"; const char* TRANSLATE_FROM = u8"Translate from";
const char* NATIVE_LANGUAGE_FROM = u8"Japanese";
const char* PATH_TO_CHROME = u8"Path to Chrome";
const char* AUTO_START_CHROME = u8"Start Chrome automatically";
const char* HEADLESS_CHROME = u8"Start in headless mode"; const char* HEADLESS_CHROME = u8"Start in headless mode";
const char* CHROME_DEBUG_PORT = u8"Chrome debug port"; const char* CHROME_DEBUG_PORT = u8"Chrome debug port";
const char* DEV_TOOLS_STATUS = u8"Status: "; const char* DEV_TOOLS_STATUS = u8"Status: ";
const char* START_DEV_TOOLS_BUTTON = u8"Start"; const char* START_DEV_TOOLS_BUTTON = u8"Start";
const char* START_DEV_TOOLS = u8"Start chrome"; const char* START_DEV_TOOLS = u8"Start Chrome";
const char* STOP_DEV_TOOLS_BUTTON = u8"Stop"; const char* STOP_DEV_TOOLS_BUTTON = u8"Stop";
const char* STOP_DEV_TOOLS = u8"Stop chrome"; const char* STOP_DEV_TOOLS = u8"Stop Chrome";
extern bool useCache, autostartchrome, headlesschrome; extern bool useCache, autoStartChrome, headlessChrome;
extern int maxSentenceSize, chromeport; extern int maxSentenceSize, chromePort;
std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devtools); std::pair<bool, std::wstring> Translate(const std::wstring& text, DevTools* devTools);
const char* LANGUAGE = u8"Language"; const char* LANGUAGE_TO = u8"Language";
const char* LANGUAGE_FROM = u8"Language from";
const std::string TRANSLATION_CACHE_FILE = FormatString("%s Cache.txt", TRANSLATION_PROVIDER); const std::string TRANSLATION_CACHE_FILE = FormatString("%s Cache.txt", TRANSLATION_PROVIDER);
QFormLayout* display; QFormLayout* display;
QSettings settings = openSettings(); Settings settings;
Synchronized<std::wstring> translateTo = L"en"; Synchronized<std::wstring> translateTo = L"en", translateFrom = L"ja";
Synchronized<std::map<std::wstring, std::wstring>> translationCache; Synchronized<std::map<std::wstring, std::wstring>> translationCache;
int savedSize; int savedSize;
DevTools* devtools = nullptr; DevTools* devTools = nullptr;
std::wstring pathtochrome = L""; std::wstring pathToChrome = L"";
void SaveCache() void SaveCache()
{ {
@ -67,23 +71,35 @@ public:
Window() : Window() :
QDialog(nullptr, Qt::WindowMinMaxButtonsHint) QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
{ {
localize();
display = new QFormLayout(this); display = new QFormLayout(this);
settings.beginGroup(TRANSLATION_PROVIDER); settings.beginGroup(TRANSLATION_PROVIDER);
auto languageBox = new QComboBox(this); auto languageBoxTo = new QComboBox(this);
languageBox->addItems(languages); languageBoxTo->addItems(languagesTo);
int language = -1; int languageTo = -1;
if (settings.contains(LANGUAGE)) language = languageBox->findText(settings.value(LANGUAGE).toString(), Qt::MatchEndsWith); if (settings.contains(LANGUAGE_TO)) languageTo = languageBoxTo->findText(settings.value(LANGUAGE_TO).toString(), Qt::MatchEndsWith);
if (language < 0) language = languageBox->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith); if (languageTo < 0) languageTo = languageBoxTo->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
if (language < 0) language = languageBox->findText("English", Qt::MatchStartsWith); if (languageTo < 0) languageTo = languageBoxTo->findText("English", Qt::MatchStartsWith);
languageBox->setCurrentIndex(language); languageBoxTo->setCurrentIndex(languageTo);
saveLanguage(languageBox->currentText()); saveLanguage(languageBoxTo->currentText());
display->addRow(TRANSLATE_TO, languageBox); display->addRow(TRANSLATE_TO, languageBoxTo);
connect(languageBox, &QComboBox::currentTextChanged, this, &Window::saveLanguage); connect(languageBoxTo, &QComboBox::currentTextChanged, this, &Window::saveLanguage);
auto languageBoxFrom = new QComboBox(this);
languageBoxFrom->addItems(languagesFrom);
int languageFrom = -1;
if (settings.contains(LANGUAGE_FROM)) languageFrom = languageBoxFrom->findText(settings.value(LANGUAGE_FROM).toString(), Qt::MatchEndsWith);
if (languageFrom < 0) languageFrom = languageBoxFrom->findText(NATIVE_LANGUAGE_FROM, Qt::MatchStartsWith);
if (languageFrom < 0) languageFrom = languageBoxFrom->findText("Japanese", Qt::MatchStartsWith);
languageBoxFrom->setCurrentIndex(languageFrom);
saveLanguageFrom(languageBoxFrom->currentText());
display->addRow(TRANSLATE_FROM, languageBoxFrom);
connect(languageBoxFrom, &QComboBox::currentTextChanged, this, &Window::saveLanguageFrom);
for (auto [value, label] : Array<bool&, const char*>{ for (auto [value, label] : Array<bool&, const char*>{
{ useCache, USE_TRANS_CACHE }, { useCache, USE_TRANS_CACHE },
{ autostartchrome, AUTO_START_CHROME }, { autoStartChrome, AUTO_START_CHROME },
//{ headlesschrome, HEADLESS_CHROME } //{ headlessChrome, HEADLESS_CHROME }
}) })
{ {
value = settings.value(label, value).toBool(); value = settings.value(label, value).toBool();
@ -94,7 +110,7 @@ public:
} }
for (auto [value, label] : Array<int&, const char*>{ for (auto [value, label] : Array<int&, const char*>{
{ maxSentenceSize, MAX_SENTENCE_SIZE }, { maxSentenceSize, MAX_SENTENCE_SIZE },
{ chromeport, CHROME_DEBUG_PORT }, { chromePort, CHROME_DEBUG_PORT },
}) })
{ {
value = settings.value(label, value).toInt(); value = settings.value(label, value).toInt();
@ -106,24 +122,24 @@ public:
} }
auto keyInput = new QLineEdit(settings.value(PATH_TO_CHROME).toString()); auto keyInput = new QLineEdit(settings.value(PATH_TO_CHROME).toString());
pathtochrome = (S(keyInput->text())); pathToChrome = (S(keyInput->text()));
if (pathtochrome.empty()) if (pathToChrome.empty())
{ {
for (auto defaultpath : Array<std::wstring>{ for (auto defaultPath : Array<std::wstring>{
{ L"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe" }, { L"C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe" },
{ L"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" }, { L"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe" },
}) })
if (std::filesystem::exists(defaultpath)) if (std::filesystem::exists(defaultPath))
{ {
pathtochrome = defaultpath; pathToChrome = defaultPath;
keyInput->setText(S(pathtochrome)); keyInput->setText(S(pathToChrome));
} }
} }
connect(keyInput, &QLineEdit::textChanged, [keyInput](QString key) { settings.setValue(PATH_TO_CHROME, S(pathtochrome = (S(key)))); }); connect(keyInput, &QLineEdit::textChanged, [keyInput](QString key) { settings.setValue(PATH_TO_CHROME, S(pathToChrome = (S(key)))); });
display->addRow(PATH_TO_CHROME, keyInput); display->addRow(PATH_TO_CHROME, keyInput);
connect(&startButton, &QPushButton::clicked, this, &Window::start); connect(&startButton, &QPushButton::clicked, this, &Window::Start);
connect(&stopButton, &QPushButton::clicked, this, &Window::stop); connect(&stopButton, &QPushButton::clicked, this, &Window::Stop);
display->addRow(START_DEV_TOOLS, &startButton); display->addRow(START_DEV_TOOLS, &startButton);
display->addRow(STOP_DEV_TOOLS, &stopButton); display->addRow(STOP_DEV_TOOLS, &stopButton);
@ -144,39 +160,42 @@ public:
} }
savedSize = translationCache->size(); savedSize = translationCache->size();
devtools = new DevTools(this); devTools = new DevTools(this);
connect(devtools, &DevTools::statusChanged, [this](QString text) connect(devTools, &DevTools::statusChanged, [this](QString text)
{ {
status.setText(text); status.setText(text);
}); });
if (autostartchrome) if (autoStartChrome)
QMetaObject::invokeMethod(this, &Window::start, Qt::QueuedConnection); QMetaObject::invokeMethod(this, &Window::Start, Qt::QueuedConnection);
} }
~Window() ~Window()
{ {
stop(); Stop();
if (devtools != nullptr) if (devTools != nullptr)
delete devtools; delete devTools;
SaveCache(); SaveCache();
} }
private: private:
void start() void Start()
{ {
if (devtools->getStatus() == "Stopped") if (devTools->getStatus() == "Stopped")
devtools->startDevTools(S(pathtochrome), headlesschrome, chromeport); devTools->startDevTools(S(pathToChrome), headlessChrome, chromePort);
} }
void stop() void Stop()
{ {
devtools->closeDevTools(); devTools->closeDevTools();
} }
void saveLanguage(QString language) void saveLanguage(QString language)
{ {
settings.setValue(LANGUAGE, S(translateTo->assign(S(language.split(": ")[1])))); settings.setValue(LANGUAGE_TO, S(translateTo->assign(S(language.split(": ")[1]))));
}
void saveLanguageFrom(QString language)
{
settings.setValue(LANGUAGE_FROM, S(translateFrom->assign(S(language.split(": ")[1]))));
} }
QPushButton startButton{ START_DEV_TOOLS_BUTTON, this }; QPushButton startButton{ START_DEV_TOOLS_BUTTON, this };
QPushButton stopButton{ STOP_DEV_TOOLS_BUTTON, this }; QPushButton stopButton{ STOP_DEV_TOOLS_BUTTON, this };
@ -197,7 +216,7 @@ bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
if (translation.empty() && (sentenceInfo["current select"])) if (translation.empty() && (sentenceInfo["current select"]))
{ {
EraseControlCharacters(sentence); EraseControlCharacters(sentence);
std::tie(cache, translation) = Translate(sentence, devtools); std::tie(cache, translation) = Translate(sentence, devTools);
} }
if (cache) translationCache->try_emplace(sentence, translation); if (cache) translationCache->try_emplace(sentence, translation);