add gcp translator and add continous dialog for translators and update language lists and make extension dialogs uncloseable without properly removing the extension

This commit is contained in:
Akash Mozumdar 2020-03-16 02:56:04 -06:00
parent df3d3a0355
commit ac4cec9708
17 changed files with 375 additions and 184 deletions

View File

@ -15,18 +15,21 @@ extern const char* CONFIRM_EXTENSION_OVERWRITE;
extern const char* EXTENSION_WRITE_ERROR;
extern const char* EXTEN_WINDOW_INSTRUCTIONS;
constexpr auto DEFAULT_EXTENSIONS = u8"Remove Repeated Characters>Remove Repeated Phrases>Regex Filter>Copy to Clipboard>Bing Translate>Extra Window>Extra Newlines";
namespace
{
constexpr auto EXTEN_SAVE_FILE = u8"SavedExtensions.txt";
constexpr auto DEFAULT_EXTENSIONS = u8"Remove Repeated Characters>Remove Repeated Phrases>Regex Filter>Copy to Clipboard>Bing Translate>Extra Window>Extra Newlines";
struct Extension
{
std::wstring name;
wchar_t* (*callback)(wchar_t*, const InfoForExtension*);
};
Ui::ExtenWindow ui;
concurrency::reader_writer_lock extenMutex;
std::vector<Extension> extensions;
ExtenWindow* This = nullptr;
bool Load(QString extenName)
{
@ -62,6 +65,39 @@ namespace
extensions.push_back(*std::find_if(::extensions.begin(), ::extensions.end(), [&](Extension extension) { return extension.name == S(extenName); }));
::extensions = extensions;
}
void Sync()
{
ui.extenList->clear();
QTextFile extenSaveFile(EXTEN_SAVE_FILE, QIODevice::WriteOnly | QIODevice::Truncate);
concurrency::reader_writer_lock::scoped_lock_read readLock(extenMutex);
for (auto extension : extensions)
{
ui.extenList->addItem(S(extension.name));
extenSaveFile.write((S(extension.name) + ">").toUtf8());
}
}
void Add(QFileInfo extenFile)
{
if (extenFile.suffix() == "dll")
{
if (extenFile.absolutePath() != QDir::currentPath())
{
if (QFile::exists(extenFile.fileName()) && QMessageBox::question(This, EXTENSIONS, CONFIRM_EXTENSION_OVERWRITE) == QMessageBox::Yes) QFile::remove(extenFile.fileName());
if (!QFile::copy(extenFile.absoluteFilePath(), extenFile.fileName())) QMessageBox::warning(This, EXTENSIONS, EXTENSION_WRITE_ERROR);
}
if (Load(extenFile.completeBaseName())) return Sync();
}
QMessageBox::information(This, EXTENSIONS, QString(INVALID_EXTENSION).arg(extenFile.fileName()));
}
void OpenMenu(QPoint point)
{
QAction addExtension(ADD_EXTENSION);
if (QMenu::exec({ &addExtension }, ui.extenList->mapToGlobal(point), nullptr, This))
if (QString extenFile = QFileDialog::getOpenFileName(This, ADD_EXTENSION, ".", EXTENSIONS + QString(" (*.dll)")); !extenFile.isEmpty()) Add(extenFile);
}
}
bool DispatchSentenceToExtensions(std::wstring& sentence, const InfoForExtension* sentenceInfo)
@ -84,57 +120,22 @@ void CleanupExtensions()
}
ExtenWindow::ExtenWindow(QWidget* parent) :
QMainWindow(parent, Qt::WindowCloseButtonHint),
ui(new Ui::ExtenWindow)
QMainWindow(parent, Qt::WindowCloseButtonHint)
{
ui->setupUi(this);
connect(ui->extenList, &QListWidget::customContextMenuRequested, [this](QPoint point)
{
if (QMenu(this).exec({ std::make_unique<QAction>(ADD_EXTENSION).get() }, ui->extenList->mapToGlobal(point)))
if (QString extenFile = QFileDialog::getOpenFileName(this, ADD_EXTENSION, ".", EXTENSIONS + QString(" (*.dll)")); !extenFile.isEmpty()) Add(extenFile);
});
ui->vboxLayout->addWidget(new QLabel(EXTEN_WINDOW_INSTRUCTIONS, this));
This = this;
ui.setupUi(this);
ui.vboxLayout->addWidget(new QLabel(EXTEN_WINDOW_INSTRUCTIONS, this));
setWindowTitle(EXTENSIONS);
ui->extenList->installEventFilter(this);
connect(ui.extenList, &QListWidget::customContextMenuRequested, OpenMenu);
ui.extenList->installEventFilter(this);
if (!QFile::exists(EXTEN_SAVE_FILE)) QTextFile(EXTEN_SAVE_FILE, QIODevice::WriteOnly).write(DEFAULT_EXTENSIONS);
for (auto extenName : QString(QTextFile(EXTEN_SAVE_FILE, QIODevice::ReadOnly).readAll()).split(">")) Load(extenName);
Sync();
}
ExtenWindow::~ExtenWindow()
{
delete ui;
}
void ExtenWindow::Add(QFileInfo extenFile)
{
if (extenFile.suffix() == "dll")
{
if (extenFile.absolutePath() != QDir::currentPath())
{
if (QFile::exists(extenFile.fileName()) && QMessageBox::question(this, EXTENSIONS, CONFIRM_EXTENSION_OVERWRITE) == QMessageBox::Yes) QFile::remove(extenFile.fileName());
if (!QFile::copy(extenFile.absoluteFilePath(), extenFile.fileName())) QMessageBox::warning(this, EXTENSIONS, EXTENSION_WRITE_ERROR);
}
if (Load(extenFile.completeBaseName())) return Sync();
}
QMessageBox::information(this, EXTENSIONS, QString(INVALID_EXTENSION).arg(extenFile.fileName()));
}
void ExtenWindow::Sync()
{
ui->extenList->clear();
QTextFile extenSaveFile(EXTEN_SAVE_FILE, QIODevice::WriteOnly | QIODevice::Truncate);
concurrency::reader_writer_lock::scoped_lock_read readLock(extenMutex);
for (auto extension : extensions)
{
ui->extenList->addItem(S(extension.name));
extenSaveFile.write((S(extension.name) + ">").toUtf8());
}
}
ExtenWindow::~ExtenWindow() = default;
bool ExtenWindow::eventFilter(QObject* target, QEvent* event)
{
@ -142,7 +143,7 @@ bool ExtenWindow::eventFilter(QObject* target, QEvent* event)
if (event->type() == QEvent::ChildRemoved)
{
QStringList extenNames;
for (int i = 0; i < ui->extenList->count(); ++i) extenNames.push_back(ui->extenList->item(i)->text());
for (int i = 0; i < ui.extenList->count(); ++i) extenNames.push_back(ui.extenList->item(i)->text());
Reorder(extenNames);
Sync();
}
@ -151,9 +152,9 @@ bool ExtenWindow::eventFilter(QObject* target, QEvent* event)
void ExtenWindow::keyPressEvent(QKeyEvent* event)
{
if (event->key() == Qt::Key_Delete && ui->extenList->currentItem())
if (event->key() == Qt::Key_Delete && ui.extenList->currentItem())
{
Unload(ui->extenList->currentIndex().row());
Unload(ui.extenList->currentIndex().row());
Sync();
}
}

View File

@ -23,14 +23,8 @@ public:
~ExtenWindow();
private:
inline static constexpr auto EXTEN_SAVE_FILE = u8"SavedExtensions.txt";
void Add(QFileInfo extenFile);
void Sync();
bool eventFilter(QObject* target, QEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;
void dropEvent(QDropEvent* event) override;
Ui::ExtenWindow* ui;
};

View File

@ -74,8 +74,8 @@ namespace
enum LaunchWithJapaneseLocale { PROMPT, ALWAYS, NEVER };
Ui::MainWindow ui;
std::atomic<DWORD> selectedProcessId = 0;
Ui::MainWindow ui{};
ExtenWindow* extenWindow = nullptr;
std::unordered_set<DWORD> alreadyAttached;
bool autoAttach = false, autoAttachSavedOnly = true;

View File

@ -40,6 +40,7 @@ foreach ($language in @{
"Extra Newlines.dll",
"Extra Window.dll",
"Google Translate.dll",
"Google Cloud Translate.dll",
"Lua.dll",
"Regex Filter.dll",
"Remove Repeated Characters.dll",

View File

@ -9,6 +9,7 @@ add_library(Copy\ to\ Clipboard MODULE copyclipboard.cpp extensionimpl.cpp)
add_library(Extra\ Newlines MODULE extranewlines.cpp extensionimpl.cpp)
add_library(Extra\ Window MODULE extrawindow.cpp extensionimpl.cpp)
add_library(Google\ Translate MODULE googletranslate.cpp translatewrapper.cpp network.cpp extensionimpl.cpp)
add_library(Google\ Cloud\ Translate MODULE googlecloudtranslate.cpp translatewrapper.cpp network.cpp extensionimpl.cpp)
add_library(Lua MODULE lua.cpp extensionimpl.cpp)
add_library(Regex\ Filter MODULE regexfilter.cpp extensionimpl.cpp)
add_library(Remove\ Repeated\ Characters MODULE removerepeatchar.cpp extensionimpl.cpp)
@ -21,6 +22,7 @@ add_library(Thread\ Linker MODULE threadlinker.cpp extensionimpl.cpp)
target_link_libraries(Bing\ Translate winhttp Qt5::Widgets)
target_link_libraries(Extra\ Window Qt5::Widgets)
target_link_libraries(Google\ Translate winhttp Qt5::Widgets)
target_link_libraries(Google\ Cloud\ Translate winhttp Qt5::Widgets)
target_link_libraries(Lua lua53 Qt5::Widgets)
target_link_libraries(Regex\ Filter Qt5::Widgets)
target_link_libraries(Thread\ Linker Qt5::Widgets)

View File

@ -6,54 +6,79 @@ extern const wchar_t* TRANSLATION_ERROR;
extern Synchronized<std::wstring> translateTo;
const char* TRANSLATION_PROVIDER = "Bing";
const char* TRANSLATION_PROVIDER = "Bing Translate";
QStringList languages
{
"Afrikaans: af",
"Arabic: ar",
"Bosnian: bs-Latn",
"Bangla: bn",
"Bosnian: bs",
"Bulgarian: bg",
"Cantonese (Traditional): yue",
"Catalan: ca",
"Chinese(Simplified): zh-CHS",
"Chinese(Traditional): zh-CHT",
"Chinese (Simplified): zh-Hans",
"Chinese (Traditional): zh-Hant",
"Croatian: hr",
"Czech: cs",
"Danish: da",
"Dutch: nl",
"English: en",
"Estonian: et",
"Fijian: fj",
"Filipino: fil",
"Finnish: fi",
"French: fr",
"German: de",
"Greek: el",
"Haitian Creole: ht",
"Hebrew: he",
"Hindi: hi",
"Hmong Daw: mww",
"Hungarian: hu",
"Icelandic: is",
"Indonesian: id",
"Irish: ga",
"Italian: it",
"Japanese: ja",
"Klingon: tlh",
"Kannada: kn",
"Klingon (Latin): tlh-Latn",
"Klingon (pIqaD): tlh-Piqd",
"Korean: ko",
"Latvian: lv",
"Lithuanian: lt",
"Malagasy: mg",
"Malay: ms",
"Malayalam: ml",
"Maltese: mt",
"Norwegian: no",
"Maori: mi",
"Norwegian: nb",
"Persian: fa",
"Polish: pl",
"Portuguese: pt",
"Portuguese (Brazil): pt",
"Portuguese (Portugal): pt-pt",
"Punjabi: pa",
"Querétaro Otomi: otq",
"Romanian: ro",
"Russian: ru",
"Serbian: sr-Cyrl",
"Samoan: sm",
"Serbian (Cyrillic): sr-Cyrl",
"Serbian (Latin): sr-Latn",
"Slovak: sk",
"Slovenian: sl",
"Spanish: es",
"Swahili: sw",
"Swedish: sv",
"Tahitian: ty",
"Tamil: ta",
"Telugu: te",
"Thai: th",
"Tongan: to",
"Turkish: tr",
"Ukranian: uk",
"Ukrainian: uk",
"Urdu: ur",
"Vietnamese: vi",
"Welsh: cy"
"Welsh: cy",
"Yucatec Maya: yua"
};
std::pair<bool, std::wstring> Translate(const std::wstring& text)
@ -65,7 +90,7 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
FormatString(L"/ttranslatev3?fromLang=auto-detect&to=%s&text=%s", translateTo->c_str(), Escape(text)).c_str()
})
// Response formatted as JSON: translation starts with text":" and ends with ","to
if (std::wsmatch results; std::regex_search(httpRequest.response, results, std::wregex(L"text\":\"(.+)\"\\,\"to"))) return { true, results[1] };
if (std::wsmatch results; std::regex_search(httpRequest.response, results, std::wregex(L"text\":\"(.+)\",\"t"))) return { true, results[1] };
else return { false, TRANSLATION_ERROR };
else return { false, FormatString(L"%s (code=%u)", TRANSLATION_ERROR, httpRequest.errorCode) };
}

