Work on translation
| @@ -2278,7 +2278,7 @@ | |||
| 2278 | <h4 data-i18n="Model Providers">Model Providers</h4> | 2278 | <h4 data-i18n="Model Providers">Model Providers</h4> |
| 2279 | <select id="openrouter_providers_text" class="openrouter_providers" multiple> | 2279 | <select id="openrouter_providers_text" class="openrouter_providers" multiple> |
| 2280 | </select> | 2280 | </select> |
| 2281 | <label class="checkbox_label" for="openrouter_allow_fallbacks_textgenerationwebui" title="Automatically chooses an alternative provider if chosen providers can't serve your request."> | 2281 | <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."> |
| 2282 | <input id="openrouter_allow_fallbacks_textgenerationwebui" type="checkbox" /> | 2282 | <input id="openrouter_allow_fallbacks_textgenerationwebui" type="checkbox" /> |
| 2283 | <span data-i18n="Allow fallback providers">Allow fallback providers</span> | 2283 | <span data-i18n="Allow fallback providers">Allow fallback providers</span> |
| 2284 | </label> | 2284 | </label> |
| @@ -2902,7 +2902,7 @@ | |||
| 2902 | <div> | 2902 | <div> |
| 2903 | <h4 data-i18n="Window AI Model">Window AI Model</h4> | 2903 | <h4 data-i18n="Window AI Model">Window AI Model</h4> |
| 2904 | <select id="model_windowai_select"> | 2904 | <select id="model_windowai_select"> |
| 2905 | <option value="">Use extension settings</option> | 2905 | <option data-i18n="Use extension settings" value="">Use extension settings</option> |
| 2906 | <option value="openai/gpt-3.5-turbo">openai/gpt-3.5-turbo</option> | 2906 | <option value="openai/gpt-3.5-turbo">openai/gpt-3.5-turbo</option> |
| 2907 | <option value="openai/gpt-3.5-turbo-16k">openai/gpt-3.5-turbo-16k</option> | 2907 | <option value="openai/gpt-3.5-turbo-16k">openai/gpt-3.5-turbo-16k</option> |
| 2908 | <option value="openai/gpt-4">openai/gpt-4</option> | 2908 | <option value="openai/gpt-4">openai/gpt-4</option> |
| @@ -2977,14 +2977,14 @@ | |||
| 2977 | <h4 data-i18n="Model Providers">Model Providers</h4> | 2977 | <h4 data-i18n="Model Providers">Model Providers</h4> |
| 2978 | <select id="openrouter_providers_chat" class="openrouter_providers" multiple> | 2978 | <select id="openrouter_providers_chat" class="openrouter_providers" multiple> |
| 2979 | </select> | 2979 | </select> |
| 2980 | <label class="checkbox_label marginTopBot5" for="openrouter_allow_fallbacks" title="Automatically chooses an alternative provider if chosen providers can't serve your request."> | 2980 | <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."> |
| 2981 | <input id="openrouter_allow_fallbacks" type="checkbox" /> | 2981 | <input id="openrouter_allow_fallbacks" type="checkbox" /> |
| 2982 | <span data-i18n="Allow fallback providers">Allow fallback providers</span> | 2982 | <span data-i18n="Allow fallback providers">Allow fallback providers</span> |
| 2983 | </label> | 2983 | </label> |
| 2984 | </div> | 2984 | </div> |
| 2985 | <small class="marginTopBot5"> | 2985 | <small class="marginTopBot5"> |
| 2986 | <i class="fa-solid fa-lightbulb"></i> | 2986 | <i class="fa-solid fa-lightbulb"></i> |
| 2987 | <span>To use instruct formatting, switch to OpenRouter under Text Completion API.</span> | 2987 | <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> |
| 2988 | </small> | 2988 | </small> |
| 2989 | </form> | 2989 | </form> |
| 2990 | <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data"> | 2990 | <form id="scale_form" data-source="scale" action="javascript:void(null);" method="post" enctype="multipart/form-data"> |
| @@ -4601,7 +4601,7 @@ | |||
| 4601 | </div> | 4601 | </div> |
| 4602 | </div> | 4602 | </div> |
| 4603 | <div nane="AutoContiueBlock" class="inline-drawer wide100p flexFlowColumn"> | 4603 | <div nane="AutoContiueBlock" class="inline-drawer wide100p flexFlowColumn"> |
| 4604 | <div class="inline-drawer-toggle inline-drawer-header userSettingsInnerExpandable" title="Automatically 'continue' a response if the model stopped before reaching a certain amount of tokens."> | 4604 | <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."> |
| 4605 | <b><span data-i18n="Auto-Continue">Auto-Continue</span></b> | 4605 | <b><span data-i18n="Auto-Continue">Auto-Continue</span></b> |
| 4606 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | 4606 | <div class="fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |
| 4607 | </div> | 4607 | </div> |
| @@ -5734,7 +5734,7 @@ | |||
| 5734 | <span class="drag-handle">☰</span> | 5734 | <span class="drag-handle">☰</span> |
| 5735 | <div class="gap5px world_entry_thin_controls wide100p alignitemscenter"> | 5735 | <div class="gap5px world_entry_thin_controls wide100p alignitemscenter"> |
| 5736 | <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> | 5736 | <div class="inline-drawer-toggle fa-fw fa-solid fa-circle-chevron-down inline-drawer-icon down"></div> |
| 5737 | <div class="fa-solid fa-toggle-on killSwitch" name="entryKillSwitch" title="Toggle entry's active state."></div> | 5737 | <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> |
| 5738 | <div class="flex-container alignitemscenter wide100p"> | 5738 | <div class="flex-container alignitemscenter wide100p"> |
| 5739 | <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter"> | 5739 | <div class="WIEntryTitleAndStatus flex-container flex1 alignitemscenter"> |
| 5740 | <div class="flex-container flex1"> | 5740 | <div class="flex-container flex1"> |
| @@ -5967,7 +5967,7 @@ | |||
| 5967 | </small> | 5967 | </small> |
| 5968 | </div> | 5968 | </div> |
| 5969 | <div class="range-block-range"> | 5969 | <div class="range-block-range"> |
| 5970 | <input class="text_pole margin0" name="sticky" type="number" placeholder="Non-sticky" min="0" max="999999"> | 5970 | <input class="text_pole margin0" name="sticky" type="number" data-i18n="[placeholder]No-sticky" placeholder="Non-sticky" min="0" max="999999"> |
| 5971 | </div> | 5971 | </div> |
| 5972 | </div> | 5972 | </div> |
| 5973 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a cooldown can't be activated N messages after being triggered." title="Entries with a cooldown can't be activated N messages after being triggered."> | 5973 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a cooldown can't be activated N messages after being triggered." title="Entries with a cooldown can't be activated N messages after being triggered."> |
| @@ -5980,7 +5980,7 @@ | |||
| 5980 | </small> | 5980 | </small> |
| 5981 | </div> | 5981 | </div> |
| 5982 | <div class="range-block-range"> | 5982 | <div class="range-block-range"> |
| 5983 | <input class="text_pole margin0" name="cooldown" type="number" placeholder="No cooldown" min="0" max="999999"> | 5983 | <input class="text_pole margin0" name="cooldown" type="number" data-i18n="[placeholder]No cooldown" placeholder="No cooldown" min="0" max="999999"> |
| 5984 | </div> | 5984 | </div> |
| 5985 | </div> | 5985 | </div> |
| 5986 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a delay can't be activated until there are N messages present in the chat." title="Entries with a delay can't be activated until there are N messages present in the chat."> | 5986 | <div class="flex2 flex-container flexFlowColumn flexNoGap" data-i18n="[title]Entries with a delay can't be activated until there are N messages present in the chat." title="Entries with a delay can't be activated until there are N messages present in the chat."> |
| @@ -5993,7 +5993,7 @@ | |||
| 5993 | </small> | 5993 | </small> |
| 5994 | </div> | 5994 | </div> |
| 5995 | <div class="range-block-range"> | 5995 | <div class="range-block-range"> |
| 5996 | <input class="text_pole margin0" name="delay" type="number" placeholder="No delay" min="0" max="999999"> | 5996 | <input class="text_pole margin0" name="delay" type="number" data-i18n="[placeholder]No delay" placeholder="No delay" min="0" max="999999"> |
| 5997 | </div> | 5997 | </div> |
| 5998 | </div> | 5998 | </div> |
| 5999 | </div> | 5999 | </div> |
| @@ -294,7 +294,7 @@ | |||
| 294 | "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde", | 294 | "Avoid sending sensitive information to the Horde.": "Избегайте отправки личной информации Horde", |
| 295 | "Review the Privacy statement": "Ознакомиться с заявлением о конфиденциальности", | 295 | "Review the Privacy statement": "Ознакомиться с заявлением о конфиденциальности", |
| 296 | "Trusted workers only": "Только доверенные рабочие машины", | 296 | "Trusted workers only": "Только доверенные рабочие машины", |
| 297 | "For privacy reasons, your API key will be hidden after you reload the page.": "По причинам безопасности ваш API-ключ будет скрыт после перезагрузки страницы.", | 297 | "For privacy reasons, your API key will be hidden after you reload the page.": "Из соображений безопасности ваш API-ключ будет скрыт после перезагрузки страницы.", |
| 298 | "-- Horde models not loaded --": "--Модель Horde не загружена--", | 298 | "-- Horde models not loaded --": "--Модель Horde не загружена--", |
| 299 | "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api", | 299 | "Example: http://127.0.0.1:5000/api ": "Пример: http://127.0.0.1:5000/api", |
| 300 | "No connection...": "Нет соединения...", | 300 | "No connection...": "Нет соединения...", |
| @@ -331,7 +331,6 @@ | |||
| 331 | "UID ↘": "UID ↘", | 331 | "UID ↘": "UID ↘", |
| 332 | "Trigger% ↗": "Триггер% ↗", | 332 | "Trigger% ↗": "Триггер% ↗", |
| 333 | "Trigger% ↘": "Триггер% ↘", | 333 | "Trigger% ↘": "Триггер% ↘", |
| 334 | "Order:": "Порядок:", | ||
| 335 | "Depth:": "Глубина:", | 334 | "Depth:": "Глубина:", |
| 336 | "Character Lore First": "Сначала лор персонажа", | 335 | "Character Lore First": "Сначала лор персонажа", |
| 337 | "Global Lore First": "Сначала глобальный лор", | 336 | "Global Lore First": "Сначала глобальный лор", |
| @@ -347,7 +346,7 @@ | |||
| 347 | "After Char Defs": "↓Перс.", | 346 | "After Char Defs": "↓Перс.", |
| 348 | "Before AN": "↑АЗ", | 347 | "Before AN": "↑АЗ", |
| 349 | "After AN": "↓АЗ", | 348 | "After AN": "↓АЗ", |
| 350 | "Order": "Порядок:", | 349 | "Order": "Очерёдность:", |
| 351 | "Update a theme file": "Обновить файл темы", | 350 | "Update a theme file": "Обновить файл темы", |
| 352 | "Save as a new theme": "Сохранить как новую тему", | 351 | "Save as a new theme": "Сохранить как новую тему", |
| 353 | "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.", | 352 | "Minimum number of blacklisted words detected to trigger an auto-swipe": "Минимальное количество обнаруженных запрещённых слов, при котором срабатывает авто-свайп.", |
| @@ -497,7 +496,7 @@ | |||
| 497 | "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно", | 496 | "What this keyword should mean to the AI, sent verbatim": "Что это ключевое слово должно означать для ИИ, отправляется дословно", |
| 498 | "Filter to Character(s)": "Фильтр по персонажу(ам)", | 497 | "Filter to Character(s)": "Фильтр по персонажу(ам)", |
| 499 | "Character Exclusion": "Исключить персонажей", | 498 | "Character Exclusion": "Исключить персонажей", |
| 500 | "Inclusion Group": "Включить персонажей", | 499 | "Inclusion Group": "Группа записей", |
| 501 | "Only one entry with the same label will be activated": "Будет активна только одна запись с одинаковой меткой", | 500 | "Only one entry with the same label will be activated": "Будет активна только одна запись с одинаковой меткой", |
| 502 | "-- Characters not found --": "-- Персонажей не найдено --", | 501 | "-- Characters not found --": "-- Персонажей не найдено --", |
| 503 | "(This will be the first message from the character that starts every chat)": "(Это будет первое сообщение от персонажа, когда вы начинаете новый чат)", | 502 | "(This will be the first message from the character that starts every chat)": "(Это будет первое сообщение от персонажа, когда вы начинаете новый чат)", |
| @@ -541,7 +540,7 @@ | |||
| 541 | "NOT ANY": "НЕ ЛЮБОЙ", | 540 | "NOT ANY": "НЕ ЛЮБОЙ", |
| 542 | "Optional Filter": "Дополнительный фильтр", | 541 | "Optional Filter": "Дополнительный фильтр", |
| 543 | "New Entry": "Новая запись", | 542 | "New Entry": "Новая запись", |
| 544 | "Fill empty Memo/Titles with Keywords": "Заполните пустые Заметки/Названия ключевыми словами", | 543 | "Fill empty Memo/Titles with Keywords": "Заполнить пустые названия ключевыми словами", |
| 545 | "AI Response Formatting": "Формат ответа ИИ", | 544 | "AI Response Formatting": "Формат ответа ИИ", |
| 546 | "Change Background Image": "Изменить фон", | 545 | "Change Background Image": "Изменить фон", |
| 547 | "Extensions": "Расширения", | 546 | "Extensions": "Расширения", |
| @@ -628,7 +627,7 @@ | |||
| 628 | "UI Theme": "Тема UI", | 627 | "UI Theme": "Тема UI", |
| 629 | "This message is invisible for the AI": "Это сообщение невидимо для ИИ", | 628 | "This message is invisible for the AI": "Это сообщение невидимо для ИИ", |
| 630 | "Sampler Priority": "Приоритет сэмплеров", | 629 | "Sampler Priority": "Приоритет сэмплеров", |
| 631 | "Ooba only. Determines the order of samplers.": "Только Ooba. Определяет порядок сэмплеров.", | 630 | "Ooba only. Determines the order of samplers.": "Только oobabooga. Определяет порядок сэмплеров.", |
| 632 | "Load default order": "Загрузить стандартный порядок", | 631 | "Load default order": "Загрузить стандартный порядок", |
| 633 | "Max Tokens Second": "Макс. кол-во токенов в секунду", | 632 | "Max Tokens Second": "Макс. кол-во токенов в секунду", |
| 634 | "CFG": "CFG", | 633 | "CFG": "CFG", |
| @@ -1342,7 +1341,7 @@ | |||
| 1342 | "Chat Lorebook": "Chat Lorebook for", | 1341 | "Chat Lorebook": "Chat Lorebook for", |
| 1343 | "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.", | 1342 | "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.", |
| 1344 | "Use tag as folder": "Tag as folder", | 1343 | "Use tag as folder": "Tag as folder", |
| 1345 | "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized❌ Disabled": "Статус записи:\n 🔵 Постоянная\n 🟢 Обычная\n 🔗 Векторизованная\n ❌ Отключена", | 1344 | "WI Entry Status:🔵 Constant🟢 Normal🔗 Vectorized": "Статус записи:\n 🔵 Постоянная\n 🟢 Обычная\n 🔗 Векторизованная", |
| 1346 | "WI_Entry_Status_Constant": "Постоянная", | 1345 | "WI_Entry_Status_Constant": "Постоянная", |
| 1347 | "WI_Entry_Status_Normal": "Обычная", | 1346 | "WI_Entry_Status_Normal": "Обычная", |
| 1348 | "WI_Entry_Status_Vectorized": "Векторизованная", | 1347 | "WI_Entry_Status_Vectorized": "Векторизованная", |
| @@ -1366,13 +1365,7 @@ | |||
| 1366 | "Can be used to automatically activate Quick Replies": "Can be used to automatically activate Quick Replies", | 1365 | "Can be used to automatically activate Quick Replies": "Can be used to automatically activate Quick Replies", |
| 1367 | "Automation ID": "Automation ID", | 1366 | "Automation ID": "Automation ID", |
| 1368 | "( None )": "( None )", | 1367 | "( 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", | ||
| 1374 | "Add Memo": "Add Memo", | 1368 | "Add Memo": "Add Memo", |
| 1375 | "close": "close", | ||
| 1376 | "reset": "reset", | 1369 | "reset": "reset", |
| 1377 | "save": "save", | 1370 | "save": "save", |
| 1378 | "Open checkpoint chat": "Открыть чат из чекпоинта", | 1371 | "Open checkpoint chat": "Открыть чат из чекпоинта", |
| @@ -2035,5 +2028,121 @@ | |||
| 2035 | "tags_sorting_desc": "Автоматически сортировать теги по алфавиту после создания или переименования одного из них.\nПри выключении новые теги будут просто добавляться в конец.\n\nЕсли вручную перетащить один из тегов на другое место, автосортировка отключится.", | 2028 | "tags_sorting_desc": "Автоматически сортировать теги по алфавиту после создания или переименования одного из них.\nПри выключении новые теги будут просто добавляться в конец.\n\nЕсли вручную перетащить один из тегов на другое место, автосортировка отключится.", |
| 2036 | "Imported tags:": "Импортируемые теги:", | 2029 | "Imported tags:": "Импортируемые теги:", |
| 2037 | "Importing Tags": "Импорт тегов", | 2030 | "Importing Tags": "Импорт тегов", |
| 2038 | "Couldn't import tags:": "Не удалось импортировать теги:" | 2031 | "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 | "No-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": "Закрыть" | ||
| 2039 | } | 2148 | } |
| @@ -682,9 +682,9 @@ function getExtensionData(extension) { | |||
| 682 | * @return {string} - The HTML string for the module information. | 682 | * @return {string} - The HTML string for the module information. |
| 683 | */ | 683 | */ |
| 684 | function getModuleInformation() { | 684 | function getModuleInformation() { |
| 685 | let moduleInfo = modules.length ? `<p>${DOMPurify.sanitize(modules.join(', '))}</p>` : '<p class="failure">Not connected to the API!</p>'; | 685 | let moduleInfo = modules.length ? `<p>${DOMPurify.sanitize(modules.join(', '))}</p>` : '<p class="failure">' + t`Not connected to the API!` + '</p>'; |
| 686 | return ` | 686 | return ` |
| 687 | <h3>Modules provided by your Extras API:</h3> | 687 | <h3>` + t`Modules provided by your Extras API:` + `</h3> |
| 688 | ${moduleInfo} | 688 | ${moduleInfo} |
| 689 | `; | 689 | `; |
| 690 | } | 690 | } |
| @@ -703,11 +703,11 @@ async function showExtensionsDetails() { | |||
| 703 | initialScrollTop = oldPopup.content.scrollTop; | 703 | initialScrollTop = oldPopup.content.scrollTop; |
| 704 | await oldPopup.completeCancelled(); | 704 | await oldPopup.completeCancelled(); |
| 705 | } | 705 | } |
| 706 | const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">Built-in Extensions:</h3></div>'); | 706 | const htmlDefault = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Built-in Extensions:` + '</h3></div>'); |
| 707 | const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">Installed Extensions:</h3></div>'); | 707 | const htmlExternal = $('<div class="marginBot10"><h3 class="textAlignCenter">' + t`Installed Extensions:` + '</h3></div>'); |
| 708 | const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5"> | 708 | const htmlLoading = $(`<div class="flex-container alignItemsCenter justifyCenter marginTop10 marginBot5"> |
| 709 | <i class="fa-solid fa-spinner fa-spin"></i> | 709 | <i class="fa-solid fa-spinner fa-spin"></i> |
| 710 | <span>Loading third-party extensions... Please wait...</span> | 710 | <span>` + t`Loading third-party extensions... Please wait...` + `</span> |
| 711 | </div>`); | 711 | </div>`); |
| 712 | 712 | ||
| 713 | htmlExternal.append(htmlLoading); | 713 | htmlExternal.append(htmlLoading); |
| @@ -728,7 +728,7 @@ async function showExtensionsDetails() { | |||
| 728 | 728 | ||
| 729 | /** @type {import('./popup.js').CustomPopupButton} */ | 729 | /** @type {import('./popup.js').CustomPopupButton} */ |
| 730 | const updateAllButton = { | 730 | const updateAllButton = { |
| 731 | text: 'Update all', | 731 | text: t`Update all`, |
| 732 | appendAtEnd: true, | 732 | appendAtEnd: true, |
| 733 | action: async () => { | 733 | action: async () => { |
| 734 | requiresReload = true; | 734 | requiresReload = true; |
| @@ -740,7 +740,7 @@ async function showExtensionsDetails() { | |||
| 740 | let waitingForSave = false; | 740 | let waitingForSave = false; |
| 741 | 741 | ||
| 742 | const popup = new Popup(html, POPUP_TYPE.TEXT, '', { | 742 | const popup = new Popup(html, POPUP_TYPE.TEXT, '', { |
| 743 | okButton: 'Close', | 743 | okButton: t`Close`, |
| 744 | wide: true, | 744 | wide: true, |
| 745 | large: true, | 745 | large: true, |
| 746 | customButtons: [updateAllButton], | 746 | customButtons: [updateAllButton], |
| @@ -833,7 +833,7 @@ async function updateExtension(extensionName, quiet) { | |||
| 833 | toastr.success('Extension is already up to date'); | 833 | toastr.success('Extension is already up to date'); |
| 834 | } | 834 | } |
| 835 | } else { | 835 | } else { |
| 836 | toastr.success(`Extension ${extensionName} updated to ${data.shortCommitHash}`, 'Reload the page to apply updates'); | 836 | toastr.success(t`Extension ${extensionName} updated to ${data.shortCommitHash}`, t`Reload the page to apply updates`); |
| 837 | } | 837 | } |
| 838 | } catch (error) { | 838 | } catch (error) { |
| 839 | console.error('Error:', error); | 839 | console.error('Error:', error); |
| @@ -1001,7 +1001,7 @@ export async function installExtension(url, global) { | |||
| 1001 | } | 1001 | } |
| 1002 | 1002 | ||
| 1003 | const response = await request.json(); | 1003 | const response = await request.json(); |
| 1004 | toastr.success(`Extension "${response.display_name}" by ${response.author} (version ${response.version}) has been installed successfully!`, 'Extension installation successful'); | 1004 | toastr.success(t`Extension '${response.display_name}' by ${response.author} (version ${response.version}) has been installed successfully!`, t`Extension installation successful`); |
| 1005 | console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`); | 1005 | console.debug(`Extension "${response.display_name}" has been installed successfully at ${response.extensionPath}`); |
| 1006 | await loadExtensionSettings({}, false, false); | 1006 | await loadExtensionSettings({}, false, false); |
| 1007 | await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED); | 1007 | await eventSource.emit(event_types.EXTENSION_SETTINGS_LOADED); |
| @@ -1175,7 +1175,7 @@ async function checkForExtensionUpdates(force) { | |||
| 1175 | await Promise.allSettled(promises); | 1175 | await Promise.allSettled(promises); |
| 1176 | 1176 | ||
| 1177 | if (updatesAvailable.length > 0) { | 1177 | if (updatesAvailable.length > 0) { |
| 1178 | toastr.info(`${updatesAvailable.map(x => `• ${x}`).join('\n')}`, 'Extension updates available'); | 1178 | toastr.info(`${updatesAvailable.map(x => `• ${x}`).join('\n')}`, t`Extension updates available`); |
| 1179 | } | 1179 | } |
| 1180 | } | 1180 | } |
| 1181 | 1181 | ||
| @@ -1189,7 +1189,7 @@ async function autoUpdateExtensions(forceAll) { | |||
| 1189 | return; | 1189 | return; |
| 1190 | } | 1190 | } |
| 1191 | 1191 | ||
| 1192 | const banner = toastr.info('Auto-updating extensions. This may take several minutes.', 'Please wait...', { timeOut: 10000, extendedTimeOut: 10000 }); | 1192 | const banner = toastr.info(t`Auto-updating extensions. This may take several minutes.`, t`Please wait...`, { timeOut: 10000, extendedTimeOut: 10000 }); |
| 1193 | const isCurrentUserAdmin = isAdmin(); | 1193 | const isCurrentUserAdmin = isAdmin(); |
| 1194 | const promises = []; | 1194 | const promises = []; |
| 1195 | for (const [id, manifest] of Object.entries(manifests)) { | 1195 | for (const [id, manifest] of Object.entries(manifests)) { |
| @@ -1,10 +1,10 @@ | |||
| 1 | <div> | 1 | <div> |
| 2 | <h3>Included settings:</h3> | 2 | <h3 data-i18n="Included settings:">Included settings:</h3> |
| 3 | <div class="justifyLeft flex-container flexFlowColumn flexNoGap"> | 3 | <div class="justifyLeft flex-container flexFlowColumn flexNoGap"> |
| 4 | {{#each settings}} | 4 | {{#each settings}} |
| 5 | <label class="checkbox_label"> | 5 | <label class="checkbox_label"> |
| 6 | <input type="checkbox" value="{{@key}}" name="exclude"{{#if this}} checked{{/if}}> | 6 | <input type="checkbox" value="{{@key}}" name="exclude"{{#if this}} checked{{/if}}> |
| 7 | <span>{{@key}}</span> | 7 | <span data-i18n="{{@key}}">{{@key}}</span> |
| 8 | </label> | 8 | </label> |
| 9 | {{/each}} | 9 | {{/each}} |
| 10 | </div> | 10 | </div> |
| @@ -12,8 +12,8 @@ | |||
| 12 | </div> | 12 | </div> |
| 13 | <div class="marginTop5"> | 13 | <div class="marginTop5"> |
| 14 | <small> | 14 | <small> |
| 15 | <b>Hint:</b> | 15 | <b data-i18n="Hint:">Hint:</b> |
| 16 | <i>Click on the setting name to omit it from the profile.</i> | 16 | <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> |
| 17 | </small> | 17 | </small> |
| 18 | </div> | 18 | </div> |
| 19 | <h3 data-i18n="Enter a name:"> | 19 | <h3 data-i18n="Enter a name:"> |
| @@ -5491,8 +5491,8 @@ export function initOpenAI() { | |||
| 5491 | 5491 | ||
| 5492 | if (!isMobile()) { | 5492 | if (!isMobile()) { |
| 5493 | $('#model_openrouter_select').select2({ | 5493 | $('#model_openrouter_select').select2({ |
| 5494 | placeholder: 'Select a model', | 5494 | placeholder: t`Select a model`, |
| 5495 | searchInputPlaceholder: 'Search models...', | 5495 | searchInputPlaceholder: t`Search models...`, |
| 5496 | searchInputCssClass: 'text_pole', | 5496 | searchInputCssClass: 'text_pole', |
| 5497 | width: '100%', | 5497 | width: '100%', |
| 5498 | templateResult: getOpenRouterModelTemplate, | 5498 | templateResult: getOpenRouterModelTemplate, |
| @@ -5,6 +5,7 @@ import { textgenerationwebui_settings as textgen_settings, textgen_types } from | |||
| 5 | import { tokenizers } from './tokenizers.js'; | 5 | import { tokenizers } from './tokenizers.js'; |
| 6 | import { renderTemplateAsync } from './templates.js'; | 6 | import { renderTemplateAsync } from './templates.js'; |
| 7 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; | 7 | import { POPUP_TYPE, callGenericPopup } from './popup.js'; |
| 8 | import { t } from './i18n.js'; | ||
| 8 | 9 | ||
| 9 | let mancerModels = []; | 10 | let mancerModels = []; |
| 10 | let togetherModels = []; | 11 | let togetherModels = []; |
| @@ -936,71 +937,71 @@ export function initTextGenModels() { | |||
| 936 | 937 | ||
| 937 | if (!isMobile()) { | 938 | if (!isMobile()) { |
| 938 | $('#mancer_model').select2({ | 939 | $('#mancer_model').select2({ |
| 939 | placeholder: 'Select a model', | 940 | placeholder: t`Select a model`, |
| 940 | searchInputPlaceholder: 'Search models...', | 941 | searchInputPlaceholder: t`Search models...`, |
| 941 | searchInputCssClass: 'text_pole', | 942 | searchInputCssClass: 'text_pole', |
| 942 | width: '100%', | 943 | width: '100%', |
| 943 | templateResult: getMancerModelTemplate, | 944 | templateResult: getMancerModelTemplate, |
| 944 | }); | 945 | }); |
| 945 | $('#model_togetherai_select').select2({ | 946 | $('#model_togetherai_select').select2({ |
| 946 | placeholder: 'Select a model', | 947 | placeholder: t`Select a model`, |
| 947 | searchInputPlaceholder: 'Search models...', | 948 | searchInputPlaceholder: t`Search models...`, |
| 948 | searchInputCssClass: 'text_pole', | 949 | searchInputCssClass: 'text_pole', |
| 949 | width: '100%', | 950 | width: '100%', |
| 950 | templateResult: getTogetherModelTemplate, | 951 | templateResult: getTogetherModelTemplate, |
| 951 | }); | 952 | }); |
| 952 | $('#ollama_model').select2({ | 953 | $('#ollama_model').select2({ |
| 953 | placeholder: 'Select a model', | 954 | placeholder: t`Select a model`, |
| 954 | searchInputPlaceholder: 'Search models...', | 955 | searchInputPlaceholder: t`Search models...`, |
| 955 | searchInputCssClass: 'text_pole', | 956 | searchInputCssClass: 'text_pole', |
| 956 | width: '100%', | 957 | width: '100%', |
| 957 | }); | 958 | }); |
| 958 | $('#tabby_model').select2({ | 959 | $('#tabby_model').select2({ |
| 959 | placeholder: '[Currently loaded]', | 960 | placeholder: t`[Currently loaded]`, |
| 960 | searchInputPlaceholder: 'Search models...', | 961 | searchInputPlaceholder: t`Search models...`, |
| 961 | searchInputCssClass: 'text_pole', | 962 | searchInputCssClass: 'text_pole', |
| 962 | width: '100%', | 963 | width: '100%', |
| 963 | allowClear: true, | 964 | allowClear: true, |
| 964 | }); | 965 | }); |
| 965 | $('#model_infermaticai_select').select2({ | 966 | $('#model_infermaticai_select').select2({ |
| 966 | placeholder: 'Select a model', | 967 | placeholder: t`Select a model`, |
| 967 | searchInputPlaceholder: 'Search models...', | 968 | searchInputPlaceholder: t`Search models...`, |
| 968 | searchInputCssClass: 'text_pole', | 969 | searchInputCssClass: 'text_pole', |
| 969 | width: '100%', | 970 | width: '100%', |
| 970 | templateResult: getInfermaticAIModelTemplate, | 971 | templateResult: getInfermaticAIModelTemplate, |
| 971 | }); | 972 | }); |
| 972 | $('#model_dreamgen_select').select2({ | 973 | $('#model_dreamgen_select').select2({ |
| 973 | placeholder: 'Select a model', | 974 | placeholder: t`Select a model`, |
| 974 | searchInputPlaceholder: 'Search models...', | 975 | searchInputPlaceholder: t`Search models...`, |
| 975 | searchInputCssClass: 'text_pole', | 976 | searchInputCssClass: 'text_pole', |
| 976 | width: '100%', | 977 | width: '100%', |
| 977 | templateResult: getDreamGenModelTemplate, | 978 | templateResult: getDreamGenModelTemplate, |
| 978 | }); | 979 | }); |
| 979 | $('#openrouter_model').select2({ | 980 | $('#openrouter_model').select2({ |
| 980 | placeholder: 'Select a model', | 981 | placeholder: t`Select a model`, |
| 981 | searchInputPlaceholder: 'Search models...', | 982 | searchInputPlaceholder: t`Search models...`, |
| 982 | searchInputCssClass: 'text_pole', | 983 | searchInputCssClass: 'text_pole', |
| 983 | width: '100%', | 984 | width: '100%', |
| 984 | templateResult: getOpenRouterModelTemplate, | 985 | templateResult: getOpenRouterModelTemplate, |
| 985 | }); | 986 | }); |
| 986 | $('#vllm_model').select2({ | 987 | $('#vllm_model').select2({ |
| 987 | placeholder: 'Select a model', | 988 | placeholder: t`Select a model`, |
| 988 | searchInputPlaceholder: 'Search models...', | 989 | searchInputPlaceholder: t`Search models...`, |
| 989 | searchInputCssClass: 'text_pole', | 990 | searchInputCssClass: 'text_pole', |
| 990 | width: '100%', | 991 | width: '100%', |
| 991 | templateResult: getVllmModelTemplate, | 992 | templateResult: getVllmModelTemplate, |
| 992 | }); | 993 | }); |
| 993 | $('#aphrodite_model').select2({ | 994 | $('#aphrodite_model').select2({ |
| 994 | placeholder: 'Select a model', | 995 | placeholder: t`Select a model`, |
| 995 | searchInputPlaceholder: 'Search models...', | 996 | searchInputPlaceholder: t`Search models...`, |
| 996 | searchInputCssClass: 'text_pole', | 997 | searchInputCssClass: 'text_pole', |
| 997 | width: '100%', | 998 | width: '100%', |
| 998 | templateResult: getAphroditeModelTemplate, | 999 | templateResult: getAphroditeModelTemplate, |
| 999 | }); | 1000 | }); |
| 1000 | providersSelect.select2({ | 1001 | providersSelect.select2({ |
| 1001 | sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)), | 1002 | sorter: data => data.sort((a, b) => a.text.localeCompare(b.text)), |
| 1002 | placeholder: 'Select providers. No selection = all providers.', | 1003 | placeholder: t`Select providers. No selection = all providers.`, |
| 1003 | searchInputPlaceholder: 'Search providers...', | 1004 | searchInputPlaceholder: t`Search providers...`, |
| 1004 | searchInputCssClass: 'text_pole', | 1005 | searchInputCssClass: 'text_pole', |
| 1005 | width: '100%', | 1006 | width: '100%', |
| 1006 | closeOnSelect: false, | 1007 | closeOnSelect: false, |
| @@ -20,6 +20,7 @@ import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js'; | |||
| 20 | import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js'; | 20 | import { callGenericPopup, Popup, POPUP_TYPE } from './popup.js'; |
| 21 | import { StructuredCloneMap } from './util/StructuredCloneMap.js'; | 21 | import { StructuredCloneMap } from './util/StructuredCloneMap.js'; |
| 22 | import { renderTemplateAsync } from './templates.js'; | 22 | import { renderTemplateAsync } from './templates.js'; |
| 23 | import { t } from './i18n.js'; | ||
| 23 | 24 | ||
| 24 | export const world_info_insertion_strategy = { | 25 | export const world_info_insertion_strategy = { |
| 25 | evenly: 0, | 26 | evenly: 0, |
| @@ -909,21 +910,21 @@ function registerWorldInfoSlashCommands() { | |||
| 909 | 910 | ||
| 910 | async function getEntriesFromFile(file) { | 911 | async function getEntriesFromFile(file) { |
| 911 | if (!file || !world_names.includes(file)) { | 912 | if (!file || !world_names.includes(file)) { |
| 912 | toastr.warning('Valid World Info file name is required'); | 913 | toastr.warning(t`Valid World Info file name is required`); |
| 913 | return ''; | 914 | return ''; |
| 914 | } | 915 | } |
| 915 | 916 | ||
| 916 | const data = await loadWorldInfo(file); | 917 | const data = await loadWorldInfo(file); |
| 917 | 918 | ||
| 918 | if (!data || !('entries' in data)) { | 919 | if (!data || !('entries' in data)) { |
| 919 | toastr.warning('World Info file has an invalid format'); | 920 | toastr.warning(t`World Info file has an invalid format`); |
| 920 | return ''; | 921 | return ''; |
| 921 | } | 922 | } |
| 922 | 923 | ||
| 923 | const entries = Object.values(data.entries); | 924 | const entries = Object.values(data.entries); |
| 924 | 925 | ||
| 925 | if (!entries || entries.length === 0) { | 926 | if (!entries || entries.length === 0) { |
| 926 | toastr.warning('World Info file has no entries'); | 927 | toastr.warning(t`World Info file has no entries`); |
| 927 | return ''; | 928 | return ''; |
| 928 | } | 929 | } |
| 929 | 930 | ||
| @@ -951,7 +952,7 @@ function registerWorldInfoSlashCommands() { | |||
| 951 | name = String(name ?? '') || context.characters[context.characterId]?.avatar || null; | 952 | name = String(name ?? '') || context.characters[context.characterId]?.avatar || null; |
| 952 | const character = findChar({ name }); | 953 | const character = findChar({ name }); |
| 953 | if (!character) { | 954 | if (!character) { |
| 954 | toastr.error('Character not found.'); | 955 | toastr.error(t`Character not found.`); |
| 955 | return ''; | 956 | return ''; |
| 956 | } | 957 | } |
| 957 | const books = []; | 958 | const books = []; |
| @@ -977,7 +978,7 @@ function registerWorldInfoSlashCommands() { | |||
| 977 | const chatId = getCurrentChatId(); | 978 | const chatId = getCurrentChatId(); |
| 978 | 979 | ||
| 979 | if (!chatId) { | 980 | if (!chatId) { |
| 980 | toastr.warning('Open a chat to get a name of the chat-bound lorebook'); | 981 | toastr.warning(t`Open a chat to get a name of the chat-bound lorebook`); |
| 981 | return ''; | 982 | return ''; |
| 982 | } | 983 | } |
| 983 | 984 | ||
| @@ -4773,7 +4774,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) { | |||
| 4773 | const bookName = characters[chid]?.data?.character_book?.name || `${characters[chid]?.name}'s Lorebook`; | 4774 | const bookName = characters[chid]?.data?.character_book?.name || `${characters[chid]?.name}'s Lorebook`; |
| 4774 | 4775 | ||
| 4775 | if (!skipPopup) { | 4776 | if (!skipPopup) { |
| 4776 | const confirmation = await Popup.show.confirm(`Are you sure you want to import "${bookName}"?`, world_names.includes(bookName) ? 'It will overwrite the World/Lorebook with the same name.' : ''); | 4777 | 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.` : ''); |
| 4777 | if (!confirmation) { | 4778 | if (!confirmation) { |
| 4778 | return; | 4779 | return; |
| 4779 | } | 4780 | } |
| @@ -4785,7 +4786,7 @@ export async function importEmbeddedWorldInfo(skipPopup = false) { | |||
| 4785 | await updateWorldInfoList(); | 4786 | await updateWorldInfoList(); |
| 4786 | $('#character_world').val(bookName).trigger('change'); | 4787 | $('#character_world').val(bookName).trigger('change'); |
| 4787 | 4788 | ||
| 4788 | toastr.success(`The world "${bookName}" has been imported and linked to the character successfully.`, 'World/Lorebook imported'); | 4789 | toastr.success(t`The world '${bookName}' has been imported and linked to the character successfully.`, t`World/Lorebook imported`); |
| 4789 | 4790 | ||
| 4790 | const newIndex = world_names.indexOf(bookName); | 4791 | const newIndex = world_names.indexOf(bookName); |
| 4791 | if (newIndex >= 0) { | 4792 | if (newIndex >= 0) { |
| @@ -4813,9 +4814,9 @@ export function onWorldInfoChange(args, text) { | |||
| 4813 | if (selected_world_info.includes(name)) { | 4814 | if (selected_world_info.includes(name)) { |
| 4814 | selected_world_info.splice(selected_world_info.indexOf(name), 1); | 4815 | selected_world_info.splice(selected_world_info.indexOf(name), 1); |
| 4815 | wiElement.prop('selected', false); | 4816 | wiElement.prop('selected', false); |
| 4816 | if (!silent) toastr.success(`Deactivated world: ${name}`); | 4817 | if (!silent) toastr.success(t`Deactivated world: ${name}`); |
| 4817 | } else { | 4818 | } else { |
| 4818 | if (!silent) toastr.error(`World was not active: ${name}`); | 4819 | if (!silent) toastr.error(t`World was not active: ${name}`); |
| 4819 | } | 4820 | } |
| 4820 | break; | 4821 | break; |
| 4821 | } | 4822 | } |
| @@ -4823,11 +4824,11 @@ export function onWorldInfoChange(args, text) { | |||
| 4823 | if (selected_world_info.includes(name)) { | 4824 | if (selected_world_info.includes(name)) { |
| 4824 | selected_world_info.splice(selected_world_info.indexOf(name), 1); | 4825 | selected_world_info.splice(selected_world_info.indexOf(name), 1); |
| 4825 | wiElement.prop('selected', false); | 4826 | wiElement.prop('selected', false); |
| 4826 | if (!silent) toastr.success(`Deactivated world: ${name}`); | 4827 | if (!silent) toastr.success(t`Deactivated world: ${name}`); |
| 4827 | } else { | 4828 | } else { |
| 4828 | selected_world_info.push(name); | 4829 | selected_world_info.push(name); |
| 4829 | wiElement.prop('selected', true); | 4830 | wiElement.prop('selected', true); |
| 4830 | if (!silent) toastr.success(`Activated world: ${name}`); | 4831 | if (!silent) toastr.success(t`Activated world: ${name}`); |
| 4831 | } | 4832 | } |
| 4832 | break; | 4833 | break; |
| 4833 | } | 4834 | } |
| @@ -4835,16 +4836,16 @@ export function onWorldInfoChange(args, text) { | |||
| 4835 | default: { | 4836 | default: { |
| 4836 | selected_world_info.push(name); | 4837 | selected_world_info.push(name); |
| 4837 | wiElement.prop('selected', true); | 4838 | wiElement.prop('selected', true); |
| 4838 | if (!silent) toastr.success(`Activated world: ${name}`); | 4839 | if (!silent) toastr.success(t`Activated world: ${name}`); |
| 4839 | } | 4840 | } |
| 4840 | } | 4841 | } |
| 4841 | } else { | 4842 | } else { |
| 4842 | if (!silent) toastr.error(`No world found named: ${worldName}`); | 4843 | if (!silent) toastr.error(t`No world found named: ${worldName}`); |
| 4843 | } | 4844 | } |
| 4844 | }); | 4845 | }); |
| 4845 | $('#world_info').trigger('change'); | 4846 | $('#world_info').trigger('change'); |
| 4846 | } else { // if no args, unset all worlds | 4847 | } else { // if no args, unset all worlds |
| 4847 | if (!silent) toastr.success('Deactivated all worlds'); | 4848 | if (!silent) toastr.success(t`Deactivated all worlds`); |
| 4848 | selected_world_info = []; | 4849 | selected_world_info = []; |
| 4849 | $('#world_info').val(null).trigger('change'); | 4850 | $('#world_info').val(null).trigger('change'); |
| 4850 | } | 4851 | } |
| @@ -4860,7 +4861,7 @@ export function onWorldInfoChange(args, text) { | |||
| 4860 | } else { | 4861 | } else { |
| 4861 | const wiElement = getWIElement(existingWorldName); | 4862 | const wiElement = getWIElement(existingWorldName); |
| 4862 | wiElement.prop('selected', false); | 4863 | wiElement.prop('selected', false); |
| 4863 | toastr.error(`The world with ${existingWorldName} is invalid or corrupted.`); | 4864 | toastr.error(t`The world with ${existingWorldName} is invalid or corrupted.`); |
| 4864 | } | 4865 | } |
| 4865 | }); | 4866 | }); |
| 4866 | } | 4867 | } |
| @@ -4892,7 +4893,7 @@ export async function importWorldInfo(file) { | |||
| 4892 | } | 4893 | } |
| 4893 | 4894 | ||
| 4894 | if (jsonData === undefined || jsonData === null) { | 4895 | if (jsonData === undefined || jsonData === null) { |
| 4895 | toastr.error(`File is not valid: ${file.name}`); | 4896 | toastr.error(t`File is not valid: ${file.name}`); |
| 4896 | return; | 4897 | return; |
| 4897 | } | 4898 | } |
| 4898 | 4899 | ||
| @@ -5038,7 +5039,7 @@ jQuery(() => { | |||
| 5038 | 5039 | ||
| 5039 | $('#world_create_button').on('click', async () => { | 5040 | $('#world_create_button').on('click', async () => { |
| 5040 | const tempName = getFreeWorldName(); | 5041 | const tempName = getFreeWorldName(); |
| 5041 | const finalName = await Popup.show.input('Create a new World Info', 'Enter a name for the new file:', tempName); | 5042 | const finalName = await Popup.show.input(t`Create a new World Info`, t`Enter a name for the new file:`, tempName); |
| 5042 | 5043 | ||
| 5043 | if (finalName) { | 5044 | if (finalName) { |
| 5044 | await createNewWorldInfo(finalName, { interactive: true }); | 5045 | await createNewWorldInfo(finalName, { interactive: true }); |