diff --git a/GUI/main.cpp b/GUI/main.cpp
index 81c08cc..3d26945 100644
--- a/GUI/main.cpp
+++ b/GUI/main.cpp
@@ -1,7 +1,6 @@
 #include "mainwindow.h"
 #include "module.h"
 #include <winhttp.h>
-#include <QApplication>
 
 extern const wchar_t* UPDATE_AVAILABLE;
 
diff --git a/extensions/bingtranslate.cpp b/extensions/bingtranslate.cpp
index 18e0e24..b91474b 100644
--- a/extensions/bingtranslate.cpp
+++ b/extensions/bingtranslate.cpp
@@ -1,9 +1,9 @@
-#include "network.h"
-#include <QStringList>
+#include "qtcommon.h"
+#include "network.h"
 
 extern const wchar_t* TRANSLATION_ERROR;
 
-extern Synchronized<std::wstring> translateTo, authKey;
+extern Synchronized<std::wstring> translateTo, translateFrom, authKey;
 
 const char* TRANSLATION_PROVIDER = "Bing Translate";
 const char* GET_API_KEY_FROM = "https://www.microsoft.com/en-us/translator/business/trial/#get-started";
@@ -78,6 +78,7 @@ QStringList languages
 	"Welsh: cy",
 	"Yucatec Maya: yua"
 };
+std::wstring autoDetectLanguage = L"auto-detect";
 
 bool translateSelectedOnly = false, rateLimitAll = true, rateLimitSelected = false, useCache = true;
 int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
@@ -85,23 +86,26 @@ int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
 std::pair<bool, std::wstring> Translate(const std::wstring& text)
 {
 	if (!authKey->empty())
+	{
+		std::wstring translateFromComponent = translateFrom.Copy() == autoDetectLanguage ? L"" : L"&from=" + translateFrom.Copy();
 		if (HttpRequest httpRequest{
 			L"Mozilla/5.0 Textractor",
 			L"api.cognitive.microsofttranslator.com",
 			L"POST",
-			FormatString(L"/translate?api-version=3.0&to=%s", translateTo.Copy()).c_str(),
+			FormatString(L"/translate?api-version=3.0&to=%s%s", translateTo.Copy(), translateFromComponent).c_str(),
 			FormatString(R"([{"text":"%s"}])", JSON::Escape(WideStringToString(text))),
 			FormatString(L"Content-Type: application/json; charset=UTF-8\r\nOcp-Apim-Subscription-Key:%s", authKey.Copy()).c_str()
 		})
 			if (auto translation = Copy(JSON::Parse(httpRequest.response)[0][L"translations"][0][L"text"].String())) return { true, translation.value() };
 			else return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, httpRequest.response) };
 		else return { false, FormatString(L"%s (code=%u)", TRANSLATION_ERROR, httpRequest.errorCode) };
+	}
 
 	if (HttpRequest httpRequest{
 		L"Mozilla/5.0 Textractor",
 		L"www.bing.com",
 		L"POST",
-		FormatString(L"/ttranslatev3?fromLang=auto-detect&to=%s&text=%s", translateTo.Copy(), Escape(text)).c_str()
+		FormatString(L"/ttranslatev3?fromLang=%s&to=%s&text=%s", translateFrom.Copy(), translateTo.Copy(), Escape(text)).c_str()
 	})
 		if (auto translation = Copy(JSON::Parse(httpRequest.response)[0][L"translations"][0][L"text"].String())) return { true, translation.value() };
 		else return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, httpRequest.response) };
diff --git a/extensions/deepltranslate.cpp b/extensions/deepltranslate.cpp
index 846bf2c..63dfed3 100644
--- a/extensions/deepltranslate.cpp
+++ b/extensions/deepltranslate.cpp
@@ -5,7 +5,7 @@
 extern const wchar_t* TRANSLATION_ERROR;
 extern const char* USE_PREV_SENTENCE_CONTEXT;
 
-extern Synchronized<std::wstring> translateTo, authKey;
+extern Synchronized<std::wstring> translateTo, translateFrom, authKey;
 
 const char* TRANSLATION_PROVIDER = "DeepL Translate";
 const char* GET_API_KEY_FROM = "https://www.deepl.com/pro.html";
