Merge pull request #2930 from Yokayo/staging

Work on translation
This commit is contained in:
Cohee
2024-10-05 20:03:53 +03:00
committed by GitHub
13 changed files with 296 additions and 146 deletions

View File

@ -8,6 +8,7 @@ import { debounce, waitUntilCondition, escapeHtml } from './utils.js';
import { debounce_timeout } from './constants.js';
import { renderTemplateAsync } from './templates.js';
import { Popup } from './popup.js';
import { t } from './i18n.js';
function debouncePromise(func, delay) {
let timeoutId;
@ -455,7 +456,7 @@ class PromptManager {
// Delete selected prompt from list form and close edit form
this.handleDeletePrompt = async (event) => {
Popup.show.confirm('Are you sure you want to delete this prompt?', null).then((userChoice) => {
Popup.show.confirm(t`Are you sure you want to delete this prompt?`, null).then((userChoice) => {
if (!userChoice) return;
const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value;
const prompt = this.getPromptById(promptID);
@ -531,7 +532,7 @@ class PromptManager {
// Import prompts for the selected character
this.handleImport = () => {
Popup.show.confirm('Existing prompts with the same ID will be overridden. Do you want to proceed?', null)
Popup.show.confirm(t`Existing prompts with the same ID will be overridden. Do you want to proceed?`, null)
.then(userChoice => {
if (!userChoice) return;
@ -552,7 +553,7 @@ class PromptManager {
const data = JSON.parse(fileContent);
this.import(data);
} catch (err) {
toastr.error('An error occurred while importing prompts. More info available in console.');
toastr.error(t`An error occurred while importing prompts. More info available in console.`);
console.log('An error occurred while importing prompts');
console.log(err.toString());
}
@ -567,7 +568,7 @@ class PromptManager {
// Restore default state of a characters prompt order
this.handleCharacterReset = () => {
Popup.show.confirm('This will reset the prompt order for this character. You will not lose any prompts.', null)
Popup.show.confirm(t`This will reset the prompt order for this character. You will not lose any prompts.`, null)
.then(userChoice => {
if (!userChoice) return;
@ -1649,7 +1650,7 @@ class PromptManager {
};
if (false === this.validateObject(controlObj, importData)) {
toastr.warning('Could not import prompts. Export failed validation.');
toastr.warning(t`Could not import prompts. Export failed validation.`);
return;
}
@ -1672,7 +1673,7 @@ class PromptManager {
throw new Error('Prompt order strategy not supported.');
}
toastr.success('Prompt import complete.');
toastr.success(t`Prompt import complete.`);
this.saveServiceSettings().then(() => this.render());
}

View File

@ -16,6 +16,7 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js';
import { SlashCommand } from './slash-commands/SlashCommand.js';
import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js';
export { MODULE_NAME as NOTE_MODULE_NAME };
import { t } from './i18n.js';
const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory
@ -37,7 +38,7 @@ const chara_note_position = {
function setNoteTextCommand(_, text) {
$('#extension_floating_prompt').val(text).trigger('input');
toastr.success('Author\'s Note text updated');
toastr.success(t`Author's Note text updated`);
return '';
}
@ -45,12 +46,12 @@ function setNoteDepthCommand(_, text) {
const value = Number(text);
if (Number.isNaN(value)) {
toastr.error('Not a valid number');
toastr.error(t`Not a valid number`);
return;
}
$('#extension_floating_depth').val(Math.abs(value)).trigger('input');
toastr.success('Author\'s Note depth updated');
toastr.success(t`Author's Note depth updated`);
return '';
}
@ -58,12 +59,12 @@ function setNoteIntervalCommand(_, text) {
const value = Number(text);
if (Number.isNaN(value)) {
toastr.error('Not a valid number');
toastr.error(t`Not a valid number`);
return;
}
$('#extension_floating_interval').val(Math.abs(value)).trigger('input');
toastr.success('Author\'s Note frequency updated');
toastr.success(t`Author's Note frequency updated`);
return '';
}
@ -76,12 +77,12 @@ function setNotePositionCommand(_, text) {
const position = validPositions[text?.trim()];
if (Number.isNaN(position)) {
toastr.error('Not a valid position');
toastr.error(t`Not a valid position`);
return;
}
$(`input[name="extension_floating_position"][value="${position}"]`).prop('checked', true).trigger('input');
toastr.info('Author\'s Note position updated');
toastr.info(t`Author's Note position updated`);
return '';
}
@ -206,7 +207,7 @@ function onExtensionFloatingCharaPromptInput() {
extension_settings.note.chara.push(tempCharaNote);
} else {
console.log('Character author\'s note error: No avatar name key could be found.');
toastr.error('Something went wrong. Could not save character\'s author\'s note.');
toastr.error(t`Something went wrong. Could not save character's author's note.`);
// Don't save settings if something went wrong
return;
@ -397,7 +398,7 @@ function onANMenuItemClick() {
//because this listener takes priority
$('#options').stop().fadeOut(animation_duration);
} else {
toastr.warning('Select a character before trying to use Author\'s Note', '', { timeOut: 2000 });
toastr.warning(t`Select a character before trying to use Author's Note`, '', { timeOut: 2000 });
}
}

View File

@ -40,6 +40,7 @@ import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
import { ScraperManager } from './scrapers.js';
import { DragAndDropHandler } from './dragdrop.js';
import { renderTemplateAsync } from './templates.js';
import { t } from './i18n.js';
/**
* @typedef {Object} FileAttachment
@ -206,7 +207,7 @@ export async function populateFileAttachment(message, inputId = 'file_form_input
const fileText = await converter(file);
base64Data = window.btoa(unescape(encodeURIComponent(fileText)));
} catch (error) {
toastr.error(String(error), 'Could not convert file');
toastr.error(String(error), t`Could not convert file`);
console.error('Could not convert file', error);
}
}
@ -257,7 +258,7 @@ export async function uploadFileAttachment(fileName, base64Data) {
const responseData = await result.json();
return responseData.path;
} catch (error) {
toastr.error(String(error), 'Could not upload file');
toastr.error(String(error), t`Could not upload file`);
console.error('Could not upload file', error);
}
}
@ -283,7 +284,7 @@ export async function getFileAttachment(url) {
const text = await result.text();
return text;
} catch (error) {
toastr.error(error, 'Could not download file');
toastr.error(error, t`Could not download file`);
console.error('Could not download file', error);
}
}
@ -299,13 +300,13 @@ async function validateFile(file) {
const isBinary = /^[\x00-\x08\x0E-\x1F\x7F-\xFF]*$/.test(fileText);
if (!isImage && file.size > fileSizeLimit) {
toastr.error(`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`);
toastr.error(t`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`);
return false;
}
// If file is binary
if (isBinary && !isImage && !isConvertible(file.type)) {
toastr.error('Binary files are not supported. Select a text file or image.');
toastr.error(t`Binary files are not supported. Select a text file or image.`);
return false;
}
@ -521,7 +522,7 @@ async function openExternalMediaOverridesDialog() {
const entityId = getCurrentEntityId();
if (!entityId) {
toastr.info('No character or group selected');
toastr.info(t`No character or group selected`);
return;
}
@ -646,7 +647,7 @@ async function deleteFileFromServer(url, silent = false) {
await eventSource.emit(event_types.FILE_ATTACHMENT_DELETED, url);
return true;
} catch (error) {
toastr.error(String(error), 'Could not delete file');
toastr.error(String(error), t`Could not delete file`);
console.error('Could not delete file', error);
return false;
}
@ -1054,7 +1055,7 @@ async function openAttachmentManager() {
const selectedAttachments = document.querySelectorAll('.attachmentListItemCheckboxContainer .attachmentListItemCheckbox:checked');
if (selectedAttachments.length === 0) {
toastr.info('No attachments selected.', 'Data Bank');
toastr.info(t`No attachments selected.`, t`Data Bank`);
return;
}
@ -1168,7 +1169,7 @@ async function runScraper(scraperId, target, callback) {
if (files.length === 0) {
console.warn('Scraping returned no files');
toastr.info('No files were scraped.', 'Data Bank');
toastr.info(t`No files were scraped.`, t`Data Bank`);
return;
}
@ -1176,12 +1177,12 @@ async function runScraper(scraperId, target, callback) {
await uploadFileAttachmentToServer(file, target);
}
toastr.success(`Scraped ${files.length} files from ${scraperId} to ${target}.`, 'Data Bank');
toastr.success(t`Scraped ${files.length} files from ${scraperId} to ${target}.`, t`Data Bank`);
callback();
}
catch (error) {
console.error('Scraping failed', error);
toastr.error('Check browser console for details.', 'Scraping failed');
toastr.error(t`Check browser console for details.`, t`Scraping failed`);
}
}
@ -1208,7 +1209,7 @@ export async function uploadFileAttachmentToServer(file, target) {
const fileText = await converter(file);
base64Data = window.btoa(unescape(encodeURIComponent(fileText)));
} catch (error) {
toastr.error(String(error), 'Could not convert file');
toastr.error(String(error), t`Could not convert file`);
console.error('Could not convert file', error);
}
} else {

View File

@ -132,7 +132,7 @@
<small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small>
<span class="fa-solid fa-circle-question note-link-span" title="By default, regex scripts alter the chat file directly and irreversibly.&#13;Enabling either (or both) of the options below will prevent chat file alteration, while still altering the specified item(s)."></span>
</span>
<label class="checkbox flex-container" title="Chat history file contents won't change, but regex will be applied to the messages displayed in the Chat UI.">
<label class="checkbox flex-container" data-i18n="[title]ext_regex_only_format_visual_desc" title="Chat history file contents won't change, but regex will be applied to the messages displayed in the Chat UI.">
<input type="checkbox" name="only_format_display" />
<span data-i18n="Only Format Display">Alter Chat Display</span>
</label>

View File

@ -189,8 +189,8 @@ async function validateGroup(group) {
group.members = group.members.filter(member => {
const character = characters.find(x => x.avatar === member || x.name === member);
if (!character) {
const msg = `Warning: Listed member ${member} does not exist as a character. It will be removed from the group.`;
toastr.warning(msg, 'Group Validation');
const msg = t`Warning: Listed member ${member} does not exist as a character. It will be removed from the group.`;
toastr.warning(msg, t`Group Validation`);
console.warn(msg);
dirty = true;
}
@ -522,7 +522,7 @@ async function saveGroupChat(groupId, shouldSaveGroup) {
});
if (!response.ok) {
toastr.error('Check the server connection and reload the page to prevent data loss.', 'Group Chat could not be saved');
toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Group Chat could not be saved`);
console.error('Group chat could not be saved', response);
return;
}
@ -837,7 +837,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) {
activatedMembers = activateSwipe(group.members);
if (activatedMembers.length === 0) {
toastr.warning('Deleted group member swiped. To get a reply, add them back to the group.');
toastr.warning(t`Deleted group member swiped. To get a reply, add them back to the group.`);
throw new Error('Deleted group member swiped');
}
}
@ -1368,15 +1368,15 @@ function isGroupMemberDisabled(avatarId) {
async function onDeleteGroupClick() {
if (!openGroupId) {
toastr.warning('Currently no group selected.');
toastr.warning(t`Currently no group selected.`);
return;
}
if (is_group_generating) {
toastr.warning('Not so fast! Wait for the characters to stop typing before deleting the group.');
toastr.warning(t`Not so fast! Wait for the characters to stop typing before deleting the group.`);
return;
}
const confirm = await Popup.show.confirm('Delete the group?', '<p>This will also delete all your chats with that group. If you want to delete a single conversation, select a "View past chats" option in the lower left menu.</p>');
const confirm = await Popup.show.confirm(t`Delete the group?`, '<p>' + t`This will also delete all your chats with that group. If you want to delete a single conversation, select a "View past chats" option in the lower left menu.` + '</p>');
if (confirm) {
deleteGroup(openGroupId);
}
@ -1630,7 +1630,7 @@ function updateFavButtonState(state) {
export async function openGroupById(groupId) {
if (isChatSaving) {
toastr.info('Please wait until the chat is saved before switching characters.', 'Your chat is still saving...');
toastr.info(t`Please wait until the chat is saved before switching characters.`, t`Your chat is still saving...`);
return;
}
@ -1659,7 +1659,7 @@ export async function openGroupById(groupId) {
function openCharacterDefinition(characterSelect) {
if (is_group_generating) {
toastr.warning('Can\'t peek a character while group reply is being generated');
toastr.warning(t`Can't peek a character while group reply is being generated`);
console.warn('Can\'t peek a character def while group reply is being generated');
return;
}
@ -1908,7 +1908,7 @@ export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) {
});
if (!response.ok) {
toastr.error('Check the server connection and reload the page to prevent data loss.', 'Group chat could not be saved');
toastr.error(t`Check the server connection and reload the page to prevent data loss.`, t`Group chat could not be saved`);
console.error('Group chat could not be saved', response);
}
}

View File

@ -388,7 +388,7 @@ async function validateReverseProxy() {
new URL(oai_settings.reverse_proxy);
}
catch (err) {
toastr.error('Entered reverse proxy address is not a valid URL');
toastr.error(t`Entered reverse proxy address is not a valid URL`);
setOnlineStatus('no_connection');
resultCheckStatus();
throw err;
@ -399,7 +399,7 @@ async function validateReverseProxy() {
const confirmation = skipConfirm || await Popup.show.confirm(t`Connecting To Proxy`, await renderTemplateAsync('proxyConnectionWarning', { proxyURL: DOMPurify.sanitize(oai_settings.reverse_proxy) }));
if (!confirmation) {
toastr.error('Update or remove your reverse proxy settings.');
toastr.error(t`Update or remove your reverse proxy settings.`);
setOnlineStatus('no_connection');
resultCheckStatus();
throw new Error('Proxy connection denied.');
@ -1231,15 +1231,15 @@ export async function prepareOpenAIMessages({
await populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples });
} catch (error) {
if (error instanceof TokenBudgetExceededError) {
toastr.error('An error occurred while counting tokens: Token budget exceeded.');
toastr.error(t`An error occurred while counting tokens: Token budget exceeded.`);
chatCompletion.log('Token budget exceeded.');
promptManager.error = 'Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.';
promptManager.error = t`Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.`;
} else if (error instanceof InvalidCharacterNameError) {
toastr.warning('An error occurred while counting tokens: Invalid character name');
toastr.warning(t`An error occurred while counting tokens: Invalid character name`);
chatCompletion.log('Invalid character name');
promptManager.error = 'The name of at least one character contained whitespaces or special characters. Please check your user and character name.';
promptManager.error = t`The name of at least one character contained whitespaces or special characters. Please check your user and character name.`;
} else {
toastr.error('An unknown error occurred while counting tokens. Further information may be available in console.');
toastr.error(t`An unknown error occurred while counting tokens. Further information may be available in console.`);
chatCompletion.log('----- Unexpected error while preparing prompts -----');
chatCompletion.log(error);
chatCompletion.log(error.stack);
@ -1293,11 +1293,8 @@ function tryParseStreamingError(response, decoded) {
}
}
function checkQuotaError(data) {
const errorText = `<h3>Encountered an error while processing your request.<br>
Check you have credits available on your
<a href="https://platform.openai.com/account/usage" target="_blank">OpenAI account</a>.<br>
If you have sufficient credits, please try again later.</h3>`;
async function checkQuotaError(data) {
const errorText = await renderTemplateAsync('quotaError');
if (!data) {
return;
@ -1933,11 +1930,11 @@ async function sendOpenAIRequest(type, messages, signal) {
else {
const data = await response.json();
checkQuotaError(data);
await checkQuotaError(data);
checkModerationError(data);
if (data.error) {
toastr.error(data.error.message || response.statusText, 'API returned an error');
toastr.error(data.error.message || response.statusText, t`API returned an error`);
throw new Error(data);
}
@ -2184,7 +2181,7 @@ function parseOpenAITextLogprobs(logprobs) {
function handleWindowError(err) {
const text = parseWindowError(err);
toastr.error(text, 'Window.ai returned an error');
toastr.error(text, t`Window.ai returned an error`);
throw err;
}
@ -3257,7 +3254,7 @@ async function getStatusOpen() {
}
function showWindowExtensionError() {
toastr.error('Get it here: <a href="https://windowai.io/" target="_blank">windowai.io</a>', 'Extension is not installed', {
toastr.error(t`Get it here:` + ' <a href="https://windowai.io/" target="_blank">windowai.io</a>', t`Extension is not installed`, {
escapeHtml: false,
timeOut: 0,
extendedTimeOut: 0,
@ -3376,7 +3373,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) {
if (triggerUi) $('#settings_preset_openai').append(option).trigger('change');
}
} else {
toastr.error('Failed to save preset');
toastr.error(t`Failed to save preset`);
throw new Error('Failed to save preset');
}
}
@ -3455,7 +3452,7 @@ async function createNewLogitBiasPreset() {
}
if (name in oai_settings.bias_presets) {
toastr.error('Preset name should be unique.');
toastr.error(t`Preset name should be unique.`);
return;
}
@ -3499,7 +3496,7 @@ async function onPresetImportFileChange(e) {
try {
presetBody = JSON.parse(importedFile);
} catch (err) {
toastr.error('Invalid file');
toastr.error(t`Invalid file`);
return;
}
@ -3540,7 +3537,7 @@ async function onPresetImportFileChange(e) {
});
if (!savePresetSettings.ok) {
toastr.error('Failed to save preset');
toastr.error(t`Failed to save preset`);
return;
}
@ -3565,7 +3562,7 @@ async function onPresetImportFileChange(e) {
async function onExportPresetClick() {
if (!oai_settings.preset_settings_openai) {
toastr.error('No preset selected');
toastr.error(t`No preset selected`);
return;
}
@ -3606,12 +3603,12 @@ async function onLogitBiasPresetImportFileChange(e) {
e.target.value = '';
if (name in oai_settings.bias_presets) {
toastr.error('Preset name should be unique.');
toastr.error(t`Preset name should be unique.`);
return;
}
if (!Array.isArray(importedFile)) {
toastr.error('Invalid logit bias preset file.');
toastr.error(t`Invalid logit bias preset file.`);
return;
}
@ -3670,16 +3667,16 @@ async function onDeletePresetClick() {
});
if (!response.ok) {
toastr.warning('Preset was not deleted from server');
toastr.warning(t`Preset was not deleted from server`);
} else {
toastr.success('Preset deleted');
toastr.success(t`Preset deleted`);
}
saveSettingsDebounced();
}
async function onLogitBiasPresetDeleteClick() {
const value = await callPopup('Delete the preset?', 'confirm');
const value = await callPopup(t`Delete the preset?`, 'confirm');
if (!value) {
return;
@ -4816,7 +4813,7 @@ function runProxyCallback(_, value) {
const result = fuse.search(value);
if (result.length === 0) {
toastr.warning(`Proxy preset "${value}" not found`);
toastr.warning(t`Proxy preset '${value}' not found`);
return '';
}
@ -4990,7 +4987,7 @@ export function initOpenAI() {
$('#update_oai_preset').on('click', async function () {
const name = oai_settings.preset_settings_openai;
await saveOpenAIPreset(name, oai_settings);
toastr.success('Preset updated');
toastr.success(t`Preset updated`);
});
$('#impersonation_prompt_restore').on('click', function () {

View File

@ -1,3 +1,3 @@
<div>
<b>Note:</b> this chat is temporary and will be deleted as soon as you leave it.
<b data-i18n="Note:">Note:</b> <span data-i18n="this chat is temporary and will be deleted as soon as you leave it.">this chat is temporary and will be deleted as soon as you leave it.</span>
</div>

View File

@ -0,0 +1,5 @@
<b><span data-i18n="THIS IS PERMANENT!">THIS IS PERMANENT!</span><br><br>
<label for="del_char_checkbox" class="checkbox_label justifyCenter">
<input type="checkbox" id="del_char_checkbox" />
<small data-i18n="Also delete the chat files">Also delete the chat files</small>
</label></b>

View File

@ -1,5 +1,5 @@
<div>
<h3>Are you sure you want to duplicate this character?</h3>
<span>If you just want to start a new chat with the same character, use "Start new chat" option in the bottom-left options menu.</span>
<h3 data-i18n="Are you sure you want to duplicate this character?">Are you sure you want to duplicate this character?</h3>
<span data-i18n="If you just want to start a new chat with the same character...">If you just want to start a new chat with the same character, use "Start new chat" option in the bottom-left options menu.</span>
<br>
</div>

View File

@ -14,18 +14,18 @@
<li><kbd data-i18n="help_hotkeys_19">Ctrl+Shift+Down</kbd> = <span data-i18n="help_hotkeys_20">Scroll chat to bottom</span></li>
</ul>
<div>
<strong>Markdown Hotkeys</strong>
<strong data-i18n="help_hotkeys_20">Markdown Hotkeys</strong>
</div>
<div>
<small>
<span>Works in the chatbar and textareas marked with this icon:</span>
<span data-i18n="help_hotkeys_21">Works in the chatbar and textareas marked with this icon:</span>
<code><i class="fa-brands fa-markdown"></i></code>
</small>
</div>
<ul>
<li><kbd>Ctrl+B</kbd> = <span>**bold**</span></li>
<li><kbd>Ctrl+I</kbd> = <span>*italic*</span></li>
<li><kbd>Ctrl+U</kbd> = <span>__underline__</span></li>
<li><kbd>Ctrl+K</kbd> = <span>`inline code`</span></li>
<li><kbd>Ctrl+Shift+~</kbd> = <span>~~strikethrough~~</span></li>
<li><kbd>Ctrl+B</kbd> = <span data-i18n="help_hotkeys_22">**bold**</span></li>
<li><kbd>Ctrl+I</kbd> = <span data-i18n="help_hotkeys_23">*italic*</span></li>
<li><kbd>Ctrl+U</kbd> = <span data-i18n="help_hotkeys_24">__underline__</span></li>
<li><kbd>Ctrl+K</kbd> = <span data-i18n="help_hotkeys_25">`inline code`</span></li>
<li><kbd>Ctrl+Shift+~</kbd> = <span data-i18n="help_hotkeys_26">~~strikethrough~~</span></li>
</ul>

View File

@ -0,0 +1,4 @@
<h3><span data-i18n="Encountered an error while processing your request.">Encountered an error while processing your request.</span><br>
<span data-i18n="Check you have credits available on your">Check you have credits available on your</span>
<a href="https://platform.openai.com/account/usage" target="_blank" data-i18n="OpenAI account quora_error">OpenAI account</a><span data-i18n="dot quota_error">.</span><br>
<span data-i18n="If you have sufficient credits, please try again later.">If you have sufficient credits, please try again later.</span></h3>