Textractor/extensions/translatewrapper.cpp

123 lines
4.1 KiB
C++
Raw Normal View History

#include "qtcommon.h"
#include "extension.h"
#include "blockmarkup.h"
2019-06-13 04:01:29 -04:00
#include "network.h"
#include <map>
#include <fstream>
2019-06-13 04:01:29 -04:00
#include <QTimer>
extern const char* NATIVE_LANGUAGE;
2019-06-13 04:01:29 -04:00
extern const char* SELECT_LANGUAGE;
extern const char* SELECT_LANGUAGE_MESSAGE;
2020-02-12 00:06:01 -07:00
extern const char* LANGUAGE_SAVED;
2019-06-13 04:01:29 -04:00
extern const wchar_t* TOO_MANY_TRANS_REQUESTS;
extern const char* TRANSLATION_PROVIDER;
extern QStringList languages;
std::pair<bool, std::wstring> Translate(const std::wstring& text);
2019-08-12 10:44:51 -04:00
const char* LANGUAGE = u8"Language";
const std::string TRANSLATION_CACHE_FILE = FormatString("%sCache.txt", TRANSLATION_PROVIDER);
2019-08-12 10:44:51 -04:00
Synchronized<std::wstring> translateTo = L"en";
Synchronized<std::map<std::wstring, std::wstring>> translationCache;
int savedSize;
2019-06-16 19:43:59 -04:00
void SaveCache()
{
std::wstring allTranslations(L"\xfeff");
for (const auto& [sentence, translation] : translationCache.Acquire().contents)
allTranslations.append(L"|SENTENCE|").append(sentence).append(L"|TRANSLATION|").append(translation).append(L"|END|\r\n");
std::ofstream(TRANSLATION_CACHE_FILE, std::ios::binary | std::ios::trunc).write((const char*)allTranslations.c_str(), allTranslations.size() * sizeof(wchar_t));
savedSize = translationCache->size();
}
2019-06-13 04:01:29 -04:00
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
2020-03-05 01:51:36 -07:00
static QSettings settings = openSettings();
2019-08-12 10:44:51 -04:00
settings.beginGroup(TRANSLATION_PROVIDER);
if (settings.contains(LANGUAGE)) translateTo->assign(S(settings.value(LANGUAGE).toString()));
else QTimer::singleShot(0, []
2019-06-13 04:01:29 -04:00
{
QString language = QInputDialog::getItem(
2019-06-13 04:01:29 -04:00
nullptr,
SELECT_LANGUAGE,
QString(SELECT_LANGUAGE_MESSAGE).arg(TRANSLATION_PROVIDER),
languages,
std::find_if(languages.begin(), languages.end(), [](QString language) { return language.startsWith(NATIVE_LANGUAGE); }) - languages.begin(),
2019-06-13 04:01:29 -04:00
false,
nullptr,
Qt::WindowCloseButtonHint
2019-06-13 04:01:29 -04:00
);
translateTo->assign(S(language.split(": ")[1]));
2019-08-12 10:44:51 -04:00
settings.setValue(LANGUAGE, S(translateTo->c_str()));
2020-02-12 00:06:01 -07:00
QMessageBox::information(nullptr, SELECT_LANGUAGE, QString(LANGUAGE_SAVED).arg(CONFIG_FILE));
2019-06-13 04:01:29 -04:00
});
2019-06-16 19:43:59 -04:00
std::ifstream stream(TRANSLATION_CACHE_FILE, std::ios::binary);
BlockMarkupIterator savedTranslations(stream, Array<std::wstring_view>{ L"|SENTENCE|", L"|TRANSLATION|" });
auto translationCache = ::translationCache.Acquire();
while (auto read = savedTranslations.Next())
{
auto& [sentence, translation] = read.value();
translationCache->try_emplace(std::move(sentence), std::move(translation));
}
savedSize = translationCache->size();
2019-06-13 04:01:29 -04:00
}
break;
case DLL_PROCESS_DETACH:
{
SaveCache();
2019-06-13 04:01:29 -04: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;
{
auto translationCache = ::translationCache.Acquire();
auto translationLocation = translationCache->find(sentence);
if (translationLocation != translationCache->end()) translation = translationLocation->second;
else if (!(rateLimiter.Request() || sentenceInfo["current select"])) translation = TOO_MANY_TRANS_REQUESTS;
else std::tie(cache, translation) = Translate(sentence);
if (cache && sentenceInfo["current select"]) translationCache->try_emplace(translationLocation, sentence, translation);
}
if (cache && translationCache->size() > savedSize + 50) SaveCache();
2019-06-13 04:01:29 -04:00
Unescape(translation);
2019-06-13 04:01:29 -04:00
sentence += L"\n" + translation;
return true;
}
TEST(
assert(Translate(L"こんにちは").second.find(L"ello") != std::wstring::npos)
2019-06-13 04:01:29 -04:00
);