View File

@ -7,8 +7,8 @@ template <typename C, int delimiterCount, int blockSize = 0x1000 / sizeof(C)> //
class BlockMarkupIterator
{
public:
BlockMarkupIterator(const std::istream& it, const std::basic_string_view<C>(&delimiters)[delimiterCount]) :
streambuf(*it.rdbuf())
BlockMarkupIterator(const std::istream& stream, const std::basic_string_view<C>(&delimiters)[delimiterCount]) :
streambuf(*stream.rdbuf())
{
std::copy_n(delimiters, delimiterCount, this->delimiters.begin());
}

View File

@ -444,7 +444,7 @@ private:
QStringList currentInflectionsUsed = inflectionsUsed;
currentInflectionsUsed.push_front(inflection.name);
QString root = inflection.root;
for (int i = 0; i < root.size(); ++i) if (root[i].isDigit()) root.replace(i, 1, match.captured(root[i].unicode() - '0'));
for (int i = 0; i < root.size(); ++i) if (root[i].isDigit()) root.replace(i, 1, match.captured(root[i].digitValue()));
for (const auto& definition : LookupDefinitions(root, foundDefinitions, currentInflectionsUsed)) results.push_back(definition);
}
return results;

View File

@ -0,0 +1,119 @@
#include "qtcommon.h"
#include "extension.h"
#include "network.h"
extern const wchar_t* TRANSLATION_ERROR;
extern const char* API_KEY;
extern QFormLayout* display;
extern QSettings* settings;
extern Synchronized<std::wstring> translateTo;
const char* TRANSLATION_PROVIDER = "Google Cloud Translate";
QStringList languages
{
"Afrikaans: af",
"Arabic: ar",
"Albanian: sq",
"Belarusian: be",
"Bengali: bn",
"Bosnian: bs",
"Bulgarian: bg",
"Catalan: ca",
"Chinese(Simplified): zh-CH",
"Chinese(Traditional): zh-TW",
"Croatian: hr",
"Czech: cs",
"Danish: da",
"Dutch: nl",
"English: en",
"Esperanto: eo",
"Estonian: et",
"Filipino: tl",
"Finnish: fi",
"French: fr",
"Galician: gl",
"German: de",
"Greek: el",
"Hebrew: iw",
"Hindi: hi",
"Hungarian: hu",
"Icelandic: is",
"Indonesian: id",
"Irish: ga",
"Italian: it",
"Japanese: ja",
"Klingon: tlh",
"Korean: ko",
"Latin: la",
"Latvian: lv",
"Lithuanian: lt",
"Macedonian: mk",
"Malay: ms",
"Maltese: mt",
"Norwegian: no",
"Persian: fa",
"Polish: pl",
"Portuguese: pt",
"Romanian: ro",
"Russian: ru",
"Serbian: sr",
"Slovak: sk",
"Slovenian: sl",
"Somali: so",
"Spanish: es",
"Swahili: sw",
"Swedish: sv",
"Thai: th",
"Turkish: tr",
"Ukranian: uk",
"Urdu: ur",
"Vietnamese: vi",
"Welsh: cy",
"Yiddish: yi",
"Zulu: zu"
};
Synchronized<std::wstring> key;
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
auto keyInput = new QLineEdit(settings->value(API_KEY).toString());
key->assign(S(keyInput->text()));
QObject::connect(keyInput, &QLineEdit::textChanged, [](QString key) { settings->setValue(API_KEY, S(::key->assign(S(key)))); });
display->addRow(API_KEY, keyInput);
auto googleCloudInfo = new QLabel(
"<a href=\"https://codelabs.developers.google.com/codelabs/cloud-translation-intro\">https://codelabs.developers.google.com/codelabs/cloud-translation-intro</a>"
);
googleCloudInfo->setOpenExternalLinks(true);
display->addRow(googleCloudInfo);
}
break;
case DLL_PROCESS_DETACH:
{
}
break;
}
return TRUE;
}
std::pair<bool, std::wstring> Translate(const std::wstring& text)
{
if (HttpRequest httpRequest{
L"Mozilla/5.0 Textractor",
L"translation.googleapis.com",
L"GET",
FormatString(L"/language/translate/v2?format=text&q=%s&target=%s&key=%s", Escape(text), translateTo->c_str(), key->c_str()).c_str()
})
{
// Response formatted as JSON: starts with "translatedText": " and translation is enclosed in quotes followed by a comma
if (std::wsmatch results; std::regex_search(httpRequest.response, results, std::wregex(L"\"translatedText\": \"(.+?)\","))) return { true, results[1] };
return { false, TRANSLATION_ERROR };
}
else return { false, FormatString(L"%s (code=%u)", TRANSLATION_ERROR, httpRequest.errorCode) };
}

