Add provider arg to /translate command

7f2cf6f7e6afcfdcbb7ec4da5408559b837de243

Cohee <18619528+Cohee1207@users.noreply.github.com>

2 files changed, +34 -8Ignore whitespace
public/scripts/extensions/translate/index.html+2 -2
@@ -15,7 +15,7 @@
15 <label data-i18n="ext_translate_mode_provider" for="translation_provider">Provider</label>15 <label data-i18n="ext_translate_mode_provider" for="translation_provider">Provider</label>
16 <div class="flex-container gap5px flexnowrap marginBot5">16 <div class="flex-container gap5px flexnowrap marginBot5">
17 <select id="translation_provider" name="provider" class="margin0">17 <select id="translation_provider" name="provider" class="margin0">
18 <option value="libre">Libre</option>18 <option value="libre">LibreTranslate</option>
19 <option value="google">Google</option>19 <option value="google">Google</option>
20 <option value="lingva">Lingva</option>20 <option value="lingva">Lingva</option>
21 <option value="deepl">DeepL</option>21 <option value="deepl">DeepL</option>
@@ -35,4 +35,4 @@
35 </div>35 </div>
36 </div>36 </div>
37 </div>37 </div>
38</div>
38 \ No newline at end of file \ No newline at end of file
38</div>
public/scripts/extensions/translate/index.js+32 -6
@@ -14,6 +14,8 @@ import { POPUP_RESULT, POPUP_TYPE, callGenericPopup } from '../../popup.js';
14import { findSecret, secret_state, writeSecret } from '../../secrets.js';14import { findSecret, secret_state, writeSecret } from '../../secrets.js';
15import { SlashCommand } from '../../slash-commands/SlashCommand.js';15import { SlashCommand } from '../../slash-commands/SlashCommand.js';
16import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';16import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from '../../slash-commands/SlashCommandArgument.js';
17import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js';
18import { enumTypes, SlashCommandEnumValue } from '../../slash-commands/SlashCommandEnumValue.js';
17import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';19import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js';
18import { splitRecursive } from '../../utils.js';20import { splitRecursive } from '../../utils.js';
1921
@@ -395,9 +397,10 @@ async function chunkedTranslate(text, lang, translateFn, chunkSize = 5000) {
395 * Translates text using the selected translation provider397 * Translates text using the selected translation provider
396 * @param {string} text Text to translate398 * @param {string} text Text to translate
397 * @param {string} lang Target language code399 * @param {string} lang Target language code
400 * @param {string} provider Translation provider to use
398 * @returns {Promise<string>} Translated text401 * @returns {Promise<string>} Translated text
399 */402 */
400async function translate(text, lang) {403async function translate(text, lang, provider = null) {
401 try {404 try {
402 if (text == '') {405 if (text == '') {
403 return '';406 return '';
@@ -407,13 +410,17 @@ async function translate(text, lang) {
407 lang = extension_settings.translate.target_language;410 lang = extension_settings.translate.target_language;
408 }411 }
409412
413 if (!provider) {
414 provider = extension_settings.translate.provider;
415 }
416
410 // split text by embedded images links417 // split text by embedded images links
411 const chunks = text.split(/!\[.*?]\([^)]*\)/);418 const chunks = text.split(/!\[.*?]\([^)]*\)/);
412 const links = [...text.matchAll(/!\[.*?]\([^)]*\)/g)];419 const links = [...text.matchAll(/!\[.*?]\([^)]*\)/g)];
413420
414 let result = '';421 let result = '';
415 for (let i = 0; i < chunks.length; i++) {422 for (let i = 0; i < chunks.length; i++) {
416 result += await translateInner(chunks[i], lang);423 result += await translateInner(chunks[i], lang, provider);
417 if (i < links.length) result += links[i][0];424 if (i < links.length) result += links[i][0];
418 }425 }
419426
@@ -424,11 +431,21 @@ async function translate(text, lang) {
424 }431 }
425}432}
426433
427async function translateInner(text, lang) {434/**
435 * Common translation function that handles the translation logic
436 * @param {string} text Text to translate
437 * @param {string} lang Target language code
438 * @param {string} provider Translation provider to use
439 * @returns {Promise<string>} Translated text
440 */
441async function translateInner(text, lang, provider) {
428 if (text == '') {442 if (text == '') {
429 return '';443 return '';
430 }444 }
431 switch (extension_settings.translate.provider) {445 if (!provider) {
446 provider = extension_settings.translate.provider;
447 }
448 switch (provider) {
432 case 'libre':449 case 'libre':
433 return await translateProviderLibre(text, lang);450 return await translateProviderLibre(text, lang);
434 case 'google':451 case 'google':
@@ -446,7 +463,7 @@ async function translateInner(text, lang) {
446 case 'yandex':463 case 'yandex':
447 return await translateProviderYandex(text, lang);464 return await translateProviderYandex(text, lang);
448 default:465 default:
449 console.error('Unknown translation provider', extension_settings.translate.provider);466 console.error('Unknown translation provider', provider);
450 return text;467 return text;
451 }468 }
452}469}
@@ -688,6 +705,14 @@ jQuery(async () => {
688 helpString: 'Translate text to a target language. If target language is not provided, the value from the extension settings will be used.',705 helpString: 'Translate text to a target language. If target language is not provided, the value from the extension settings will be used.',
689 namedArgumentList: [706 namedArgumentList: [
690 new SlashCommandNamedArgument('target', 'The target language code to translate to', ARGUMENT_TYPE.STRING, false, false, '', Object.values(languageCodes)),707 new SlashCommandNamedArgument('target', 'The target language code to translate to', ARGUMENT_TYPE.STRING, false, false, '', Object.values(languageCodes)),
708 SlashCommandNamedArgument.fromProps({
709 name: 'provider',
710 description: 'The translation provider to use. If not provided, the value from the extension settings will be used.',
711 typeList: [ARGUMENT_TYPE.STRING],
712 isRequired: false,
713 acceptsMultiple: false,
714 enumProvider: () => Array.from(document.getElementById('translation_provider').querySelectorAll('option')).map((option) => new SlashCommandEnumValue(option.value, option.text, enumTypes.name, enumIcons.server)),
715 }),
691 ],716 ],
692 unnamedArgumentList: [717 unnamedArgumentList: [
693 new SlashCommandArgument('The text to translate', ARGUMENT_TYPE.STRING, true, false, ''),718 new SlashCommandArgument('The text to translate', ARGUMENT_TYPE.STRING, true, false, ''),
@@ -696,7 +721,8 @@ jQuery(async () => {
696 const target = args?.target && Object.values(languageCodes).includes(String(args.target))721 const target = args?.target && Object.values(languageCodes).includes(String(args.target))
697 ? String(args.target)722 ? String(args.target)
698 : extension_settings.translate.target_language;723 : extension_settings.translate.target_language;
699 return await translate(String(value), target);724 const provider = args?.provider || extension_settings.translate.provider;
725 return await translate(String(value), target, provider);
700 },726 },
701 returns: ARGUMENT_TYPE.STRING,727 returns: ARGUMENT_TYPE.STRING,
702 }));728 }));