forked from Public-Mirror/Textractor
add source language selection and rename variables
Added source language selection since autodetect fails sometimes Refactored names of variables
This commit is contained in:
parent
4b46057800
commit
9bb7fbff06
@ -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)
|
||||||
{
|
{
|
||||||
|
@ -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;
|
||||||
};
|
};
|
@ -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) };
|
||||||
}
|
}
|
@ -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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user