View File

@ -7,19 +7,26 @@ extern const wchar_t* TRANSLATION_ERROR;
extern Synchronized<std::wstring> translateTo;
const char* TRANSLATION_PROVIDER = "Google";
const char* TRANSLATION_PROVIDER = "Google Translate";
QStringList languages
{
"Afrikaans: af",
"Arabic: ar",
"Albanian: sq",
"Amharic: am",
"Arabic: ar",
"Armenian: hy",
"Azerbaijani: az",
"Basque: eu",
"Belarusian: be",
"Bengali: bn",
"Bosnian: bs",
"Bulgarian: bg",
"Catalan: ca",
"Chinese(Simplified): zh-CH",
"Chinese(Traditional): zh-TW",
"Cebuano: ceb",
"Chichewa: ny",
"Chinese (Simplified): zh",
"Chinese (Traditional): zh-TW",
"Corsican: co",
"Croatian: hr",
"Czech: cs",
"Danish: da",
@ -30,45 +37,87 @@ QStringList languages
"Filipino: tl",
"Finnish: fi",
"French: fr",
"Frisian: fy",
"Galician: gl",
"Georgian: ka",
"German: de",
"Greek: el",
"Gujarati: gu",
"Haitian Creole: ht",
"Hausa: ha",
"Hawaiian: haw",
"Hebrew: iw",
"Hindi: hi",
"Hmong: hmn",
"Hungarian: hu",
"Icelandic: is",
"Igbo: ig",
"Indonesian: id",
"Irish: ga",
"Italian: it",
"Japanese: ja",
"Klingon: tlh",
"Javanese: jw",
"Kannada: kn",
"Kazakh: kk",
"Khmer: km",
"Kinyarwanda: rw",
"Korean: ko",
"Kurdish (Kurmanji): ku",
"Kyrgyz: ky",
"Lao: lo",
"Latin: la",
"Latvian: lv",
"Lithuanian: lt",
"Luxembourgish: lb",
"Macedonian: mk",
"Malagasy: mg",
"Malay: ms",
"Malayalam: ml",
"Maltese: mt",
"Maori: mi",
"Marathi: mr",
"Mongolian: mn",
"Myanmar (Burmese): my",
"Nepali: ne",
"Norwegian: no",
"Odia (Oriya): or",
"Pashto: ps",
"Persian: fa",
"Polish: pl",
"Portuguese: pt",
"Punjabi: pa",
"Romanian: ro",
"Russian: ru",
"Samoan: sm",
"Scots Gaelic: gd",
"Serbian: sr",
"Sesotho: st",
"Shona: sn",
"Sindhi: sd",
"Sinhala: si",
"Slovak: sk",
"Slovenian: sl",
"Somali: so",
"Spanish: es",
"Sundanese: su",
"Swahili: sw",
"Swedish: sv",
"Tajik: tg",
"Tamil: ta",
"Tatar: tt",
"Telugu: te",
"Thai: th",
"Turkish: tr",
"Ukranian: uk",
"Turkmen: tk",
"Ukrainian: uk",
"Urdu: ur",
"Uyghur: ug",
"Uzbek: uz",
"Vietnamese: vi",
"Welsh: cy",
"Xhosa: xh",
"Yiddish: yi",
"Yoruba: yo",
"Zulu: zu"
};

