diff --git a/public/scripts/extensions/translate/index.js b/public/scripts/extensions/translate/index.js
index 6a10b787d..2be6cf45f 100644
--- a/public/scripts/extensions/translate/index.js
+++ b/public/scripts/extensions/translate/index.js
@@ -135,12 +135,15 @@ const languageCodes = {
'Zulu': 'zu',
};
-const KEY_REQUIRED = ['deepl'];
+const KEY_REQUIRED = ['deepl','libre'];
+const LOCAL_URL = ['libre'];
-function showKeyButton() {
+function showKeysButton() {
const providerRequiresKey = KEY_REQUIRED.includes(extension_settings.translate.provider);
+ const providerOptionalUrl = LOCAL_URL.includes(extension_settings.translate.provider);
$("#translate_key_button").toggle(providerRequiresKey);
$("#translate_key_button").toggleClass('success', Boolean(secret_state[extension_settings.translate.provider]));
+ $("#translate_url_button").toggle(providerOptionalUrl);
}
function loadSettings() {
@@ -153,7 +156,7 @@ function loadSettings() {
$(`#translation_provider option[value="${extension_settings.translate.provider}"]`).attr('selected', true);
$(`#translation_target_language option[value="${extension_settings.translate.target_language}"]`).attr('selected', true);
$(`#translation_auto_mode option[value="${extension_settings.translate.auto_mode}"]`).attr('selected', true);
- showKeyButton();
+ showKeysButton();
}
async function translateImpersonate(text) {
@@ -181,6 +184,22 @@ async function translateIncomingMessage(messageId) {
updateMessageBlock(messageId, message);
}
+async function translateProviderLibre(text, lang) {
+ const response = await fetch('/libre_translate', {
+ method: 'POST',
+ headers: getRequestHeaders(),
+ body: JSON.stringify({ text: text, lang: lang }),
+ });
+
+ if (response.ok) {
+ const result = await response.text();
+ return result;
+ }
+
+ throw new Error(response.statusText);
+}
+
+
async function translateProviderGoogle(text, lang) {
const response = await fetch('/google_translate', {
method: 'POST',
@@ -222,6 +241,8 @@ async function translate(text, lang) {
}
switch (extension_settings.translate.provider) {
+ case 'libre':
+ return await translateProviderLibre(text, lang);
case 'google':
return await translateProviderGoogle(text, lang);
case 'deepl':
@@ -368,10 +389,12 @@ jQuery(() => {
@@ -403,7 +426,7 @@ jQuery(() => {
});
$('#translation_provider').on('change', (event) => {
extension_settings.translate.provider = event.target.value;
- showKeyButton();
+ showKeysButton();
saveSettingsDebounced();
});
$('#translation_target_language').on('change', (event) => {
@@ -422,6 +445,17 @@ jQuery(() => {
await writeSecret(extension_settings.translate.provider, key);
toastr.success('API Key saved');
});
+ $('#translate_url_button').on('click', async () => {
+ const optionText = $('#translation_provider option:selected').text();
+ const url = await callPopup(`${optionText} API URL
`, 'input');
+
+ if (url == false) {
+ return;
+ }
+
+ await writeSecret(extension_settings.translate.provider + "_url", url);
+ toastr.success('API URL saved');
+ });
loadSettings();
diff --git a/server.js b/server.js
index fbaabda46..ec155540d 100644
--- a/server.js
+++ b/server.js
@@ -4096,6 +4096,8 @@ const SECRET_KEYS = {
NOVEL: 'api_key_novel',
CLAUDE: 'api_key_claude',
DEEPL: 'deepl',
+ LIBRE: 'libre',
+ LIBRE_URL: 'libre_url',
OPENROUTER: 'api_key_openrouter',
SCALE: 'api_key_scale',
AI21: 'api_key_ai21',
@@ -4324,6 +4326,46 @@ app.post('/horde_generateimage', jsonParser, async (request, response) => {
}
});
+app.post('/libre_translate', jsonParser, async (request, response) => {
+ const key = readSecret(SECRET_KEYS.LIBRE);
+ const url = readSecret(SECRET_KEYS.LIBRE_URL);
+
+ const text = request.body.text;
+ const lang = request.body.lang;
+
+ if (!text || !lang) {
+ return response.sendStatus(400);
+ }
+
+ console.log('Input text: ' + text);
+
+ try {
+ const result = await fetch(url, {
+ method: "POST",
+ body: JSON.stringify({
+ q: text,
+ source: "auto",
+ target: lang,
+ format: "text",
+ api_key: key
+ }),
+ headers: { "Content-Type": "application/json" }
+ });
+
+ if (!result.ok) {
+ return response.sendStatus(result.status);
+ }
+
+ const json = await result.json();
+ console.log('Translated text: ' + json.translatedText);
+
+ return response.send(json.translatedText);
+ } catch (error) {
+ console.log("Translation error: " + error.message);
+ return response.sendStatus(500);
+ }
+});
+
app.post('/google_translate', jsonParser, async (request, response) => {
const { generateRequestUrl, normaliseResponse } = require('google-translate-api-browser');