@@ -23,6 +23,7 @@ QStringList languages
 	"Russian: RU",
 	"Spanish: ES",
 };
+std::wstring autoDetectLanguage = L"auto";
 
 bool translateSelectedOnly = true, rateLimitAll = true, rateLimitSelected = true, useCache = true;
 int tokenCount = 10, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
@@ -33,25 +34,28 @@ int keyType = CAT;
 std::pair<bool, std::wstring> Translate(const std::wstring& text)
 {
 	if (!authKey->empty())
+	{
+		std::string translateFromComponent = translateFrom.Copy() == autoDetectLanguage ? "" : "&source_lang=" + WideStringToString(translateFrom.Copy());
 		if (HttpRequest httpRequest{
 			L"Mozilla/5.0 Textractor",
 			L"api.deepl.com",
 			L"POST",
 			keyType == CAT ? L"/v1/translate" : L"/v2/translate",
-			FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()),
+			FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()) + translateFromComponent,
 			L"Content-Type: application/x-www-form-urlencoded"
 		}; httpRequest && (!httpRequest.response.empty() || (httpRequest = HttpRequest{
 			L"Mozilla/5.0 Textractor",
 			L"api.deepl.com",
 			L"POST",
 			(keyType = !keyType) == CAT ? L"/v1/translate" : L"/v2/translate",
-			FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()),
+			FormatString("text=%S&auth_key=%S&target_lang=%S", Escape(text), authKey.Copy(), translateTo.Copy()) + translateFromComponent,
 			L"Content-Type: application/x-www-form-urlencoded"
 		})))
 			// Response formatted as JSON: translation starts with text":" and ends with "}]
 			if (auto translation = Copy(JSON::Parse(httpRequest.response)[L"translations"][0][L"text"].String())) return { true, translation.value() };
 			else return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, httpRequest.response) };
 		else return { false, FormatString(L"%s (code=%u)", TRANSLATION_ERROR, httpRequest.errorCode) };
+	}
 
 	// the following code was reverse engineered from the DeepL website; it's as close as I could make it but I'm not sure what parts of this could be removed and still have it work
 	int64_t r = _time64(nullptr), n = std::count(text.begin(), text.end(), L'i') + 1;
@@ -68,7 +72,7 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
 		"timestamp": %lld,
 		"lang": {
 			"target_lang": "%S",
-			"source_lang_user_selected": "auto"
+			"source_lang_user_selected": "%S"
 		},
 		"jobs": [{
 			"raw_en_sentence": "%s",
@@ -80,7 +84,7 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
 		}]
 	}
 }