View File

@ -41,10 +41,11 @@ bool logErrors = true;
Synchronized<std::string> script;
std::atomic<int> revCount = 0;
class Window : public QMainWindow
class Window : public QDialog
{
public:
Window()
: QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
{
connect(&loadButton, &QPushButton::clicked, this, &Window::LoadScript);
@ -53,7 +54,6 @@ public:
layout.addWidget(&loadButton);
resize(800, 600);
setCentralWidget(&centralWidget);
setWindowTitle("Lua");
QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection);
}
@ -76,10 +76,9 @@ private:
QTextFile(LUA_SAVE_FILE, QIODevice::WriteOnly | QIODevice::Truncate).write(scriptEditor.toPlainText().toUtf8());
}
QWidget centralWidget{ this };
QHBoxLayout layout{ &centralWidget };
QPlainTextEdit scriptEditor{ QTextFile(LUA_SAVE_FILE, QIODevice::ReadOnly).readAll(), &centralWidget };
QPushButton loadButton{ LOAD_LUA_SCRIPT, &centralWidget };
QHBoxLayout layout{ this };
QPlainTextEdit scriptEditor{ QTextFile(LUA_SAVE_FILE, QIODevice::ReadOnly).readAll(), this };
QPushButton loadButton{ LOAD_LUA_SCRIPT, this };
} window;
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)

