Merge pull request #3291 from Yokayo/staging Update ru-ru translation

4322197aba621eb22dadbc0571a96add8176ae5b

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

Signed
8 files changed, +185 -74Ignore whitespace
public/index.html+6 -6
@@ -2278,7 +2278,7 @@
22782278 <h4 data-i18n="Model Providers">Model Providers</h4>
22792279 <select id="openrouter_providers_text" class="openrouter_providers" multiple>
22802280 </select>
22812281 <label class="checkbox_label" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." for="openrouter_allow_fallbacks_textgenerationwebui" title="Automatically chooses an alternative provider if chosen providers can't serve your request.">
22822282 <input id="openrouter_allow_fallbacks_textgenerationwebui" type="checkbox" />
22832283 <span data-i18n="Allow fallback providers">Allow fallback providers</span>
22842284 </label>
@@ -2902,7 +2902,7 @@
29022902 <div>
29032903 <h4 data-i18n="Window AI Model">Window AI Model</h4>
29042904 <select id="model_windowai_select">
29052905 <option data-i18n="Use extension settings" value="">Use extension settings</option>
29062906 <option value="openai/gpt-3.5-turbo">openai/gpt-3.5-turbo</option>
29072907 <option value="openai/gpt-3.5-turbo-16k">openai/gpt-3.5-turbo-16k</option>
29082908 <option value="openai/gpt-4">openai/gpt-4</option>
@@ -2977,14 +2977,14 @@
29772977 <h4 data-i18n="Model Providers">Model Providers</h4>
29782978 <select id="openrouter_providers_chat" class="openrouter_providers" multiple>
29792979 </select>
29802980 <label class="checkbox_label marginTopBot5" for="openrouter_allow_fallbacks" data-i18n="[title]Automatically chooses an alternative provider if chosen providers can't serve your request." title="Automatically chooses an alternative provider if chosen providers can't serve your request.">
29812981 <input id="openrouter_allow_fallbacks" type="checkbox" />
29822982 <span data-i18n="Allow fallback providers">Allow fallback providers</span>
29832983 </label>
29842984 </div>
29852985 <small class="marginTopBot5">
29862986 <i class="fa-solid fa-lightbulb"></i>
29872987 <span data-i18n="To use instruct formatting, switch to OpenRouter under Text Completion API.">To use instruct formatting, switch to OpenRouter under Text Completion API.</span>
29882988 </small>
29892989 </form>
29902990 <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data">
@@ -4601,7 +4601,7 @@
46014601 </div>
46024602 </div>
46034603 <div nane="AutoContiueBlock" class="inline-drawer wide100p flexFlowColumn">
46044604 <div class="inline-drawer-toggle inline-drawer-header userSettingsInnerExpandable" data-i18n="[title]Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens." title="Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.">
46054605 <b><span data-i18n="Auto-Continue">Auto-Continue</span></b>
46064606 <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
46074607 </div>
@@ -5734,7 +5734,7 @@
57345734 <span class="drag-handle">&#9776;</span>
57355735 <div class="gap5px world_entry_thin_controls wide100p alignitemscenter">
57365736 <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div>
57375737 <div class="fa-solid fa-toggle-on killSwitch" name="entryKillSwitch" data-i18n="[title]Toggle entry's active state." title="Toggle entry's active state."></div>
57385738 <div class="flex-container alignitemscenter wide100p">
57395739 <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter">
57405740 <div class="flex-container flex1">
public/locales/ru-ru.json+123 -14
@@ -294,7 +294,7 @@
294294 "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde",
295295 "Review the Privacy statement": "Ознакомиться с заявлением о конфиденциальности",
296296 "Trusted workers only": "Только доверенные рабочие машины",
297297 "For privacy reasons, your API key will be hidden after you reload the page.": "ПоИз причинамсоображений безопасности ваш API-ключ будет скрыт после перезагрузки страницы.",
298298 "-- Horde models not loaded --": "--Модель Horde не загружена--",
299299 "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api",
300300 "No connection...": "Нет соединения...",
@@ -331,7 +331,6 @@
331331 "UID ↘": "UID ↘",
332332 "Trigger% ↗": "Триггер% ↗",
333333 "Trigger% ↘": "Триггер% ↘",
334- "Order:": "Порядок:",
335334 "Depth:": "Глубина:",
336335 "Character Lore First": "Сначала лор персонажа",
337336 "Global Lore First": "Сначала глобальный лор",
@@ -347,7 +346,7 @@
347346 "After Char Defs": "↓Перс.",
348347 "Before AN": "↑АЗ",
349348 "After AN": "↓АЗ",
350349 "Order": "ПорядокОчерёдность:",
351350 "Update a theme file": "Обновить файл темы",
352351 "Save as a new theme": "Сохранить как новую тему",
353352 "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.",
@@ -497,7 +496,7 @@
497496 "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно",
498497 "Filter to Character(s)": "Фильтр по персонажу(ам)",
499498 "Character Exclusion": "Исключить персонажей",
500499 "Inclusion Group": "ВключитьГруппа персонажейзаписей",
501500 "Only one entry with the same label will be activated": "Будет активна только одна запись с одинаковой меткой",
502501 "-- Characters not found --": "-- Персонажей не найдено --",
503502 "(This will be the first message from the character that starts every chat)": "(Это будет первое сообщение от персонажа, когда вы начинаете новый чат)",
@@ -541,7 +540,7 @@
541540 "NOT ANY": "НЕ ЛЮБОЙ",
542541 "Optional Filter": "Дополнительный фильтр",
543542 "New Entry": "Новая запись",
544543 "Fill empty Memo/Titles with Keywords": "ЗаполнитеЗаполнить пустые Заметки/Названияназвания ключевыми словами",
545544 "AI Response Formatting": "Формат ответа ИИ",
546545 "Change Background Image": "Изменить фон",
547546 "Extensions": "Расширения",
@@ -628,7 +627,7 @@
628627 "UI Theme": "Тема UI",
629628 "This message is invisible for the AI": "Это сообщение невидимо для ИИ",
630629 "Sampler Priority": "Приоритет сэмплеров",
631630 "Ooba only. Determines the order of samplers.": "Только Oobaoobabooga. Определяет порядок сэмплеров.",
632631 "Load default order": "Загрузить стандартный порядок",
633632 "Max Tokens Second": "Макс. кол-во токенов в секунду",
634633 "CFG": "CFG",
@@ -1342,7 +1341,7 @@
13421341 "Chat Lorebook": "Chat Lorebook for",
13431342 "chat_world_template_txt": "A selected World Info will be bound to this chat. When generating an AI reply,\n it will be combined with the entries from global and character lorebooks.",
13441343 "Use tag as folder": "Tag as folder",
13451344 "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Статус записи:\n 🔵 Постоянная\n 🟢 Обычная\n 🔗 Векторизованная\n ❌ Отключена",
13461345 "WI_Entry_Status_Constant": "Постоянная",
13471346 "WI_Entry_Status_Normal": "Обычная",
13481347 "WI_Entry_Status_Vectorized": "Векторизованная",
@@ -1366,13 +1365,7 @@
13661365 "Can be used to automatically activate Quick Replies": "Can be used to automatically activate Quick Replies",
13671366 "Automation ID": "Automation ID",
13681367 "( None )": "( None )",
1369- "Delay until recursion (this entry can only be activated on recursive checking)": "Delay until recursion (this entry can only be activated on recursive checking)",
1370- "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.\rSupports multiple comma-separated groups.\r\rDocumentation: World Info - Inclusion Group",
1371- "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Prioritize this entry: When checked, this entry is prioritized out of all selections.\rIf multiple are prioritized, the one with the highest 'Order' is chosen.\r",
1372- "A relative likelihood of entry activation within the group": "A relative likelihood of entry activation within the group",
1373- "Group Weight": "Group Weight",
13741368 "Add Memo": "Add Memo",
1375- "close": "close",
13761369 "reset": "reset",
13771370 "save": "save",
13781371 "Open checkpoint chat": "Открыть чат из чекпоинта",
@@ -2035,5 +2028,121 @@
20352028 "tags_sorting_desc": "Автоматически сортировать теги по алфавиту после создания или переименования одного из них.\nПри выключении новые теги будут просто добавляться в конец.\n\nЕсли вручную перетащить один из тегов на другое место, автосортировка отключится.",
20362029 "Imported tags:": "Импортируемые теги:",
20372030 "Importing Tags": "Импорт тегов",
20382031 "Couldn't import tags:": "Не удалось импортировать теги:",
2032+ "Allow fallback models": "Разрешить fallback-модели",
2033+ "Allow fallback providers": "Разрешить fallback-провайдеров",
2034+ "To use instruct formatting, switch to OpenRouter under Text Completion API.": "Переключитесь на OpenRouter в Text Completion API, чтобы использовать форматирование Instruct-режима.",
2035+ "Select providers. No selection = all providers.": "Выберите провайдера. Нет выбранного = выбраны все.",
2036+ "Model Providers": "Провайдеры моделей",
2037+ "Select a model": "Выберите модель",
2038+ "Search models...": "Искать по моделям...",
2039+ "[Currently loaded]": "[Загруженная сейчас]",
2040+ "Search providers...": "Искать по провайдерам...",
2041+ "Automatically chooses an alternative provider if chosen providers can't serve your request.": "Автоматически переключаться на другого провайдера, если текущий не может обслужить запрос.",
2042+ "Example: 127.0.0.1:8000": "Пример: 127.0.0.1:8000",
2043+ "Edit a connection profile": "Редактировать профиль соединения",
2044+ "System Prompt Name": "Название системного промпта",
2045+ "Use System Prompt": "Использовать системный промпт",
2046+ "Hint:": "Подсказка:",
2047+ "Click on the setting name to omit it from the profile.": "Нажмите на название настройки, чтобы исключить её из профиля",
2048+ "Included settings:": "Сохранённые параметры:",
2049+ "Server URL": "Адрес сервера",
2050+ "NanoGPT API Key": "Ключ от API NanoGPT",
2051+ "NanoGPT Model": "Модель NanoGPT",
2052+ "Use extension settings": "Использовать настройки из расширения",
2053+ "DeepSeek API Key": "Ключ от API DeepSeek",
2054+ "DeepSeek Model": "Модель DeepSeek",
2055+ "prompt_post_processing_merge": "Объединять идущие подряд сообщения с одной ролью",
2056+ "prompt_post_processing_semi": "Semi-strict (чередовать роли)",
2057+ "prompt_post_processing_strict": "Strict (чередовать роли, сначала пользователь)",
2058+ "Select Horde models": "Выбрать модель из Horde",
2059+ "Model ID (optional)": "Идентификатор модели (необязательно)",
2060+ "Derive context size from backend": "Использовать бэкенд для определения размера контекста",
2061+ "Rename current preset": "Переименовать пресет",
2062+ "No Worlds active. Click here to select.": "Нет активных миров. Нажмите, чтобы выбрать.",
2063+ "Title/Memo": "Название",
2064+ "Strategy": "Статус",
2065+ "Position": "Позиция",
2066+ "Trigger %": "% срабатывания",
2067+ "Use global": "Глоб. настройка",
2068+ "Whole Words": "Целые слова",
2069+ "Non-recursable (will not be activated by another)": "Не рекурсивная (не активируется другими)",
2070+ "Delay until recursion (can only be activated on recursive checking)": "Рекурсивная (активируется только рекурсией)",
2071+ "Toggle entry's active state.": "Вкл/выкл запись.",
2072+ "Prioritize": "Важная",
2073+ "Prioritize this entry: When checked, this entry is prioritized out of all selections.If multiple are prioritized, the one with the highest 'Order' is chosen.": "Важная запись получает приоритет среди всех выбранных. Если важных записей несколько, выбирается та, у которой выше \"Очерёдность\".",
2074+ "Group Weight": "Вес в группе",
2075+ "A relative likelihood of entry activation within the group": "Относительная вероятность активации записи в рамках группы",
2076+ "Sticky": "Липучка",
2077+ "Sticky entries will stay active for N messages after being triggered.": "Запись-\"липучка\" останется активной в течение N сообщений после срабатывания.",
2078+ "Cooldown": "Кулдаун",
2079+ "Entries with a cooldown can't be activated N messages after being triggered.": "Запись с заданным кулдауном не активируется следующие N сообщений после срабатывания.",
2080+ "Delay": "Задержка",
2081+ "Entries with a delay can't be activated until there are N messages present in the chat.": "Запись с заданной задержкой может активироваться только после того, как в чате наберётся N сообщений.",
2082+ "Non-sticky": "Нет",
2083+ "No cooldown": "Нет",
2084+ "No delay": "Нет",
2085+ "Filter to Characters or Tags": "Фильтровать по персонажам или тегам",
2086+ "Switch to plaintext mode": "Вкл/выкл режим чистого текста",
2087+ "Exclude": "Режим исключения",
2088+ "Switch the Character/Tags filter around to exclude the listed characters and tags from matching for this entry": "Инвертировать логику: для выбранных в фильтре персонажей/тегов данная запись активна НЕ БУДЕТ",
2089+ "Apply current sorting as Order": "Настроить Очерёдность в соответствии с текущей сортировкой",
2090+ "Create a new World Info": "Создать новый мир",
2091+ "Enter a name for the new file:": "Название нового файла:",
2092+ "Inclusion Groups ensure only one entry from a group is activated at a time, if multiple are triggered.Documentation: World Info - Inclusion Group": "Если сразу несколько записей из одной группы окажутся активированными, по факту сработает только одна. Одна запись может входить в несколько групп, отделяются запятыми. Раздел в документации: World Info - Inclusion Group",
2093+ "Valid World Info file name is required": "Требуется корректное имя для файла мира",
2094+ "World Info file has an invalid format": "Файл мира имеет неизвестный формат",
2095+ "World Info file has no entries": "В файле нет ни одной записи",
2096+ "Character not found.": "Персонаж не найден",
2097+ "Open a chat to get a name of the chat-bound lorebook": "Чтобы получить название привязанного к чату лорбука, требуется открыть чат.",
2098+ "File is not valid: ${0}": "Файл повреждён или имеет неизвестный формат: ${0}",
2099+ "The world with ${0} is invalid or corrupted.": "Мир ${0} повреждён или имеет неизвестный формат.",
2100+ "Deactivated all worlds": "Все миры отключены",
2101+ "No world found named: ${0}": "Не найдено мира с название ${0}",
2102+ "Activated world: ${0}": "Мир ${0} включён",
2103+ "Deactivated world: ${0}": "Мир ${0} отключён",
2104+ "World was not active: ${0}": "Мир ${0} не включён",
2105+ "The world '${0}' has been imported and linked to the character successfully.": "Мир ${0} успешно импортирован и привязан к персонажу.",
2106+ "World/Lorebook imported": "Мир/лорбук импортирован",
2107+ "Are you sure you want to import '${0}'?": "Вы точно хотите импортировать '${0}'?",
2108+ "It will overwrite the World/Lorebook with the same name.": "Существующий мир с таким же названием будет перезаписан.",
2109+ "Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens.": "Автоматически \"продолжать\" ответ, если он оказался короче, чем целевая длина (в токенах).",
2110+ "None (not injected)": "Никуда",
2111+ "ext_sum_injection_position_none": "Пересказ не будет вставляться в промпт. Однако его по-прежнему можно будет вставить с помощью макроса {{summary}}",
2112+ "ext_sum_include_wi_scan": "Учитывать при сканировании лорбуком",
2113+ "ext_sum_include_wi_scan_desc": "Учитывать актуальный пересказ при сканировании промпта лорбуком.",
2114+ "ext_sum_force_tip": "Отправить запрос на создание пересказа прямо сейчас.",
2115+ "ext_sum_restore_tip": "Откатиться к предыдущему пересказу; используйте несколько раз, чтобы очистить историю пересказов для чата",
2116+ "Built-in Extensions:": "Комплектные расширения:",
2117+ "Installed Extensions:": "Установленные расширения:",
2118+ "Loading third-party extensions... Please wait...": "Загрузка сторонних расширений... Пожалуйста, подождите...",
2119+ "The page will be reloaded shortly...": "Страница будет перезагружена...",
2120+ "Extensions state changed": "Изменено состояние расширения",
2121+ "Error loading extensions. See browser console for details.": "Не удалось загрузить расширения. Подробности см. в консоли браузера.",
2122+ "You don't have permission to update global extensions.": "Отсутствуют права на обновление глобальных расширений.",
2123+ "Extension update failed": "Не удалось обновить расширение",
2124+ "Extension ${0} updated to ${1}": "Расширение ${0} обновлено до ${1}",
2125+ "Reload the page to apply updates": "Чтобы изменения вступили в силу, обновите страницу",
2126+ "You don't have permission to delete global extensions.": "Отсутствуют права на удаление глобальных расширений.",
2127+ "Are you sure you want to delete ${0}?": "Вы точно хотите удалить ${0}?",
2128+ "You don't have permission to move extensions.": "Отсутствуют права на перемещение расширений.",
2129+ "Are you sure you want to move ${0} to your local extensions? This will make it available only for you.": "Вы точно хотите сделать ${0} локальным расширением? После этого оно будет доступно только вам.",
2130+ "Are you sure you want to move ${0} to the global extensions? This will make it available for all users.": "Вы точно хотите сделать ${0} глобальным расширением? После этого оно будет доступно всем пользователям.",
2131+ "Extension ${0} moved.": "Расширение ${0} перемещено.",
2132+ "Extension ${0} deleted": "Расширение ${0} удалено.",
2133+ "Please wait...": "Пожалуйста, подождите...",
2134+ "Installing extension": "Идёт установка расширения",
2135+ "Extension installation failed": "Не удалось установить расширение",
2136+ "Extension '${0}' by ${1} (version ${2}) has been installed successfully!": "Расширение ${0} от автора ${1} (версия ${2}) успешно установлено!",
2137+ "Extension installation successful": "Расширение установлено",
2138+ "Extension updates available": "Доступных обновлений расширений",
2139+ "Auto-updating extensions. This may take several minutes.": "Запущено автоматическое обновление расширений. Это может занять несколько минут.",
2140+ "Install just for me": "Установить только мне",
2141+ "Install": "Установить",
2142+ "Install for all users": "Установить для всех пользователей",
2143+ "Modules provided by your Extras API:": "Модули из Extras API:",
2144+ "Not connected to the API!": "Нет соединения с API!",
2145+ "ext_type_system": "Это комплектное расширение. Его нельзя удалить, а обновляется оно вместе со всей системой.",
2146+ "Update all": "Обновить все",
2147+ "Close": "Закрыть"
20392148}
public/scripts/extensions.js+11 -11
@@ -682,9 +682,9 @@ function getExtensionData(extension) {
682682 * @return {string} - The HTML string for the module information.
683683 */
684684function getModuleInformation() {
685685 let moduleInfo = modules.length ? `<p>${DOMPurify.sanitize(modules.join(', '))}</p>` : '<p class="failure">' + t`Not connected to the API!` + '</p>';
686686 return `
687687 <h3>` + t`Modules provided by your Extras API:` + `</h3>
688688 ${moduleInfo}
689689 `;
690690}
@@ -703,11 +703,11 @@ async function showExtensionsDetails() {
703703 initialScrollTop = oldPopup.content.scrollTop;
704704 await oldPopup.completeCancelled();
705705 }
706706 const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Built-in Extensions:` + '</h3></div>');
707707 const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Installed Extensions:` + '</h3></div>');
708708 const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5">
709709 <i class="fa-solid fa-spinner fa-spin"></i>
710710 <span>` + t`Loading third-party extensions... Please wait...` + `</span>
711711 </div>`);
712712
713713 htmlExternal.append(htmlLoading);
@@ -728,7 +728,7 @@ async function showExtensionsDetails() {
728728
729729 /** @type {import('./popup.js').CustomPopupButton} */
730730 const updateAllButton = {
731731 text: 't`Update all'`,
732732 appendAtEnd: true,
733733 action: async () => {
734734 requiresReload = true;
@@ -740,7 +740,7 @@ async function showExtensionsDetails() {
740740 let waitingForSave = false;
741741
742742 const popup = new Popup(html, POPUP_TYPE.TEXT, '', {
743743 okButton: 't`Close'`,
744744 wide: true,
745745 large: true,
746746 customButtons: [updateAllButton],
@@ -833,7 +833,7 @@ async function updateExtension(extensionName, quiet) {
833833 toastr.success('Extension is already up to date');
834834 }
835835 } else {
836836 toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, 't`Reload the page to apply updates'`);
837837 }
838838 } catch (error) {
839839 console.error('Error:', error);
@@ -1001,7 +1001,7 @@ export async function installExtension(url, global) {
10011001 }
10021002
10031003 const response = await request.json();
10041004 toastr.success(t`Extension "'${response.display_name}"' by ${response.author} (version ${response.version}) has been installed successfully!`, 't`Extension installation successful'`);
10051005 console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`);
10061006 await loadExtensionSettings({}, false, false);
10071007 await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED);
@@ -1175,7 +1175,7 @@ async function checkForExtensionUpdates(force) {
11751175 await Promise.allSettled(promises);
11761176
11771177 if (updatesAvailable.length > 0) {
11781178 toastr.info(`${updatesAvailable.map(x => `• ${x}`).join('\n')}`, 't`Extension updates available'`);
11791179 }
11801180}
11811181
@@ -1189,7 +1189,7 @@ async function autoUpdateExtensions(forceAll) {
11891189 return;
11901190 }
11911191
11921192 const banner = toastr.info('t`Auto-updating extensions. This may take several minutes.'`, 't`Please wait...'`, { timeOut: 10000, extendedTimeOut: 10000 });
11931193 const isCurrentUserAdmin = isAdmin();
11941194 const promises = [];
11951195 for (const [id, manifest] of Object.entries(manifests)) {
public/scripts/extensions/connection-manager/edit.html+2 -2
@@ -1,10 +1,10 @@
11<div>
22 <h3 data-i18n="Included settings:">Included settings:</h3>
33 <div class="justifyLeft flex-container flexFlowColumn flexNoGap">
44 {{#each settings}}
55 <label class="checkbox_label">
66 <input type="checkbox" value="{{@key}}" name="exclude"{{#if this}} checked{{/if}}>
77 <span data-i18n="{{@key}}">{{@key}}</span>
88 </label>
99 {{/each}}
1010 </div>
public/scripts/extensions/connection-manager/profile.html+2 -2
@@ -12,8 +12,8 @@
1212 </div>
1313 <div class="marginTop5">
1414 <small>
1515 <b data-i18n="Hint:">Hint:</b>
1616 <i data-i18n="Click on the setting name to omit it from the profile.">Click on the setting name to omit it from the profile.</i>
1717 </small>
1818 </div>
1919 <h3 data-i18n="Enter a name:">
public/scripts/openai.js+2 -2
@@ -5491,8 +5491,8 @@ export function initOpenAI() {
54915491
54925492 if (!isMobile()) {
54935493 $('#model_openrouter_select').select2({
54945494 placeholder: 't`Select a model'`,
54955495 searchInputPlaceholder: 't`Search models...'`,
54965496 searchInputCssClass: 'text_pole',
54975497 width: '100%',
54985498 templateResult: getOpenRouterModelTemplate,
public/scripts/textgen-models.js+21 -20
@@ -5,6 +5,7 @@ import { textgenerationwebui_settings as textgen_settings, textgen_types } from
55import { tokenizers } from './tokenizers.js';
66import { renderTemplateAsync } from './templates.js';
77import { POPUP_TYPE, callGenericPopup } from './popup.js';
8+import { t } from './i18n.js';
89
910let mancerModels = [];
1011let togetherModels = [];
@@ -936,71 +937,71 @@ export function initTextGenModels() {
936937
937938 if (!isMobile()) {
938939 $('#mancer_model').select2({
939940 placeholder: 't`Select a model'`,
940941 searchInputPlaceholder: 't`Search models...'`,
941942 searchInputCssClass: 'text_pole',
942943 width: '100%',
943944 templateResult: getMancerModelTemplate,
944945 });
945946 $('#model_togetherai_select').select2({
946947 placeholder: 't`Select a model'`,
947948 searchInputPlaceholder: 't`Search models...'`,
948949 searchInputCssClass: 'text_pole',
949950 width: '100%',
950951 templateResult: getTogetherModelTemplate,
951952 });
952953 $('#ollama_model').select2({
953954 placeholder: 't`Select a model'`,
954955 searchInputPlaceholder: 't`Search models...'`,
955956 searchInputCssClass: 'text_pole',
956957 width: '100%',
957958 });
958959 $('#tabby_model').select2({
959960 placeholder: 't`[Currently loaded]'`,
960961 searchInputPlaceholder: 't`Search models...'`,
961962 searchInputCssClass: 'text_pole',
962963 width: '100%',
963964 allowClear: true,
964965 });
965966 $('#model_infermaticai_select').select2({
966967 placeholder: 't`Select a model'`,
967968 searchInputPlaceholder: 't`Search models...'`,
968969 searchInputCssClass: 'text_pole',
969970 width: '100%',
970971 templateResult: getInfermaticAIModelTemplate,
971972 });
972973 $('#model_dreamgen_select').select2({
973974 placeholder: 't`Select a model'`,
974975 searchInputPlaceholder: 't`Search models...'`,
975976 searchInputCssClass: 'text_pole',
976977 width: '100%',
977978 templateResult: getDreamGenModelTemplate,
978979 });
979980 $('#openrouter_model').select2({
980981 placeholder: 't`Select a model'`,
981982 searchInputPlaceholder: 't`Search models...'`,
982983 searchInputCssClass: 'text_pole',
983984 width: '100%',
984985 templateResult: getOpenRouterModelTemplate,
985986 });
986987 $('#vllm_model').select2({
987988 placeholder: 't`Select a model'`,
988989 searchInputPlaceholder: 't`Search models...'`,
989990 searchInputCssClass: 'text_pole',
990991 width: '100%',
991992 templateResult: getVllmModelTemplate,
992993 });
993994 $('#aphrodite_model').select2({
994995 placeholder: 't`Select a model'`,
995996 searchInputPlaceholder: 't`Search models...'`,
996997 searchInputCssClass: 'text_pole',
997998 width: '100%',
998999 templateResult: getAphroditeModelTemplate,
9991000 });
10001001 providersSelect.select2({
10011002 sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)),
10021003 placeholder: 't`Select providers. No selection = all providers.'`,
10031004 searchInputPlaceholder: 't`Search providers...'`,
10041005 searchInputCssClass: 'text_pole',
10051006 width: '100%',
10061007 closeOnSelect: false,
public/scripts/world-info.js+18 -17
@@ -20,6 +20,7 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
2020import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js';
2121import { StructuredCloneMap } from './util/StructuredCloneMap.js';
2222import { renderTemplateAsync } from './templates.js';
23+import { t } from './i18n.js';
2324
2425export const world_info_insertion_strategy = {
2526 evenly: 0,
@@ -909,21 +910,21 @@ function registerWorldInfoSlashCommands() {
909910
910911 async function getEntriesFromFile(file) {
911912 if (!file || !world_names.includes(file)) {
912913 toastr.warning('t`Valid World Info file name is required'`);
913914 return '';
914915 }
915916
916917 const data = await loadWorldInfo(file);
917918
918919 if (!data || !('entries' in data)) {
919920 toastr.warning('t`World Info file has an invalid format'`);
920921 return '';
921922 }
922923
923924 const entries = Object.values(data.entries);
924925
925926 if (!entries || entries.length === 0) {
926927 toastr.warning('t`World Info file has no entries'`);
927928 return '';
928929 }
929930
@@ -951,7 +952,7 @@ function registerWorldInfoSlashCommands() {
951952 name = String(name ?? '') || context.characters[context.characterId]?.avatar || null;
952953 const character = findChar({ name });
953954 if (!character) {
954955 toastr.error('t`Character not found.'`);
955956 return '';
956957 }
957958 const books = [];
@@ -977,7 +978,7 @@ function registerWorldInfoSlashCommands() {
977978 const chatId = getCurrentChatId();
978979
979980 if (!chatId) {
980981 toastr.warning('t`Open a chat to get a name of the chat-bound lorebook'`);
981982 return '';
982983 }
983984
@@ -4773,7 +4774,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
47734774 const bookName = characters[chid]?.data?.character_book?.name || `${characters[chid]?.name}'s Lorebook`;
47744775
47754776 if (!skipPopup) {
47764777 const confirmation = await Popup.show.confirm(t`Are you sure you want to import "'${bookName}"'?`, world_names.includes(bookName) ? 't`It will overwrite the World/Lorebook with the same name.'` : '');
47774778 if (!confirmation) {
47784779 return;
47794780 }
@@ -4785,7 +4786,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) {
47854786 await updateWorldInfoList();
47864787 $('#character_world').val(bookName).trigger('change');
47874788
47884789 toastr.success(t`The world "'${bookName}"' has been imported and linked to the character successfully.`, 't`World/Lorebook imported'`);
47894790
47904791 const newIndex = world_names.indexOf(bookName);
47914792 if (newIndex >= 0) {
@@ -4813,9 +4814,9 @@ export function onWorldInfoChange(args, text) {
48134814 if (selected_world_info.includes(name)) {
48144815 selected_world_info.splice(selected_world_info.indexOf(name), 1);
48154816 wiElement.prop('selected', false);
48164817 if (!silent) toastr.success(t`Deactivated world: ${name}`);
48174818 } else {
48184819 if (!silent) toastr.error(t`World was not active: ${name}`);
48194820 }
48204821 break;
48214822 }
@@ -4823,11 +4824,11 @@ export function onWorldInfoChange(args, text) {
48234824 if (selected_world_info.includes(name)) {
48244825 selected_world_info.splice(selected_world_info.indexOf(name), 1);
48254826 wiElement.prop('selected', false);
48264827 if (!silent) toastr.success(t`Deactivated world: ${name}`);
48274828 } else {
48284829 selected_world_info.push(name);
48294830 wiElement.prop('selected', true);
48304831 if (!silent) toastr.success(t`Activated world: ${name}`);
48314832 }
48324833 break;
48334834 }
@@ -4835,16 +4836,16 @@ export function onWorldInfoChange(args, text) {
48354836 default: {
48364837 selected_world_info.push(name);
48374838 wiElement.prop('selected', true);
48384839 if (!silent) toastr.success(t`Activated world: ${name}`);
48394840 }
48404841 }
48414842 } else {
48424843 if (!silent) toastr.error(t`No world found named: ${worldName}`);
48434844 }
48444845 });
48454846 $('#world_info').trigger('change');
48464847 } else { // if no args, unset all worlds
48474848 if (!silent) toastr.success('t`Deactivated all worlds'`);
48484849 selected_world_info = [];
48494850 $('#world_info').val(null).trigger('change');
48504851 }
@@ -4860,7 +4861,7 @@ export function onWorldInfoChange(args, text) {
48604861 } else {
48614862 const wiElement = getWIElement(existingWorldName);
48624863 wiElement.prop('selected', false);
48634864 toastr.error(t`The world with ${existingWorldName} is invalid or corrupted.`);
48644865 }
48654866 });
48664867 }
@@ -4892,7 +4893,7 @@ export async function importWorldInfo(file) {
48924893 }
48934894
48944895 if (jsonData === undefined || jsonData === null) {
48954896 toastr.error(t`File is not valid: ${file.name}`);
48964897 return;
48974898 }
48984899
@@ -5038,7 +5039,7 @@ jQuery(() => {
50385039
50395040 $('#world_create_button').on('click', async () => {
50405041 const tempName = getFreeWorldName();
50415042 const finalName = await Popup.show.input('t`Create a new World Info'`, 't`Enter a name for the new file:'`, tempName);
50425043
50435044 if (finalName) {
50445045 await createNewWorldInfo(finalName, { interactive: true });