SillyTavern/public/scripts/extensions/translate/index.js

675 lines
21 KiB
JavaScript
Raw Normal View History

2024-04-27 20:11:41 +02:00
export { translate };
import {
eventSource,
2024-04-27 20:15:44 +02:00
event_types,
2024-04-27 20:11:41 +02:00
getRequestHeaders,
reloadCurrentChat,
saveSettingsDebounced,
substituteParams,
updateMessageBlock,
} from '../../../script.js';
2024-06-12 11:30:32 +02:00
import { extension_settings, getContext, renderExtensionTemplateAsync } from '../../extensions.js';
import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from '../../popup.js';
2024-04-27 20:11:41 +02:00
import { findSecret, secret_state, writeSecret } from '../../secrets.js';
2024-05-30 21:03:51 +02:00
import { SlashCommand } from '../../slash-commands/SlashCommand.js';
import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
2024-04-27 20:11:41 +02:00
import { splitRecursive } from '../../utils.js';
2023-07-20 19:32:15 +02:00
export const autoModeOptions = {
2024-04-27 20:11:41 +02:00
NONE: 'none',
RESPONSES: 'responses',
INPUT: 'inputs',
BOTH: 'both',
2023-07-20 19:32:15 +02:00
};
const incomingTypes = [autoModeOptions.RESPONSES, autoModeOptions.BOTH];
const outgoingTypes = [autoModeOptions.INPUT, autoModeOptions.BOTH];
const defaultSettings = {
2024-04-27 20:11:41 +02:00
target_language: 'en',
internal_language: 'en',
provider: 'google',
auto_mode: autoModeOptions.NONE,
2023-07-20 19:32:15 +02:00
};
const languageCodes = {
2024-04-27 20:11:41 +02:00
'Afrikaans': 'af',
'Albanian': 'sq',
'Amharic': 'am',
'Arabic': 'ar',
'Armenian': 'hy',
'Azerbaijani': 'az',
'Basque': 'eu',
'Belarusian': 'be',
'Bengali': 'bn',
'Bosnian': 'bs',
'Bulgarian': 'bg',
'Catalan': 'ca',
'Cebuano': 'ceb',
'Chinese (Simplified)': 'zh-CN',
'Chinese (Traditional)': 'zh-TW',
'Corsican': 'co',
'Croatian': 'hr',
'Czech': 'cs',
'Danish': 'da',
'Dutch': 'nl',
'English': 'en',
'Esperanto': 'eo',
'Estonian': 'et',
'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',
'Javanese': 'jw',
'Kannada': 'kn',
'Kazakh': 'kk',
'Khmer': 'km',
'Korean': 'ko',
'Kurdish': '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',
'Nyanja (Chichewa)': 'ny',
'Pashto': 'ps',
'Persian': 'fa',
'Polish': 'pl',
'Portuguese (Portugal, Brazil)': 'pt',
'Punjabi': 'pa',
'Romanian': 'ro',
'Russian': 'ru',
'Samoan': 'sm',
'Scots Gaelic': 'gd',
'Serbian': 'sr',
'Sesotho': 'st',
'Shona': 'sn',
'Sindhi': 'sd',
'Sinhala (Sinhalese)': 'si',
'Slovak': 'sk',
'Slovenian': 'sl',
'Somali': 'so',
'Spanish': 'es',
'Sundanese': 'su',
'Swahili': 'sw',
'Swedish': 'sv',
'Tagalog (Filipino)': 'tl',
'Tajik': 'tg',
'Tamil': 'ta',
'Telugu': 'te',
'Thai': 'th',
'Turkish': 'tr',
'Ukrainian': 'uk',
'Urdu': 'ur',
'Uzbek': 'uz',
'Vietnamese': 'vi',
'Welsh': 'cy',
'Xhosa': 'xh',
'Yiddish': 'yi',
'Yoruba': 'yo',
'Zulu': 'zu',
2023-07-20 19:32:15 +02:00
};
2023-09-10 17:22:39 +02:00
const KEY_REQUIRED = ['deepl', 'libre'];
const LOCAL_URL = ['libre', 'oneringtranslator', 'deeplx', 'lingva'];
2023-07-20 19:32:15 +02:00
2023-08-26 18:53:57 +02:00
function showKeysButton() {
2024-04-27 20:15:44 +02:00
const providerRequiresKey = KEY_REQUIRED.includes(extension_settings.translate.provider);
const providerOptionalUrl = LOCAL_URL.includes(extension_settings.translate.provider);
2024-04-27 20:11:41 +02:00
$('#translate_key_button').toggle(providerRequiresKey);
2024-04-27 20:15:44 +02:00
$('#translate_key_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider]));
2024-04-27 20:11:41 +02:00
$('#translate_url_button').toggle(providerOptionalUrl);
2024-04-27 20:15:44 +02:00
$('#translate_url_button').toggleClass('success', Boolean(secret_state[extension_settings.translate.provider + '_url']));
2023-07-20 19:32:15 +02:00
}
function loadSettings() {
2024-04-27 20:11:41 +02:00
for (const key in defaultSettings) {
if (!Object.hasOwn(extension_settings.translate, key)) {
extension_settings.translate[key] = defaultSettings[key];
}
2023-07-20 19:32:15 +02:00
}
2024-04-27 20:11:41 +02:00
2024-04-27 20:15:44 +02:00
$(`#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);
2024-04-27 20:11:41 +02:00
showKeysButton();
2023-07-20 19:32:15 +02:00
}
async function translateImpersonate(text) {
2024-04-27 20:15:44 +02:00
const translatedText = await translate(text, extension_settings.translate.target_language);
2024-04-27 20:11:41 +02:00
$('#send_textarea').val(translatedText);
2023-07-20 19:32:15 +02:00
}
async function translateIncomingMessage(messageId) {
2024-04-27 20:11:41 +02:00
const context = getContext();
const message = context.chat[messageId];
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
if (typeof message.extra !== 'object') {
message.extra = {};
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
// New swipe is being generated. Don't translate that
if ($(`#chat .mes[mesid="${messageId}"] .mes_text`).text() == '...') {
return;
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:15:44 +02:00
const textToTranslate = substituteParams(message.mes, context.name1, message.name);
const translation = await translate(textToTranslate, extension_settings.translate.target_language);
2024-04-27 20:11:41 +02:00
message.extra.display_text = translation;
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
updateMessageBlock(messageId, message);
2023-07-20 19:32:15 +02:00
}
2023-09-10 16:27:50 +02:00
async function translateProviderOneRing(text, lang) {
2024-04-27 20:15:44 +02:00
let from_lang = lang == extension_settings.translate.internal_language
? extension_settings.translate.target_language
: extension_settings.translate.internal_language;
2024-04-27 20:11:41 +02:00
const response = await fetch('/api/translate/onering', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text, from_lang: from_lang, to_lang: lang }),
});
if (response.ok) {
const result = await response.text();
return result;
}
2023-09-10 16:27:50 +02:00
2024-04-27 20:11:41 +02:00
throw new Error(response.statusText);
2023-09-10 16:27:50 +02:00
}
/**
* Translates text using the LibreTranslate API
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
2023-08-26 18:53:57 +02:00
async function translateProviderLibre(text, lang) {
2024-04-27 20:11:41 +02:00
const response = await fetch('/api/translate/libre', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text, lang: lang }),
});
if (response.ok) {
const result = await response.text();
return result;
}
2023-08-26 18:53:57 +02:00
2024-04-27 20:11:41 +02:00
throw new Error(response.statusText);
2023-08-26 18:53:57 +02:00
}
2023-09-10 16:27:50 +02:00
/**
* Translates text using the Google Translate API
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
2023-07-20 19:32:15 +02:00
async function translateProviderGoogle(text, lang) {
2024-04-27 20:11:41 +02:00
const response = await fetch('/api/translate/google', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text, lang: lang }),
});
if (response.ok) {
const result = await response.text();
return result;
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
throw new Error(response.statusText);
2023-07-20 19:32:15 +02:00
}
/**
* Translates text using an instance of the Lingva Translate
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
async function translateProviderLingva(text, lang) {
2024-04-27 20:11:41 +02:00
const response = await fetch('/api/translate/lingva', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text, lang: lang }),
});
if (response.ok) {
const result = await response.text();
return result;
}
2024-04-27 20:11:41 +02:00
throw new Error(response.statusText);
}
2023-09-10 16:27:50 +02:00
/**
* Translates text using the DeepL API
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
2023-07-20 19:32:15 +02:00
async function translateProviderDeepl(text, lang) {
2024-04-27 20:11:41 +02:00
if (!secret_state.deepl) {
throw new Error('No DeepL API key');
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
const response = await fetch('/api/translate/deepl', {
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);
2023-07-20 19:32:15 +02:00
}
2023-09-10 17:22:39 +02:00
/**
* Translates text using the DeepLX API
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
async function translateProviderDeepLX(text, lang) {
2024-04-27 20:11:41 +02:00
const response = await fetch('/api/translate/deeplx', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text, lang: lang }),
});
if (response.ok) {
const result = await response.text();
return result;
}
2023-09-10 17:22:39 +02:00
2024-04-27 20:11:41 +02:00
throw new Error(response.statusText);
2023-09-10 17:22:39 +02:00
}
2023-10-06 13:39:03 +02:00
/**
* Translates text using the Bing API
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
async function translateProviderBing(text, lang) {
2024-04-27 20:11:41 +02:00
const response = await fetch('/api/translate/bing', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ text: text, lang: lang }),
});
if (response.ok) {
const result = await response.text();
return result;
}
2023-10-06 13:39:03 +02:00
2024-04-27 20:11:41 +02:00
throw new Error(response.statusText);
2023-10-06 13:39:03 +02:00
}
2024-06-10 12:12:09 +02:00
/**
* Translates text using the Yandex Translate API
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
async function translateProviderYandex(text, lang) {
let chunks = [];
const chunkSize = 5000;
if (text.length <= chunkSize) {
chunks.push(text);
} else {
chunks = splitRecursive(text, chunkSize);
}
const response = await fetch('/api/translate/yandex', {
method: 'POST',
headers: getRequestHeaders(),
body: JSON.stringify({ chunks: chunks, lang: lang }),
});
if (response.ok) {
const result = await response.text();
return result;
}
throw new Error(response.statusText);
}
/**
* Splits text into chunks and translates each chunk separately
* @param {string} text Text to translate
* @param {string} lang Target language code
2024-04-27 20:15:44 +02:00
* @param {(text: string, lang: string) => Promise<string>} translateFn Function to translate a single chunk (must return a Promise)
* @param {number} chunkSize Maximum chunk size
* @returns {Promise<string>} Translated text
*/
async function chunkedTranslate(text, lang, translateFn, chunkSize = 5000) {
2024-04-27 20:11:41 +02:00
if (text.length <= chunkSize) {
return await translateFn(text, lang);
}
2024-04-27 20:11:41 +02:00
const chunks = splitRecursive(text, chunkSize);
2024-04-27 20:11:41 +02:00
let result = '';
for (const chunk of chunks) {
result += await translateFn(chunk, lang);
}
return result;
}
2023-09-10 16:27:50 +02:00
/**
* Translates text using the selected translation provider
* @param {string} text Text to translate
* @param {string} lang Target language code
* @returns {Promise<string>} Translated text
*/
2023-07-20 19:32:15 +02:00
async function translate(text, lang) {
2024-04-27 20:11:41 +02:00
try {
if (text == '') {
return '';
}
if (!lang) {
lang = extension_settings.translate.target_language;
}
2024-04-27 20:11:41 +02:00
switch (extension_settings.translate.provider) {
case 'libre':
return await translateProviderLibre(text, lang);
case 'google':
2024-04-27 20:15:44 +02:00
return await chunkedTranslate(text, lang, translateProviderGoogle, 5000);
2024-04-27 20:11:41 +02:00
case 'lingva':
2024-04-27 20:15:44 +02:00
return await chunkedTranslate(text, lang, translateProviderLingva, 5000);
2024-04-27 20:11:41 +02:00
case 'deepl':
return await translateProviderDeepl(text, lang);
case 'deeplx':
2024-04-27 20:15:44 +02:00
return await chunkedTranslate(text, lang, translateProviderDeepLX, 1500);
2024-04-27 20:11:41 +02:00
case 'oneringtranslator':
return await translateProviderOneRing(text, lang);
case 'bing':
return await chunkedTranslate(text, lang, translateProviderBing, 1000);
2024-06-10 12:12:09 +02:00
case 'yandex':
return await translateProviderYandex(text, lang);
2024-04-27 20:11:41 +02:00
default:
2024-04-27 20:15:44 +02:00
console.error('Unknown translation provider', extension_settings.translate.provider);
2024-04-27 20:11:41 +02:00
return text;
}
} catch (error) {
console.log(error);
toastr.error(String(error), 'Failed to translate message');
}
2023-07-20 19:32:15 +02:00
}
async function translateOutgoingMessage(messageId) {
2024-04-27 20:11:41 +02:00
const context = getContext();
const message = context.chat[messageId];
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
if (typeof message.extra !== 'object') {
message.extra = {};
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
const originalText = message.mes;
message.extra.display_text = originalText;
2024-04-27 20:15:44 +02:00
message.mes = await translate(originalText, extension_settings.translate.internal_language);
2024-04-27 20:11:41 +02:00
updateMessageBlock(messageId, message);
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
console.log('translateOutgoingMessage', messageId);
2023-07-20 19:32:15 +02:00
}
function shouldTranslate(types) {
2024-04-27 20:11:41 +02:00
return types.includes(extension_settings.translate.auto_mode);
2023-07-20 19:32:15 +02:00
}
function createEventHandler(translateFunction, shouldTranslateFunction) {
2024-04-27 20:11:41 +02:00
return async (data) => {
if (shouldTranslateFunction()) {
await translateFunction(data);
}
};
2023-07-20 19:32:15 +02:00
}
async function onTranslateInputMessageClick() {
2024-04-27 20:22:50 +02:00
const textarea = document.getElementById('send_textarea');
if (!(textarea instanceof HTMLTextAreaElement)) {
return;
}
if (!textarea.value) {
toastr.warning('Enter a message first');
return;
}
const toast = toastr.info('Input Message is translating', 'Please wait...');
const translatedText = await translate(textarea.value, extension_settings.translate.internal_language);
textarea.value = translatedText;
textarea.dispatchEvent(new Event('input', { bubbles: true }));
2024-04-27 20:22:50 +02:00
toastr.clear(toast);
}
2024-04-27 20:15:44 +02:00
2023-07-20 19:32:15 +02:00
// Prevents the chat from being translated in parallel
let translateChatExecuting = false;
async function onTranslateChatClick() {
2024-04-27 20:11:41 +02:00
if (translateChatExecuting) {
return;
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
try {
translateChatExecuting = true;
const context = getContext();
const chat = context.chat;
2023-07-20 19:32:15 +02:00
2024-04-27 20:15:44 +02:00
toastr.info(`${chat.length} message(s) queued for translation.`, 'Please wait...');
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
for (let i = 0; i < chat.length; i++) {
await translateIncomingMessage(i);
}
2024-04-27 20:11:41 +02:00
await context.saveChat();
} catch (error) {
console.log(error);
toastr.error('Failed to translate chat');
} finally {
translateChatExecuting = false;
}
2023-07-20 19:32:15 +02:00
}
async function onTranslationsClearClick() {
2024-06-12 11:30:32 +02:00
const popupHtml = await renderExtensionTemplateAsync('translate', 'deleteConfirmation');
const confirm = await callGenericPopup(popupHtml, POPUP_TYPE.CONFIRM);
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
if (!confirm) {
return;
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
const context = getContext();
const chat = context.chat;
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
for (const mes of chat) {
if (mes.extra) {
delete mes.extra.display_text;
}
2023-07-20 19:32:15 +02:00
}
2024-04-27 20:11:41 +02:00
await context.saveChat();
await reloadCurrentChat();
2023-07-20 19:32:15 +02:00
}
async function translateMessageEdit(messageId) {
2024-04-27 20:11:41 +02:00
const context = getContext();
const chat = context.chat;
const message = chat[messageId];
2024-04-27 20:15:44 +02:00
if (message.is_system || extension_settings.translate.auto_mode == autoModeOptions.NONE) {
2024-04-27 20:11:41 +02:00
return;
}
2024-04-27 20:15:44 +02:00
if ((message.is_user && shouldTranslate(outgoingTypes)) || (!message.is_user && shouldTranslate(incomingTypes))) {
2024-04-27 20:11:41 +02:00
await translateIncomingMessage(messageId);
}
2023-07-20 19:32:15 +02:00
}
async function onMessageTranslateClick() {
2024-04-27 20:11:41 +02:00
const context = getContext();
const messageId = $(this).closest('.mes').attr('mesid');
const message = context.chat[messageId];
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
// If the message is already translated, revert it back to the original text
if (message?.extra?.display_text) {
delete message.extra.display_text;
updateMessageBlock(messageId, message);
}
// If the message is not translated, translate it
else {
await translateIncomingMessage(messageId);
}
2023-07-20 19:32:15 +02:00
2024-04-27 20:11:41 +02:00
await context.saveChat();
2023-07-20 19:32:15 +02:00
}
2024-04-27 20:15:44 +02:00
const handleIncomingMessage = createEventHandler(translateIncomingMessage, () => shouldTranslate(incomingTypes));
const handleOutgoingMessage = createEventHandler(translateOutgoingMessage, () => shouldTranslate(outgoingTypes));
const handleImpersonateReady = createEventHandler(translateImpersonate, () => shouldTranslate(incomingTypes));
2023-07-20 19:32:15 +02:00
const handleMessageEdit = createEventHandler(translateMessageEdit, () => true);
window['translate'] = translate;
2024-06-15 20:58:15 +02:00
jQuery(async () => {
2024-06-12 11:30:32 +02:00
const html = await renderExtensionTemplateAsync('translate', 'index');
const buttonHtml = await renderExtensionTemplateAsync('translate', 'buttons');
$('#translate_wand_container').append(buttonHtml);
$('#translation_container').append(html);
2024-04-27 20:11:41 +02:00
$('#translate_chat').on('click', onTranslateChatClick);
$('#translate_input_message').on('click', onTranslateInputMessageClick);
$('#translation_clear').on('click', onTranslationsClearClick);
for (const [key, value] of Object.entries(languageCodes)) {
2024-04-27 20:15:44 +02:00
$('#translation_target_language').append(`<option value="${value}">${key}</option>`);
}
2024-04-27 20:11:41 +02:00
$('#translation_auto_mode').on('change', (event) => {
extension_settings.translate.auto_mode = event.target.value;
saveSettingsDebounced();
});
$('#translation_provider').on('change', (event) => {
extension_settings.translate.provider = event.target.value;
showKeysButton();
saveSettingsDebounced();
});
$('#translation_target_language').on('change', (event) => {
extension_settings.translate.target_language = event.target.value;
saveSettingsDebounced();
});
$(document).on('click', '.mes_translate', onMessageTranslateClick);
$('#translate_key_button').on('click', async () => {
const optionText = $('#translation_provider option:selected').text();
const key = await callGenericPopup(`<h3>${optionText} API Key</h3>`, POPUP_TYPE.INPUT);
2024-04-27 20:11:41 +02:00
if (key == false) {
return;
}
await writeSecret(extension_settings.translate.provider, key);
toastr.success('API Key saved');
$('#translate_key_button').addClass('success');
});
$('#translate_url_button').on('click', async () => {
const optionText = $('#translation_provider option:selected').text();
const exampleURLs = {
'libre': 'http://127.0.0.1:5000/translate',
'lingva': 'https://lingva.ml/api/v1',
'oneringtranslator': 'http://127.0.0.1:4990/translate',
2024-06-15 20:58:15 +02:00
'deeplx': 'http://127.0.0.1:1188/translate',
2024-04-27 20:11:41 +02:00
};
const popupText = `<h3>${optionText} API URL</h3><i>Example: <tt>${String(exampleURLs[extension_settings.translate.provider])}</tt></i>`;
const secretKey = extension_settings.translate.provider + '_url';
const savedUrl = secret_state[secretKey] ? await findSecret(secretKey) : '';
const url = await callGenericPopup(popupText, POPUP_TYPE.INPUT, savedUrl,{
customButtons: [{
text: 'Remove URL',
appendAtEnd: true,
result: POPUP_RESULT.NEGATIVE,
action: async () => {
await writeSecret(secretKey, '');
toastr.success('API URL removed');
$('#translate_url_button').toggleClass('success', !!secret_state[secretKey]);
},
}],
});
2024-04-27 20:11:41 +02:00
if (url == false || url == '') {
return;
}
await writeSecret(secretKey, url);
toastr.success('API URL saved');
$('#translate_url_button').addClass('success');
});
loadSettings();
eventSource.makeFirst(event_types.CHARACTER_MESSAGE_RENDERED, handleIncomingMessage);
eventSource.makeFirst(event_types.USER_MESSAGE_RENDERED, handleOutgoingMessage);
2024-04-27 20:11:41 +02:00
eventSource.on(event_types.MESSAGE_SWIPED, handleIncomingMessage);
eventSource.on(event_types.IMPERSONATE_READY, handleImpersonateReady);
2024-05-21 13:23:18 +02:00
eventSource.on(event_types.MESSAGE_UPDATED, handleMessageEdit);
2024-04-27 20:11:41 +02:00
document.body.classList.add('translate');
2024-05-30 21:03:51 +02:00
SlashCommandParser.addCommandObject(SlashCommand.fromProps({
name: 'translate',
helpString: 'Translate text to a target language. If target language is not provided, the value from the extension settings will be used.',
namedArgumentList: [
new SlashCommandNamedArgument('target', 'The target language code to translate to', ARGUMENT_TYPE.STRING, false, false, '', Object.values(languageCodes)),
],
unnamedArgumentList: [
new SlashCommandArgument('The text to translate', ARGUMENT_TYPE.STRING, true, false, ''),
],
callback: async (args, value) => {
const target = args?.target && Object.values(languageCodes).includes(String(args.target))
? String(args.target)
: extension_settings.translate.target_language;
return await translate(String(value), target);
},
2024-06-15 20:58:15 +02:00
returns: ARGUMENT_TYPE.STRING,
2024-05-30 21:03:51 +02:00
}));
2023-07-20 19:32:15 +02:00
});