View File

@ -56,11 +56,12 @@ void Unescape(std::wstring& text)
{
if (text[i] == L'\\')
{
text[i] = 0x200b;
if (text[i + 1] == L'r') text[i + 1] = 0x200b; // for some reason \r gets displayed as a newline
text[i] = 0;
if (text[i + 1] == L'r') text[i + 1] = 0; // for some reason \r gets displayed as a newline
if (text[i + 1] == L'n') text[i + 1] = L'\n';
if (text[i + 1] == L't') text[i + 1] = L'\t';
if (text[i + 1] == L'\\') ++i;
}
}
text.erase(std::remove(text.begin(), text.end(), 0), text.end());
}

View File

@ -15,10 +15,11 @@ std::optional<std::wregex> regex;
std::shared_mutex m;
DWORD (*GetSelectedProcessId)() = nullptr;
class Window : public QMainWindow
class Window : public QDialog
{
public:
Window()
: QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
{
ui.setupUi(this);

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FilterWindow</class>
<widget class="QMainWindow" name="FilterWindow">
<widget class="QDialog">
<property name="geometry">
<rect>
<x>0</x>
@ -10,49 +10,47 @@
<height>105</height>
</rect>
</property>
<widget class="QWidget">
<layout class="QVBoxLayout">
<item>
<widget class="QLineEdit" name="input"/>
</item>
<item>
<widget class="QLabel" name="output">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="save">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel">
<property name="text">
<string>&lt;a href=&quot;https://regexr.com&quot;&gt;regexr.com&lt;/a&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
</layout>
</widget>
<layout class="QVBoxLayout">
<item>
<widget class="QLineEdit" name="input"/>
</item>
<item>
<widget class="QLabel" name="output">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="save">
<property name="text">
<string>Save</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel">
<property name="text">
<string>&lt;a href=&quot;https://regexr.com&quot;&gt;regexr.com&lt;/a&gt;</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>

View File

@ -11,17 +11,17 @@ extern const char* HEXADECIMAL;
std::unordered_map<int64_t, std::unordered_multiset<int64_t>> linkedTextHandles;
std::shared_mutex m;
class Window : public QMainWindow
class Window : public QDialog
{
public:
Window()
: QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
{
connect(&linkButton, &QPushButton::clicked, this, &Window::Link);
layout.addWidget(&linkList);
layout.addWidget(&linkButton);
setCentralWidget(&centralWidget);
setWindowTitle(THREAD_LINKER);
QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection);
}
@ -51,10 +51,9 @@ private:
}
}
QWidget centralWidget{ this };
QHBoxLayout layout{ &centralWidget };
QListWidget linkList{ &centralWidget };
QPushButton linkButton{ LINK, &centralWidget };
QHBoxLayout layout{ this };
QListWidget linkList{ this };
QPushButton linkButton{ LINK, this };
} window;
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)