-	)", id, r + (n - r % n), translateTo.Copy(), JSON::Escape(WideStringToString(text)));
+	)", id, r + (n - r % n), translateTo.Copy(), translateFrom.Copy(), JSON::Escape(WideStringToString(text)));
 	// missing accept-encoding header since it fucks up HttpRequest
 	if (HttpRequest httpRequest{
 		L"Mozilla/5.0 Textractor",
diff --git a/extensions/devtoolsdeepltranslate.cpp b/extensions/devtoolsdeepltranslate.cpp
index 8950d9a..affad8b 100644
--- a/extensions/devtoolsdeepltranslate.cpp
+++ b/extensions/devtoolsdeepltranslate.cpp
@@ -3,7 +3,7 @@
 #include <ShlObj.h>
 
 extern const wchar_t* TRANSLATION_ERROR;
-extern Synchronized<std::wstring> translateTo;
+extern Synchronized<std::wstring> translateTo, translateFrom;
 extern QFormLayout* display;
 extern Settings settings;
 
@@ -34,6 +34,7 @@ QStringList languages
 	"Russian: ru",
 	"Spanish: es",
 };
+std::wstring autoDetectLanguage = L"auto";
 
 BOOL WINAPI DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
 {
@@ -115,10 +116,16 @@ std::pair<bool, std::wstring> Translate(const std::wstring& text)
 	// DevTools can't handle concurrent translations yet
 	static std::mutex translationMutex;
 	std::scoped_lock lock(translationMutex);
-	DevTools::SendRequest(L"Page.navigate", FormatString(LR"({"url":"https://www.deepl.com/translator#any/%s/%s"})", translateTo.Copy(), Escape(text)));
+	DevTools::SendRequest(L"Page.navigate", FormatString(LR"({"url":"https://www.deepl.com/translator#%s/%s/%s"})", translateFrom.Copy(), translateTo.Copy(), Escape(text)));
 	for (int retry = 0; ++retry < 100; Sleep(100))
-		if (auto translation = Copy(DevTools::SendRequest(
-			L"Runtime.evaluate", LR"({"expression":"document.querySelector('#target-dummydiv').innerHTML","returnByValue":true})")[L"result"][L"value"].String())
-		) if (!translation->empty()) return { true, translation.value() };
+		if (auto translation = Copy(
+			DevTools::SendRequest(L"Runtime.evaluate", LR"({"expression":"document.querySelector('#target-dummydiv').innerHTML","returnByValue":true})")[L"result"][L"value"].String()
+		)) if (!translation->empty()) return { true, translation.value() };
+	if (auto errorMessage = Copy(
+		DevTools::SendRequest(
+			L"Runtime.evaluate",
+			LR"({"expression":"document.querySelector('div.lmt__system_notification').innerHTML","returnByValue":true})"
+		)[L"result"][L"value"].String()
+	)) return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, errorMessage.value()) };
 	return { false, TRANSLATION_ERROR };
-}
\ No newline at end of file
+}
diff --git a/extensions/extrawindow.cpp b/extensions/extrawindow.cpp
index 9801b27..92be065 100644
--- a/extensions/extrawindow.cpp
+++ b/extensions/extrawindow.cpp
@@ -42,11 +42,10 @@ QColor colorPrompt(QWidget* parent, QColor default, const QString& title, bool c
 	return color;
 }
 
-struct PrettyWindow : QDialog
+struct PrettyWindow : QDialog, Localizer
 {
 	PrettyWindow(const char* name)
 	{
-		Localize();
 		ui.setupUi(this);
 		ui.display->setGraphicsEffect(&outliner);
 		setWindowFlags(Qt::FramelessWindowHint);
@@ -159,7 +158,7 @@ public:
 		PrettyWindow("Extra Window")
 	{
 		ui.display->setTextFormat(Qt::PlainText);
-		if (settings.contains(WINDOW) && QGuiApplication::screenAt(settings.value(WINDOW).toRect().bottomRight())) setGeometry(settings.value(WINDOW).toRect());
+		if (settings.contains(WINDOW) && QApplication::screenAt(settings.value(WINDOW).toRect().bottomRight())) setGeometry(settings.value(WINDOW).toRect());
 		maxSentenceSize = settings.value(MAX_SENTENCE_SIZE, maxSentenceSize).toInt();
 
 		for (auto [name, default, slot] : Array<const char*, bool, void(ExtraWindow::*)(bool)>{
diff --git a/extensions/googletranslate.cpp b/extensions/googletranslate.cpp
index dfbb178..bf7f948 100644
--- a/extensions/googletranslate.cpp
+++ b/extensions/googletranslate.cpp
@@ -4,7 +4,7 @@
 
 extern const wchar_t* TRANSLATION_ERROR;
 
-extern Synchronized<std::wstring> translateTo, authKey;
+extern Synchronized<std::wstring> translateTo, translateFrom, authKey;
 
 const char* TRANSLATION_PROVIDER = "Google Translate";
 const char* GET_API_KEY_FROM = "https://codelabs.developers.google.com/codelabs/cloud-translation-intro";
@@ -120,6 +120,7 @@ QStringList languages
 	"Yoruba: yo",
 	"Zulu: zu"
 };
+std::wstring autoDetectLanguage = L"auto";
 
 bool translateSelectedOnly = false, rateLimitAll = true, rateLimitSelected = false, useCache = true;
 int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
@@ -127,23 +128,28 @@ int tokenCount = 30, tokenRestoreDelay = 60000, maxSentenceSize = 1000;
 std::pair<bool, std::wstring> Translate(const std::wstring& text)
 {
 	if (!authKey->empty())
+	{
+		std::wstring translateFromComponent = translateFrom.Copy() == autoDetectLanguage ? L"" : L"&source=" + translateFrom.Copy();
 		if (HttpRequest httpRequest{
 			L"Mozilla/5.0 Textractor",
 			L"translation.googleapis.com",
 			L"POST",
-			FormatString(L"/language/translate/v2?format=text&target=%s&key=%s", translateTo.Copy(), authKey.Copy()).c_str(),
+			FormatString(L"/language/translate/v2?format=text&target=%s&key=%s%s", translateTo.Copy(), authKey.Copy(), translateFromComponent).c_str(),
 			FormatString(R"({"q":["%s"]})", JSON::Escape(WideStringToString(text)))
 		})
 			if (auto translation = Copy(JSON::Parse(httpRequest.response)[L"data"][L"translations"][0][L"translatedText"].String())) return { true, translation.value() };
 			else return { false, FormatString(L"%s: %s", TRANSLATION_ERROR, httpRequest.response) };
 		else return { false, FormatString(L"%s (code=%u)", TRANSLATION_ERROR, httpRequest.errorCode) };
+	}
 
 	if (HttpRequest httpRequest{
 		L"Mozilla/5.0 Textractor",
 		L"translate.google.com",
 		L"POST",
 		L"/_/TranslateWebserverUi/data/batchexecute?rpcids=MkEWBc",
-		"f.req=" + Escape(WideStringToString(FormatString(LR"([[["MkEWBc","[[\"%s\",\"auto\",\"%s\",true],[null]]",null,"generic"]]])", JSON::Escape((JSON::Escape(text))), translateTo.Copy()))),
+		"f.req=" + Escape(WideStringToString(
+			FormatString(LR"([[["MkEWBc","[[\"%s\",\"%s\",\"%s\",true],[null]]",null,"generic"]]])", JSON::Escape((JSON::Escape(text))), translateFrom.Copy(), translateTo.Copy())
+		)),
 		L"Content-Type: application/x-www-form-urlencoded"
 	})
 	{
diff --git a/extensions/lua.cpp b/extensions/lua.cpp
index 0188896..5b102f3 100644
--- a/extensions/lua.cpp
+++ b/extensions/lua.cpp
@@ -41,13 +41,12 @@ bool logErrors = true;
 Synchronized<std::string> script;
 std::atomic<int> revCount = 0;
 
-class Window : public QDialog
+class Window : public QDialog, Localizer
 {
 public:
 	Window()
 		: QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
 	{
-		Localize();
 		connect(&loadButton, &QPushButton::clicked, this, &Window::LoadScript);
 
 		if (scriptEditor.toPlainText().isEmpty()) scriptEditor.setPlainText(LUA_INTRO);
diff --git a/extensions/regexfilter.cpp b/extensions/regexfilter.cpp
index f0d5c8b..56a174d 100644
--- a/extensions/regexfilter.cpp
+++ b/extensions/regexfilter.cpp
@@ -16,13 +16,12 @@ std::wstring replace;
 std::shared_mutex m;
 DWORD (*GetSelectedProcessId)() = nullptr;
 
-class Window : public QDialog
+class Window : public QDialog, Localizer
 {
 public:
 	Window()
 		: QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
 	{
-		Localize();
 		ui.setupUi(this);
 
 		connect(ui.regexEdit, &QLineEdit::textEdited, this, &Window::SetRegex);
diff --git a/extensions/styler.cpp b/extensions/styler.cpp
index 433024b..6b15e1d 100644
--- a/extensions/styler.cpp
+++ b/extensions/styler.cpp
@@ -1,20 +1,18 @@
 #include "qtcommon.h"
 #include "extension.h"
 #include <fstream>
-#include <QApplication>
 #include <QPlainTextEdit>
 
 extern const char* LOAD_SCRIPT;
 
 constexpr auto STYLE_SAVE_FILE = u8"Textractor.css";
 
-class Window : public QDialog
+class Window : public QDialog, Localizer
 {
 public:
 	Window()
 		: QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
 	{
-		Localize();
 		connect(&loadButton, &QPushButton::clicked, this, &Window::LoadScript);
 
 		if (scriptEditor.toPlainText().isEmpty()) scriptEditor.setPlainText("/*https://doc.qt.io/qt-5/stylesheet-syntax.html*/");
diff --git a/extensions/threadlinker.cpp b/extensions/threadlinker.cpp
index aa7b93b..0097171 100644
--- a/extensions/threadlinker.cpp
+++ b/extensions/threadlinker.cpp
@@ -11,13 +11,12 @@ extern const char* HEXADECIMAL;
 std::unordered_map<int64_t, std::unordered_multiset<int64_t>> linkedTextHandles;
 std::shared_mutex m;
 
-class Window : public QDialog
+class Window : public QDialog, Localizer
 {
 public:
 	Window()
 		: QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
 	{
-		Localize();
 		connect(&linkButton, &QPushButton::clicked, this, &Window::Link);
 
 		layout.addWidget(&linkList);
diff --git a/extensions/translatewrapper.cpp b/extensions/translatewrapper.cpp
index 1f97bc1..7d2d699 100644
--- a/extensions/translatewrapper.cpp
+++ b/extensions/translatewrapper.cpp
@@ -8,6 +8,7 @@
 
 extern const char* NATIVE_LANGUAGE;
 extern const char* TRANSLATE_TO;
+extern const char* TRANSLATE_FROM;
 extern const char* TRANSLATE_SELECTED_THREAD_ONLY;
 extern const char* RATE_LIMIT_ALL_THREADS;
 extern const char* RATE_LIMIT_SELECTED_THREAD;
@@ -21,16 +22,18 @@ extern const wchar_t* TOO_MANY_TRANS_REQUESTS;
 extern const char* TRANSLATION_PROVIDER;
 extern const char* GET_API_KEY_FROM;
 extern QStringList languages;
+extern std::wstring autoDetectLanguage;
 extern bool translateSelectedOnly, rateLimitAll, rateLimitSelected, useCache;
 extern int tokenCount, tokenRestoreDelay, maxSentenceSize;
 std::pair<bool, std::wstring> Translate(const std::wstring& text);
 
+// backwards compatibility
 const char* LANGUAGE = u8"Language";
 const std::string TRANSLATION_CACHE_FILE = FormatString("%s Translation Cache.txt", TRANSLATION_PROVIDER);
 
 QFormLayout* display;
 Settings settings;
-Synchronized<std::wstring> translateTo = L"en", authKey;
+Synchronized<std::wstring> translateTo = L"en", translateFrom = L"auto", authKey;
 
 namespace
 {
@@ -46,27 +49,38 @@ namespace
 	}
 }
 
-class Window : public QDialog
+class Window : public QDialog, Localizer
 {
 public:
 	Window() :
 		QDialog(nullptr, Qt::WindowMinMaxButtonsHint)
 	{
-		Localize();
 		display = new QFormLayout(this);
 
 		settings.beginGroup(TRANSLATION_PROVIDER);
 
-		auto languageCombo = new QComboBox(this);
-		languageCombo->addItems(languages);
+		auto translateToCombo = new QComboBox(this);
+		translateToCombo->addItems(languages);
 		int language = -1;
-		if (settings.contains(LANGUAGE)) language = languageCombo->findText(settings.value(LANGUAGE).toString(), Qt::MatchEndsWith);
-		if (language < 0) language = languageCombo->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
-		if (language < 0) language = languageCombo->findText("English", Qt::MatchStartsWith);
-		languageCombo->setCurrentIndex(language);
-		saveLanguage(languageCombo->currentText());
-		display->addRow(TRANSLATE_TO, languageCombo);
-		connect(languageCombo, &QComboBox::currentTextChanged, this, &Window::saveLanguage);
+		if (settings.contains(LANGUAGE)) language = translateToCombo->findText(settings.value(LANGUAGE).toString(), Qt::MatchEndsWith);
+		if (settings.contains(TRANSLATE_TO)) language = translateToCombo->findText(settings.value(TRANSLATE_TO).toString(), Qt::MatchEndsWith);
+		if (language < 0) language = translateToCombo->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
+		if (language < 0) language = translateToCombo->findText("English", Qt::MatchStartsWith);
+		translateToCombo->setCurrentIndex(language);
+		SaveTranslateTo(translateToCombo->currentText());
+		display->addRow(TRANSLATE_TO, translateToCombo);
+		connect(translateToCombo, &QComboBox::currentTextChanged, this, &Window::SaveTranslateTo);
+		languages.push_front("?: " + S(autoDetectLanguage));
+		auto translateFromCombo = new QComboBox(this);
+		translateFromCombo->addItems(languages);
+		language = -1;
+		if (settings.contains(TRANSLATE_FROM)) language = translateFromCombo->findText(settings.value(TRANSLATE_FROM).toString(), Qt::MatchEndsWith);
+		if (language < 0) language = translateFromCombo->findText(NATIVE_LANGUAGE, Qt::MatchStartsWith);
+		if (language < 0) language = translateFromCombo->findText("?", Qt::MatchStartsWith);
+		translateFromCombo->setCurrentIndex(language);
+		SaveTranslateFrom(translateFromCombo->currentText());
+		display->addRow(TRANSLATE_FROM, translateFromCombo);
+		connect(translateFromCombo, &QComboBox::currentTextChanged, this, &Window::SaveTranslateFrom);
 		for (auto [value, label] : Array<bool&, const char*>{
 			{ translateSelectedOnly, TRANSLATE_SELECTED_THREAD_ONLY },
 			{ rateLimitAll, RATE_LIMIT_ALL_THREADS },
@@ -123,9 +137,13 @@ public:
 	}
 
 private:
-	void saveLanguage(QString language)
+	void SaveTranslateTo(QString language)
 	{
-		settings.setValue(LANGUAGE, S(translateTo->assign(S(language.split(": ")[1]))));
+		settings.setValue(TRANSLATE_TO, S(translateTo->assign(S(language.split(": ")[1]))));
+	}
+	void SaveTranslateFrom(QString language)
+	{
+		settings.setValue(TRANSLATE_FROM, S(translateFrom->assign(S(language.split(": ")[1]))));
 	}
 } window;
 
diff --git a/include/qtcommon.h b/include/qtcommon.h
index 6cd3d91..bb8ceba 100644
--- a/include/qtcommon.h
+++ b/include/qtcommon.h
@@ -9,6 +9,7 @@
 #include <QSettings>
 #include <QMainWindow>
 #include <QDialog>
+#include <QApplication>
 #include <QLayout>
 #include <QFormLayout>
 #include <QLabel>
@@ -26,6 +27,7 @@ constexpr auto WINDOW = u8"Window";
 
 struct Settings : QSettings { Settings(QObject* parent = nullptr) : QSettings(CONFIG_FILE, QSettings::IniFormat, parent) {} };
 struct QTextFile : QFile { QTextFile(QString name, QIODevice::OpenMode mode) : QFile(name) { open(mode | QIODevice::Text); } };
+struct Localizer { Localizer() { Localize(); } };
 inline std::wstring S(const QString& s) { return { s.toStdWString() }; }
 inline QString S(const std::string& s) { return QString::fromStdString(s); }
 inline QString S(const std::wstring& s) { return QString::fromStdWString(s); }
diff --git a/text.cpp b/text.cpp
index 0757595..a051545 100644
--- a/text.cpp
+++ b/text.cpp
@@ -134,6 +134,7 @@ 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* TRANSLATE_TO = u8"Translate to";
+const char* TRANSLATE_FROM = u8"Translate from";
 const char* TRANSLATE_SELECTED_THREAD_ONLY = u8"Translate selected text thread only";
 const char* RATE_LIMIT_ALL_THREADS = u8"Rate limit all text threads";
 const char* RATE_LIMIT_SELECTED_THREAD = u8"Rate limit selected text thread";