2019-06-13 16:01:29 +08:00
|
|
|
|
#include "extension.h"
|
|
|
|
|
#include "network.h"
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QInputDialog>
|
2019-06-17 07:43:59 +08:00
|
|
|
|
#include <QFile>
|
2019-06-13 16:01:29 +08:00
|
|
|
|
|
|
|
|
|
extern const char* SELECT_LANGUAGE;
|
|
|
|
|
extern const char* SELECT_LANGUAGE_MESSAGE;
|
|
|
|
|
extern const wchar_t* TOO_MANY_TRANS_REQUESTS;
|
|
|
|
|
|
|
|
|
|
extern const char* TRANSLATION_PROVIDER;
|
|
|
|
|
extern QStringList languages;
|
|
|
|
|
extern Synchronized<std::wstring> translateTo;
|
|
|
|
|
std::pair<bool, std::wstring> Translate(const std::wstring& text);
|
|
|
|
|
|
2019-06-17 07:43:59 +08:00
|
|
|
|
Synchronized<std::unordered_map<std::wstring, std::wstring>> translationCache;
|
|
|
|
|
|
2019-06-13 16:01:29 +08:00
|
|
|
|
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
|
|
|
|
|
{
|
|
|
|
|
switch (ul_reason_for_call)
|
|
|
|
|
{
|
|
|
|
|
case DLL_PROCESS_ATTACH:
|
|
|
|
|
{
|
|
|
|
|
QTimer::singleShot(0, []
|
|
|
|
|
{
|
|
|
|
|
translateTo->assign(QInputDialog::getItem(
|
|
|
|
|
nullptr,
|
|
|
|
|
SELECT_LANGUAGE,
|
|
|
|
|
QString(SELECT_LANGUAGE_MESSAGE).arg(TRANSLATION_PROVIDER),
|
|
|
|
|
languages,
|
|
|
|
|
0,
|
|
|
|
|
false,
|
|
|
|
|
nullptr,
|
|
|
|
|
Qt::WindowCloseButtonHint)
|
|
|
|
|
.split(": ")[1]
|
|
|
|
|
.toStdWString()
|
|
|
|
|
);
|
|
|
|
|
});
|
2019-06-17 07:43:59 +08:00
|
|
|
|
|
|
|
|
|
QFile file(QString("%1 Cache.txt").arg(TRANSLATION_PROVIDER));
|
|
|
|
|
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
|
|
|
QStringList savedCache = QString(file.readAll()).split("|T|\n", QString::SkipEmptyParts);
|
|
|
|
|
for (int i = 0; i < savedCache.size() - 1; i += 2)
|
|
|
|
|
translationCache->insert({ savedCache[i].toStdWString(), savedCache[i + 1].toStdWString() });
|
2019-06-13 16:01:29 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case DLL_PROCESS_DETACH:
|
|
|
|
|
{
|
2019-06-17 07:43:59 +08:00
|
|
|
|
QFile file(QString("%1 Cache.txt").arg(TRANSLATION_PROVIDER));
|
|
|
|
|
file.open(QIODevice::WriteOnly | QIODevice::Text);
|
|
|
|
|
auto translationCache = ::translationCache.Acquire();
|
|
|
|
|
for (const auto& [original, translation] : translationCache.contents)
|
|
|
|
|
file.write(QString::fromStdWString(FormatString(L"%s|T|\n%s|T|\n", original, translation)).toUtf8());
|
2019-06-13 16:01:29 +08:00
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
|
|
|
|
|
{
|
|
|
|
|
if (sentenceInfo["text number"] == 0) return false;
|
|
|
|
|
|
|
|
|
|
static class
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
bool Request()
|
|
|
|
|
{
|
|
|
|
|
auto tokens = this->tokens.Acquire();
|
|
|
|
|
tokens->push_back(GetTickCount());
|
|
|
|
|
if (tokens->size() > tokenCount * 5) tokens->erase(tokens->begin(), tokens->begin() + tokenCount * 3);
|
|
|
|
|
tokens->erase(std::remove_if(tokens->begin(), tokens->end(), [this](DWORD token) { return GetTickCount() - token > delay; }), tokens->end());
|
|
|
|
|
return tokens->size() < tokenCount;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
const int tokenCount = 30, delay = 60 * 1000;
|
|
|
|
|
Synchronized<std::vector<DWORD>> tokens;
|
|
|
|
|
} rateLimiter;
|
|
|
|
|
|
|
|
|
|
bool cache = false;
|
|
|
|
|
std::wstring translation;
|
|
|
|
|
if (translationCache->count(sentence) != 0) translation = translationCache->at(sentence);
|
|
|
|
|
else if (!(rateLimiter.Request() || sentenceInfo["current select"])) translation = TOO_MANY_TRANS_REQUESTS;
|
|
|
|
|
else std::tie(cache, translation) = Translate(sentence);
|
|
|
|
|
if (cache) translationCache->insert({ sentence, translation });
|
|
|
|
|
Unescape(translation);
|
|
|
|
|
|
|
|
|
|
sentence += L"\n" + translation;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TEST(
|
|
|
|
|
{
|
|
|
|
|
std::wstring test = L"こんにちは";
|
|
|
|
|
ProcessSentence(test, { SentenceInfo::DUMMY });
|
|
|
|
|
assert(test.find(L"Hello") != std::wstring::npos);
|
|
|
|
|
}
|
|
|
|
|
);
|