View File

@ -4,12 +4,11 @@
#include "network.h"
#include <map>
#include <fstream>
#include <QComboBox>
#include <QTimer>
extern const char* NATIVE_LANGUAGE;
extern const char* SELECT_LANGUAGE;
extern const char* SELECT_LANGUAGE_MESSAGE;
extern const char* LANGUAGE_SAVED;
extern const char* TRANSLATE_TO;
extern const wchar_t* TOO_MANY_TRANS_REQUESTS;
extern const char* TRANSLATION_PROVIDER;
@ -17,8 +16,10 @@ extern QStringList languages;
std::pair<bool, std::wstring> Translate(const std::wstring& text);
const char* LANGUAGE = u8"Language";
const std::string TRANSLATION_CACHE_FILE = FormatString("%sCache.txt", TRANSLATION_PROVIDER);
const std::string TRANSLATION_CACHE_FILE = FormatString("%s Cache.txt", TRANSLATION_PROVIDER);
QFormLayout* display;
QSettings* settings;
Synchronized<std::wstring> translateTo = L"en";
Synchronized<std::map<std::wstring, std::wstring>> translationCache;
@ -33,31 +34,30 @@ void SaveCache()
savedSize = translationCache->size();
}
BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
class Window : public QDialog
{
switch (ul_reason_for_call)
public:
Window() :
QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
{
case DLL_PROCESS_ATTACH:
{
static QSettings settings = openSettings();
display = &layout;
::settings = &settings;
languageBox.addItems(languages);
settings.beginGroup(TRANSLATION_PROVIDER);
if (settings.contains(LANGUAGE)) translateTo->assign(S(settings.value(LANGUAGE).toString()));
else QTimer::singleShot(0, []
{
QString language = QInputDialog::getItem(
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(),
false,
nullptr,
Qt::WindowCloseButtonHint
);
translateTo->assign(S(language.split(": ")[1]));
settings.setValue(LANGUAGE, S(translateTo->c_str()));
QMessageBox::information(nullptr, SELECT_LANGUAGE, QString(LANGUAGE_SAVED).arg(CONFIG_FILE));
});
int language = -1;
if (settings.contains(LANGUAGE)) language = languageBox.findText(settings.value(LANGUAGE).toString(), Qt::MatchEndsWith);
if (language < 0) language = languageBox.findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
if (language < 0) language = languageBox.findText("English", Qt::MatchStartsWith);
languageBox.setCurrentIndex(language);
saveLanguage(languageBox.currentText());
connect(&languageBox, &QComboBox::currentTextChanged, this, &Window::saveLanguage);
layout.addRow(TRANSLATE_TO, &languageBox);
setWindowTitle(TRANSLATION_PROVIDER);
QMetaObject::invokeMethod(this, &QWidget::show, Qt::QueuedConnection);
std::ifstream stream(TRANSLATION_CACHE_FILE, std::ios::binary);
BlockMarkupIterator savedTranslations(stream, Array<std::wstring_view>{ L"|SENTENCE|", L"|TRANSLATION|" });
@ -69,15 +69,22 @@ BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved
}
savedSize = translationCache->size();
}
break;
case DLL_PROCESS_DETACH:
~Window()
{
SaveCache();
}
break;
private:
void saveLanguage(QString language)
{
settings.setValue(LANGUAGE, S(translateTo->assign(S(language.split(": ")[1]))));
}
return TRUE;
}
QFormLayout layout{ this };
QComboBox languageBox{ this };
QSettings settings{ openSettings(this) };
} window;
bool ProcessSentence(std::wstring& sentence, SentenceInfo sentenceInfo)
{

View File

@ -4,6 +4,18 @@
#define ARCH "x86"
#endif
#if 0
#define TURKISH
#define SPANISH
#define SIMPLIFIED_CHINESE
#define RUSSIAN
#define INDONESIAN
#define ITALIAN
#define THAI
#define PORTUGUESE
#define KOREAN
#endif
const char* NATIVE_LANGUAGE = "English";
const char* ATTACH = u8"Attach to game";
const char* LAUNCH = u8"Launch game";
@ -117,11 +129,10 @@ const char* SEND_ERROR = u8"Textractor: Send ERROR (likely an unstable/incorrect
const char* READ_ERROR = u8"Textractor: Reader ERROR (likely an incorrect R-code)";
const char* HIJACK_ERROR = u8"Textractor: Hijack ERROR";
const char* COULD_NOT_FIND = u8"Textractor: could not find text";
const char* SELECT_LANGUAGE = u8"Select language";
const char* SELECT_LANGUAGE_MESSAGE = u8"What language should %1 translate to?";
const char* LANGUAGE_SAVED = u8"Translation language saved (you can delete it in the config file %1 then reopen Textractor to reselect)";
const char* TRANSLATE_TO = u8"Translate to";
const wchar_t* TOO_MANY_TRANS_REQUESTS = L"Too many translation requests: refuse to make more";
const wchar_t* TRANSLATION_ERROR = L"Error while translating";
const char* API_KEY = u8"API key";
const char* EXTRA_WINDOW_INFO = u8R"(Right click to change settings
Click and drag on window edges to move, or the bottom right corner to resize)";
const char* SENTENCE_TOO_BIG = u8"Sentence too large to display";
@ -278,8 +289,6 @@ Código fuente disponible bajo GPLv3 en la página del proyecto)";
READ_ERROR = u8"Textractor: Reader ERROR (probablemente un R-code incorrecto)";
HIJACK_ERROR = u8"Textractor: Hijack ERROR";
COULD_NOT_FIND = u8"Textractor: no se puede encontrar texto";
SELECT_LANGUAGE = u8"Seleccionar lenguaje";
SELECT_LANGUAGE_MESSAGE = u8"¿A qué idioma debe traducir %1?";
TOO_MANY_TRANS_REQUESTS = L"Demasiadas peticiones de traducción: no se puede hacer más";
TRANSLATION_ERROR = L"Error al traducir";
EXTRA_WINDOW_INFO = u8R"(Clic derecho para configurar
@ -293,7 +302,7 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
#endif // SPANISH
#ifdef SIMPLIFIED_CHINESE
NATIVE_LANGUAGE = "Chinese(Simplified)";
NATIVE_LANGUAGE = "Chinese (Simplified)";
ATTACH = u8"附加到游戏";
LAUNCH = u8"启动游戏";
DETACH = u8"从游戏分离";
@ -343,8 +352,6 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
READ_ERROR = u8"Textractor: Reader 错误 (R码可能不正确)";
HIJACK_ERROR = u8"Textractor: Hijack 错误";
COULD_NOT_FIND = u8"Textractor: 无法找到文本";
SELECT_LANGUAGE = u8"选择语言";
SELECT_LANGUAGE_MESSAGE = u8"想要使用 %1 翻译到哪种语言?";
TOO_MANY_TRANS_REQUESTS = L"太多翻译请求: 拒绝生成更多";
TRANSLATION_ERROR = L"翻译时出错";
EXTRA_WINDOW_INFO = u8R"(右键修改设置
@ -438,8 +445,6 @@ Clic y arrastra los bordes de la ventana para moverla, o en la esquina inferior
READ_ERROR = u8"Textractor: Reader ERROR (вероятно неверный R-code)";
HIJACK_ERROR = u8"Textractor: Hijack ERROR";
COULD_NOT_FIND = u8"Textractor: невозможно найти текст";
SELECT_LANGUAGE = u8"Выберете язык";
SELECT_LANGUAGE_MESSAGE = u8"На какой язык переводить в %1?";
TOO_MANY_TRANS_REQUESTS = L"Слишком много запросов для перевода: отклонено";
TRANSLATION_ERROR = L"Ошибка при переводе";
EXTRA_WINDOW_INFO = u8R"(Правый клик для изменения настроек
@ -540,8 +545,6 @@ Jika kamu menyukai project ini, tolong sebarluaskan project ini :))";
READ_ERROR = u8"Textractor: Reader ERROR (Kemungkinan R-Code salah)";
HIJACK_ERROR = u8"Textractor: Hijack ERROR";
COULD_NOT_FIND = u8"Textractor: tidak dapat menemukan teks";
SELECT_LANGUAGE = u8"Pilih bahasa";
SELECT_LANGUAGE_MESSAGE = u8"Bahasa apakah yang %1 harus terjemahkan?";
TOO_MANY_TRANS_REQUESTS = L"Terlalu banyak permintaan terjemahan: menolak untuk menerjemahkan";
TRANSLATION_ERROR = L"Terjadi kesalahan ketika menerjemahkan";
EXTRA_WINDOW_INFO = u8R"(Klik kanan untuk merubah pengaturan
@ -646,8 +649,6 @@ esempio: Textractor -p4466 -p"My Game.exe" sta tentando di inniettare i processi
READ_ERROR = u8"Textractor: Reader ERROR (probabilmente un R-code incorretto)";
HIJACK_ERROR = u8"Textractor: Hijack ERROR";
COULD_NOT_FIND = u8"Textractor: impossibile trovare il testo";
SELECT_LANGUAGE = u8"Seleziona lingua";
SELECT_LANGUAGE_MESSAGE = u8"In quale lingua dovrei %1 tradurlo?";
TOO_MANY_TRANS_REQUESTS = L"Troppe richieste di traduzione: rifiuta per farne altre";
TRANSLATION_ERROR = L"Errore durante la traduzione";
EXTRA_WINDOW_INFO = u8R"(Tasto destro per cambiare le impostazioni
@ -762,8 +763,6 @@ Se você gostou desse projeto, divulgue a todos :))";
SEND_ERROR = u8"Textractor: ERRO no envio (provavelmente um H-code incorreto)";
READ_ERROR = u8"Textractor: ERRO na leitura (provavelmente um R-code incorreto)";
COULD_NOT_FIND = u8"Textractor: não foi possível encontrar texto";
SELECT_LANGUAGE = u8"Selecione a lingua";
SELECT_LANGUAGE_MESSAGE = u8"Qual lingua deve o/a %1 traduzir para?";
TOO_MANY_TRANS_REQUESTS = L"Foram feitos pedidos de tradução demais: recusa na feitura de mais pedidos";
TRANSLATION_ERROR = L"Erro enquanto traduzindo";
EXTRA_WINDOW_INFO = u8R"(Clique com o botão direito para mudar as opções
@ -839,8 +838,6 @@ Source code สามารถหาได้จากส่วนของ GPLv
READ_ERROR = u8"Textractor: Reader ERROR (คาดว่าเป็นความผิดพลาดของ R-Code)";
HIJACK_ERROR = u8"Textractor: Hijack ERROR";
COULD_NOT_FIND = u8"Textractor: ไม่สามารถหาข้อมูลตัวอักษรได้";
SELECT_LANGUAGE = u8"เลือกภาษา";
SELECT_LANGUAGE_MESSAGE = u8"ภาษาใดที่ %1 ควรจะแปลให้เป็น?";
TOO_MANY_TRANS_REQUESTS = L"มีการเรียกขอมากเกินกำหนด : ปฏิเสธที่จะทำการขอคำแปลต่อ";
TRANSLATION_ERROR = L"เกิดข้อผิดพลาดระหว่างการแปลภาษา";
EXTRA_WINDOW_INFO = u8R"(คลิกขวาเพื่อที่จะตั่งค่า
@ -906,8 +903,6 @@ Source code สามารถหาได้จากส่วนของ GPLv
LAUNCH_FAILED = L"Textractor: 실행할 수 없습니다";
INVALID_CODE = L"Textractor: 유효하지 않은 코드";
INVALID_CODEPAGE = L"Textractor: 텍스트를 변환할 수 없습니다 (유효하지 않은 코드페이지?)";
SELECT_LANGUAGE = u8"언어 선택";
SELECT_LANGUAGE_MESSAGE = u8"어떤 언어로 %1 번역하시겠습니까?";
TOO_MANY_TRANS_REQUESTS = L"너무 많은 번역요청: 요청 거부됨";
TRANSLATION_ERROR = L"번역 에러";
EXTRA_WINDOW_INFO = u8R"(오른쪽 클릭으로 설정변경