Merge pull request #2930 from Yokayo/staging Work on translation
Signed| @@ -56,7 +56,7 @@ | ||
| 56 | 56 | "Rep. Pen. Slope": "Rep. Pen. Slope", |
| 57 | 57 | "Top K": "Top K", |
| 58 | 58 | "Top P": "Top P", |
| 59 | 59 | "Do Sample": "СделатьВключить образецсэмплинг", |
| 60 | 60 | "Add BOS Token": "Добавлять BOS-токен", |
| 61 | 61 | "Add the bos_token to the beginning of prompts. Disabling this can make the replies more creative": "Добавлять BOS-токен в начале промпта. Если выключить, ответы могут стать более креативными.", |
| 62 | 62 | "Ban EOS Token": "Запретить EOS-токен", |
| @@ -451,8 +451,8 @@ | ||
| 451 | 451 | "Creator's Notes": "Заметки создателя", |
| 452 | 452 | "A-Z": "A-Z", |
| 453 | 453 | "Z-A": "Z-A", |
| 454 | 454 | "Newest": "НовейшиеСначала новые", |
| 455 | 455 | "Oldest": "СтарейшиеСначала старые", |
| 456 | 456 | "Favorites": "Избранные", |
| 457 | 457 | "Recent": "Последние", |
| 458 | 458 | "Most chats": "Больше всего чатов", |
| @@ -564,7 +564,7 @@ | ||
| 564 | 564 | "Advanced Definition": "Расширенное описание", |
| 565 | 565 | "Character Lore": "Лор персонажа", |
| 566 | 566 | "Export and Download": "Экспортировать и скачать", |
| 567 | 567 | "Duplicate Character": "ДублироватьКлонировать персонажа", |
| 568 | 568 | "Create Character": "Создать персонажа", |
| 569 | 569 | "Delete Character": "Удалить персонажа", |
| 570 | 570 | "View all tags": "Показать все тэги", |
| @@ -1690,7 +1690,7 @@ | ||
| 1690 | 1690 | "Delete Message": "Удалить сообщение", |
| 1691 | 1691 | "Delete Swipe": "Удалить свайп", |
| 1692 | 1692 | "Could not get a reply from API. Check your connection settings / API key and try again.": "Не удалось получить ответ от API. Проверьте настройки соединения и API-ключ и повторите попытку.", |
| 1693 | 1693 | "Connecting To Proxy": "ПодключениеПодключиться к прокси", |
| 1694 | 1694 | "Are you sure you want to connect to the following proxy URL?": "Вы точно хотите соединиться с прокси по этому адресу?", |
| 1695 | 1695 | "API connection successful!": "Соединение с API установлено!", |
| 1696 | 1696 | "Proxy Saved": "Прокси сохранена", |
| @@ -1747,5 +1747,151 @@ | ||
| 1747 | 1747 | "Markdown Hotkeys": "Горячие клавиши для разметки", |
| 1748 | 1748 | "markdown_hotkeys_desc": "Включить горячие клавиши для вставки символов разметки в некоторых полях ввода. См. '/help hotkeys'.", |
| 1749 | 1749 | "Save and Update": "Сохранить и обновить", |
| 1750 | 1750 | "Profile name:": "Название профиля:", |
| 1751 | + "API returned an error": "API вернуло ошибку", | |
| 1752 | + "Failed to save preset": "Не удалось сохранить пресет", | |
| 1753 | + "Preset name should be unique.": "Название пресета должно быть уникальным.", | |
| 1754 | + "Invalid file": "Невалидный файл", | |
| 1755 | + "No preset selected": "Пресет не выбран", | |
| 1756 | + "Invalid logit bias preset file.": "Файл пресета невалиден.", | |
| 1757 | + "Preset was not deleted from server": "Пресет не удалён с сервера", | |
| 1758 | + "Preset deleted": "Пресет удалён", | |
| 1759 | + "Delete the preset?": "Удалить пресет?", | |
| 1760 | + "Preset updated": "Пресет обновлён", | |
| 1761 | + "Entered reverse proxy address is not a valid URL": "Введённый адрес прокси невалиден", | |
| 1762 | + "An error occurred while counting tokens: Token budget exceeded.": "Ошибка при подсчёте токенов: Превышен бюджет токенов", | |
| 1763 | + "An error occurred while counting tokens: Invalid character name": "Ошибка при подсчёте токенов: Невалидное имя персонажа", | |
| 1764 | + "Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.": "Недостаточно токенов для всех выбранных промптов. Повысьте лимит токенов или отключите часть промптов.", | |
| 1765 | + "The name of at least one character contained whitespaces or special characters. Please check your user and character name.": "В имени одного из персонажей содержится пробел или иной спецсимвол. Проверьте имена пользователя и персонажа.", | |
| 1766 | + "An unknown error occurred while counting tokens. Further information may be available in console.": "Неизвестная ошибка при подсчёте токенов. Проверьте консоль, возможно, подробная информация есть там.", | |
| 1767 | + "Encountered an error while processing your request.": "При обработке вашего запроса возникла ошибка.", | |
| 1768 | + "Check you have credits available on your": "Убедитесь, что на вашем", | |
| 1769 | + "OpenAI account quora_error": "аккаунте OpenAI", | |
| 1770 | + "dot quota_error": "имеется достаточно кредитов.", | |
| 1771 | + "If you have sufficient credits, please try again later.": "Если кредитов достаточно, то повторите попытку позднее.", | |
| 1772 | + "Proxy preset '${0}' not found": "Пресет '${0}' не найден", | |
| 1773 | + "Window.ai returned an error": "Window.ai вернул ошибку", | |
| 1774 | + "Get it here:": "Загрузите здесь:", | |
| 1775 | + "Extension is not installed": "Расширение не установлено", | |
| 1776 | + "Update or remove your reverse proxy settings.": "Измените или удалите ваши настройки прокси.", | |
| 1777 | + "An error occurred while importing prompts. More info available in console.": "В процессе импорта произошла ошибка. Подробную информацию см. в консоли.", | |
| 1778 | + "Could not import prompts. Export failed validation.": "Не удалось импортировать промпты. Не пройдена валидация при экспорте.", | |
| 1779 | + "Prompt import complete.": "Импорт завершён.", | |
| 1780 | + "Are you sure you want to delete this prompt?": "Вы точно хотите удалить этот промпт?", | |
| 1781 | + "Existing prompts with the same ID will be overridden. Do you want to proceed?": "Имеющиеся промпты с совпадающими идентификаторами будут перезаписаны. Продолжить?", | |
| 1782 | + "This will reset the prompt order for this character. You will not lose any prompts.": "Будет сброшен порядок промптов для этого персонажа. Сами промпты вы не потеряете.", | |
| 1783 | + "Note:": "Примечание:", | |
| 1784 | + "this chat is temporary and will be deleted as soon as you leave it.": "это временный чат, он будет удалён, как только вы из него выйдете.", | |
| 1785 | + "help_hotkeys_20": "Горячие клавиши для разметки", | |
| 1786 | + "help_hotkeys_21": "Работают в окне ввода чата, а также в полях, отмеченных этим значком:", | |
| 1787 | + "help_hotkeys_22": "**полужирный**", | |
| 1788 | + "help_hotkeys_23": "*курсив*", | |
| 1789 | + "help_hotkeys_24": "__подчёркивание__", | |
| 1790 | + "help_hotkeys_25": "`inline-код`", | |
| 1791 | + "help_hotkeys_26": "~~зачёркнутый~~", | |
| 1792 | + "ext_regex_only_format_visual_desc": "Содержимое файла с историей чата останется нетронутым, изменения будут лишь визуальными (в UI).", | |
| 1793 | + "Could not convert file": "Не удалось сконвертировать файл", | |
| 1794 | + "Could not upload file": "Не удалось загрузить файл", | |
| 1795 | + "Could not download file": "Не удалось скачать файл", | |
| 1796 | + "File is too big. Maximum size is ${0}.": "Слишком большой файл. Максимальный размер: ${0}.", | |
| 1797 | + "Binary files are not supported. Select a text file or image.": "Бинарные файлы не поддерживаются. Выберите текстовый файл или изображение.", | |
| 1798 | + "No character or group selected": "Не выбрано ни одного персонажа или группы", | |
| 1799 | + "Could not delete file": "Не удалось удалить файл", | |
| 1800 | + "No attachments selected.": "Вложение не выбрано.", | |
| 1801 | + "Data Bank": "Банк данных", | |
| 1802 | + "No files were scraped.": "Скрапинг не выполнен.", | |
| 1803 | + "Scraped ${0} files from ${1} to ${2}.": "Соскраплено из ${0} файлов из ${1} в ${2}.", | |
| 1804 | + "Check browser console for details.": "Подробности см. в консоли браузера.", | |
| 1805 | + "Scraping failed": "Ошибка скрапинга", | |
| 1806 | + "External media has been blocked": "Внешние медиа отключены", | |
| 1807 | + "Use the 'Ext. Media' button to allow it. Click on this message to dismiss.": "Разрешить можно с помощью кнопки 'Внешн. медиа'. Нажмите на это сообщение, чтобы его скрыть.", | |
| 1808 | + "Couldn't get CSRF token. Please refresh the page.": "Не удалось получить CSRF токен. Попробуйте перезагрузить страницу.", | |
| 1809 | + "Error": "Ошибка", | |
| 1810 | + "API Error": "Ошибка API", | |
| 1811 | + "Please wait until the chat is saved before switching characters.": "Пожалуйста, дождитесь сохранения чата, прежде чем переключать персонажа.", | |
| 1812 | + "Your chat is still saving...": "Чат всё ещё сохраняется...", | |
| 1813 | + "Character ${0} not found in the list": "Персонаж ${0} не найден в списке", | |
| 1814 | + "Streaming is enabled, but the version of Kobold used does not support token streaming.": "Включён стриминг текста, но ваша версия Kobold не поддерживает стриминг токенов.", | |
| 1815 | + "Streaming is not supported for the Legacy API. Update Ooba and use new API to enable streaming.": "Для устаревшего API стриминг недоступен. Обновите oobaboga и используйте новый API, чтобы включить стриминг.", | |
| 1816 | + "Verify that the server is running and accessible.": "Убедитесь, что сервер запущен и доступен по сети.", | |
| 1817 | + "ST Server cannot be reached": "Не удалось соединиться с сервером ST", | |
| 1818 | + "You must first select a character to duplicate!": "Вы не выбрали персонажа, которого хотите клонировать!", | |
| 1819 | + "Character Duplicated": "Персонаж склонирован", | |
| 1820 | + "No character name provided.": "Вы не ввели имя персонажа.", | |
| 1821 | + "Rename Character": "Переименование", | |
| 1822 | + "No character selected.": "Вы не выбрали персонажа.", | |
| 1823 | + "New name:": "Новое имя:", | |
| 1824 | + "Same character name provided, so name did not change.": "Введено то же самое имя, ничего не изменилось.", | |
| 1825 | + "Character renamed and past chats updated!": "Персонаж переименован, а чаты обновлены!", | |
| 1826 | + "Character renamed!": "Персонаж переименован!", | |
| 1827 | + "Something went wrong. The page will be reloaded.": "Что-то пошло не так. Страница будет перезагружена.", | |
| 1828 | + "Past chat could not be updated: ${0}": "Не удалось обновить чат ${0}", | |
| 1829 | + "Trying to save group chat with regular saveChat function. Aborting to prevent corruption.": "Произошла попытка сохранения группового чата функцией saveChat. Откатываем изменения, чтобы предотвратить потерю данных.", | |
| 1830 | + "Check the server connection and reload the page to prevent data loss.": "Проверьте связь с сервером и перезагрузите страницу, чтобы избежать потери данных.", | |
| 1831 | + "Chat could not be saved": "Не удалось сохранить чат", | |
| 1832 | + "Settings could not be loaded after multiple attempts. Please try again later.": "Не удалось загрузить настройки за несколько попыток. Попробуйте позднее.", | |
| 1833 | + "Settings could not be saved": "Не удалось сохранить настройки", | |
| 1834 | + "Could not load chat data. Try reloading the page.": "Не удалось загрузить чат. Попробуйте обновить страницу.", | |
| 1835 | + "Invalid process (no 'type')": "Невалидный процесс (нет параметра 'type')", | |
| 1836 | + "Character Deleted: ${0}": "Персонаж удалён: ${0}", | |
| 1837 | + "Character Created: ${0}": "Персонаж создан: ${0}", | |
| 1838 | + "Group Created": "Группа создана", | |
| 1839 | + "Group Deleted": "Группа удалена", | |
| 1840 | + "Character Imported: ${0}": "Персонаж импортирован: ${0}", | |
| 1841 | + "Invalid swipe ID: ${0}": "Некорректный идентификатор свайпа: ${0}", | |
| 1842 | + "No messages to delete swipes from.": "Сообщение, из которого требуется удалить свайп, не найдено.", | |
| 1843 | + "Can't delete the last swipe.": "Невозможно удалить единственный свайп.", | |
| 1844 | + "GUI Settings preset is not supported for Horde. Please select another preset.": "Для Horde не поддерживаются пресеты настроек GUI. Пожалуйста, выберите другой пресет.", | |
| 1845 | + "Embedded lorebook will be removed from this character.": "Встроенный лорбук будет удалён из персонажа.", | |
| 1846 | + "Name is required": "Введите имя", | |
| 1847 | + "Cannot create characters while generating. Stop the request and try again.": "Во время генерации ответа создать персонажа невозможно. Остановите запрос и повторите попытку.", | |
| 1848 | + "Creation aborted": "Процесс создания прерван", | |
| 1849 | + "Failed to create character": "Не удалось создать персонажа", | |
| 1850 | + "Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.": "Что-то пошло не так в процессе сохранения персонажа, либо вы загрузили файл некорректного формата. Проверьте, что изображение точно не в формате webp.", | |
| 1851 | + "Context template '${0}' not found": "Шаблон контекста '${0}' не найден", | |
| 1852 | + "Instruct template '${0}' not found": "Шаблон Instruct-режима '${0}' не найден", | |
| 1853 | + "Error: ${0} is not a valid API": "Ошибка: ${0} не является валидным API", | |
| 1854 | + "API set to ${0}, trying to connect..": "Установлено API ${0}, пробуем подключиться...", | |
| 1855 | + "Unsupported file type: ": "Неподдерживаемый тип файла: ", | |
| 1856 | + "Cannot import characters while generating. Stop the request and try again.": "Во время генерации ответа импорт персонажа невозможен. Остановите запрос и повторите попытку.", | |
| 1857 | + "Import aborted": "Процесс импорта прерван", | |
| 1858 | + "The file is likely invalid or corrupted.": "Вероятно, файл невалиден или повреждён.", | |
| 1859 | + "Could not import character": "Не удалось импортировать персонажа", | |
| 1860 | + "Cannot run /impersonate command while the reply is being generated.": "Во время генерации ответа выполнить /impersonate невозможно.", | |
| 1861 | + "Name must be provided as an argument to rename this chat.": "Для переименования чата необходимо предоставить новое имя в качестве аргумента.", | |
| 1862 | + "No chat selected that can be renamed.": "Чат, который требуется переименовать, не найден.", | |
| 1863 | + "Successfully renamed chat to: ${0}": "Чат успешно переименован в: ${0}", | |
| 1864 | + "Character ${0} not found. Skipping deletion.": "Персонаж ${0} не найден. Удаление пропускается.", | |
| 1865 | + "Failed to delete character": "При удалении персонажа произошло ошибка", | |
| 1866 | + "Are you sure you want to duplicate this character?": "Вы точно хотите клонировать этого персонажа?", | |
| 1867 | + "If you just want to start a new chat with the same character...": "Если вы хотите просто создать новый чат, воспользуйтесь кнопкой \"Начать новый чат\" в меню слева внизу.", | |
| 1868 | + "THIS IS PERMANENT!": "ОТМЕНИТЬ БУДЕТ НЕВОЗМОЖНО!", | |
| 1869 | + "Also delete the chat files": "Также удалить файлы чатов", | |
| 1870 | + "Delete the character?": "Удалить персонажа?", | |
| 1871 | + "Not a valid number": "Некорректное число", | |
| 1872 | + "Author's Note depth updated": "Глубина заметок автора обновлена", | |
| 1873 | + "Author's Note frequency updated": "Частота заметок автора обновлена", | |
| 1874 | + "Not a valid position": "Некорректная позиция", | |
| 1875 | + "Author's Note position updated": "Позиция заметок автора обновлена", | |
| 1876 | + "Something went wrong. Could not save character's author's note.": "Что-то пошло не так. Не удалось сохранить заметки автора для этого персонажа.", | |
| 1877 | + "Select a character before trying to use Author's Note": "Сначала необходимо выбрать персонажа", | |
| 1878 | + "Author's Note text updated": "Текст заметок автора обновлён", | |
| 1879 | + "Group Validation": "Валидация группы", | |
| 1880 | + "Warning: Listed member ${0} does not exist as a character. It will be removed from the group.": "Предупреждение: персонаж ${0} не существует в виде карточки. Он будет удалён из группы.", | |
| 1881 | + "Group Chat could not be saved": "Не удалось сохранить групповой чат", | |
| 1882 | + "Deleted group member swiped. To get a reply, add them back to the group.": "Вы пытаетесь свайпнуть удалённого члена группы. Чтобы получить ответ, добавьте этого персонажа обратно в группу.", | |
| 1883 | + "Currently no group selected.": "В данный момент не выбрано ни одной группы.", | |
| 1884 | + "Not so fast! Wait for the characters to stop typing before deleting the group.": "Чуть помедленнее! Перед удалением группы дождитесь, пока персонаж закончит печатать.", | |
| 1885 | + "Delete the group?": "Удалить группу?", | |
| 1886 | + "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.": "Вместе с ней будут удалены и все её чаты. Если требуется удалить только один чат, воспользуйтесь кнопкой \"Все чаты\" в меню в левом нижнем углу.", | |
| 1887 | + "Can't peek a character while group reply is being generated": "Невозможно открыть карточку персонажа во время генерации ответа", | |
| 1888 | + "Threshold": "Порог", | |
| 1889 | + "DRY Repetition Penalty": "DRY Штраф за повтор", | |
| 1890 | + "Multiplier": "Множитель", | |
| 1891 | + "DRY_Multiplier_desc": "Поставьте в положение > 0, чтобы включить DRY. Определяет величину штрафа для кратчайшей \"штрафуемой\" строки.", | |
| 1892 | + "DRY_Repetition_Penalty_desc": "DRY налагает штраф на токены, генерация которых приведёт к появлению строки, которая уже была в тексте раньше. Установите множитель = 0, чтобы отключить.", | |
| 1893 | + "Base": "Основание", | |
| 1894 | + "DRY_Base_desc": "Определяет, насколько быстро возрастает штраф с увеличением длины строки.", | |
| 1895 | + "Allowed Length": "Допустимая длина", | |
| 1896 | + "DRY_Allowed_Length_desc": "Длина повторяющейся строки, при превышении которой DRY начинает налагать штраф." | |
| 1751 | 1897 | } |
| @@ -391,8 +391,8 @@ DOMPurify.addHook('uponSanitizeElement', (node, _, config) => { | ||
| 391 | 391 | |
| 392 | 392 | if (localStorage.getItem(warningShownKey) === null) { |
| 393 | 393 | const warningToast = toastr.warning( |
| 394 | 394 | 't`Use the "'Ext. Media"' button to allow it. Click on this message to dismiss.'`, |
| 395 | 395 | 't`External media has been blocked'`, |
| 396 | 396 | { |
| 397 | 397 | timeOut: 0, |
| 398 | 398 | preventDuplicates: true, |
| @@ -933,7 +933,7 @@ async function firstLoadInit() { | ||
| 933 | 933 | token = tokenData.token; |
| 934 | 934 | } catch { |
| 935 | 935 | hideLoader(); |
| 936 | 936 | toastr.error('t`Couldn\'t get CSRF token. Please refresh the page.'`, 't`Error'`, { timeOut: 0, extendedTimeOut: 0, preventDuplicates: true }); |
| 937 | 937 | throw new Error('Initialization failed'); |
| 938 | 938 | } |
| 939 | 939 | |
| @@ -1149,7 +1149,7 @@ async function getStatusKobold() { | ||
| 1149 | 1149 | |
| 1150 | 1150 | // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. |
| 1151 | 1151 | if (online_status === 'no_connection' && data.response) { |
| 1152 | 1152 | toastr.error(data.response, 't`API Error'`, { timeOut: 5000, preventDuplicates: true }); |
| 1153 | 1153 | } |
| 1154 | 1154 | } catch (err) { |
| 1155 | 1155 | console.error('Error getting status', err); |
| @@ -1235,7 +1235,7 @@ async function getStatusTextgen() { | ||
| 1235 | 1235 | |
| 1236 | 1236 | // We didn't get a 200 status code, but the endpoint has an explanation. Which means it DID connect, but I digress. |
| 1237 | 1237 | if (online_status === 'no_connection' && data.response) { |
| 1238 | 1238 | toastr.error(data.response, 't`API Error'`, { timeOut: 5000, preventDuplicates: true }); |
| 1239 | 1239 | } |
| 1240 | 1240 | } catch (err) { |
| 1241 | 1241 | if (err instanceof AbortReason) { |
| @@ -1287,7 +1287,7 @@ export async function selectCharacterById(id) { | ||
| 1287 | 1287 | } |
| 1288 | 1288 | |
| 1289 | 1289 | if (isChatSaving) { |
| 1290 | 1290 | toastr.info('t`Please wait until the chat is saved before switching characters.'`, 't`Your chat is still saving...'`); |
| 1291 | 1291 | return; |
| 1292 | 1292 | } |
| 1293 | 1293 | |
| @@ -1641,7 +1641,7 @@ export async function getOneCharacter(avatarUrl) { | ||
| 1641 | 1641 | if (indexOf !== -1) { |
| 1642 | 1642 | characters[indexOf] = getData; |
| 1643 | 1643 | } else { |
| 1644 | 1644 | toastr.error(t`Character ${avatarUrl} not found in the list`, 't`Error'`, { timeOut: 5000, preventDuplicates: true }); |
| 1645 | 1645 | } |
| 1646 | 1646 | } |
| 1647 | 1647 | } |
| @@ -3408,7 +3408,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3408 | 3408 | await eventSource.emit(event_types.GENERATION_AFTER_COMMANDS, type, { automatic_trigger, force_name2, quiet_prompt, quietToLoud, skipWIAN, force_chid, signal, quietImage }, dryRun); |
| 3409 | 3409 | |
| 3410 | 3410 | if (main_api == 'kobold' && kai_settings.streaming_kobold && !kai_flags.can_use_streaming) { |
| 3411 | 3411 | toastr.error('t`Streaming is enabled, but the version of Kobold used does not support token streaming.'`, undefined, { timeOut: 10000, preventDuplicates: true }); |
| 3412 | 3412 | unblockGeneration(type); |
| 3413 | 3413 | return Promise.resolve(); |
| 3414 | 3414 | } |
| @@ -3417,7 +3417,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3417 | 3417 | textgen_settings.streaming && |
| 3418 | 3418 | textgen_settings.legacy_api && |
| 3419 | 3419 | textgen_settings.type === OOBA) { |
| 3420 | 3420 | toastr.error('t`Streaming is not supported for the Legacy API. Update Ooba and use new API to enable streaming.'`, undefined, { timeOut: 10000, preventDuplicates: true }); |
| 3421 | 3421 | unblockGeneration(type); |
| 3422 | 3422 | return Promise.resolve(); |
| 3423 | 3423 | } |
| @@ -3433,7 +3433,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 3433 | 3433 | |
| 3434 | 3434 | if (!pingResult) { |
| 3435 | 3435 | unblockGeneration(type); |
| 3436 | 3436 | toastr.error('t`Verify that the server is running and accessible.'`, 't`ST Server cannot be reached'`); |
| 3437 | 3437 | throw new Error('Server unreachable'); |
| 3438 | 3438 | } |
| 3439 | 3439 | |
| @@ -4461,7 +4461,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4461 | 4461 | generatedPromptCache = ''; |
| 4462 | 4462 | |
| 4463 | 4463 | if (data?.response) { |
| 4464 | 4464 | toastr.error(data.response, 't`API Error'`, { preventDuplicates: true }); |
| 4465 | 4465 | } |
| 4466 | 4466 | throw new Error(data?.response); |
| 4467 | 4467 | } |
| @@ -4552,7 +4552,7 @@ export async function Generate(type, { automatic_trigger, force_name2, quiet_pro | ||
| 4552 | 4552 | |
| 4553 | 4553 | function onError(exception) { |
| 4554 | 4554 | if (typeof exception?.error?.message === 'string') { |
| 4555 | 4555 | toastr.error(exception.error.message, 't`Error'`, { timeOut: 10000, extendedTimeOut: 20000 }); |
| 4556 | 4556 | } |
| 4557 | 4557 | |
| 4558 | 4558 | generatedPromptCache = ''; |
| @@ -4956,7 +4956,7 @@ function addChatsSeparator(mesSendString) { | ||
| 4956 | 4956 | |
| 4957 | 4957 | async function duplicateCharacter() { |
| 4958 | 4958 | if (!this_chid) { |
| 4959 | 4959 | toastr.warning('t`You must first select a character to duplicate!'`); |
| 4960 | 4960 | return ''; |
| 4961 | 4961 | } |
| 4962 | 4962 | |
| @@ -4975,7 +4975,7 @@ async function duplicateCharacter() { | ||
| 4975 | 4975 | body: JSON.stringify(body), |
| 4976 | 4976 | }); |
| 4977 | 4977 | if (response.ok) { |
| 4978 | 4978 | toastr.success('t`Character Duplicated'`); |
| 4979 | 4979 | const data = await response.json(); |
| 4980 | 4980 | await eventSource.emit(event_types.CHARACTER_DUPLICATED, { oldAvatar: body.avatar_url, newAvatar: data.path }); |
| 4981 | 4981 | await getCharacters(); |
| @@ -5822,23 +5822,23 @@ export function setSendButtonState(value) { | ||
| 5822 | 5822 | |
| 5823 | 5823 | export async function renameCharacter(name = null, { silent = false, renameChats = null } = {}) { |
| 5824 | 5824 | if (!name && silent) { |
| 5825 | 5825 | toastr.warning('t`No character name provided.'`, 't`Rename Character'`); |
| 5826 | 5826 | return false; |
| 5827 | 5827 | } |
| 5828 | 5828 | if (this_chid === undefined) { |
| 5829 | 5829 | toastr.warning('t`No character selected.'`, 't`Rename Character'`); |
| 5830 | 5830 | return false; |
| 5831 | 5831 | } |
| 5832 | 5832 | |
| 5833 | 5833 | const oldAvatar = characters[this_chid].avatar; |
| 5834 | 5834 | const newValue = name || await callGenericPopup('<h3>' + t`New name:` + '</h3>', POPUP_TYPE.INPUT, characters[this_chid].name); |
| 5835 | 5835 | |
| 5836 | 5836 | if (!newValue) { |
| 5837 | 5837 | toastr.warning('t`No character name provided.'`, 't`Rename Character'`); |
| 5838 | 5838 | return false; |
| 5839 | 5839 | } |
| 5840 | 5840 | if (newValue === characters[this_chid].name) { |
| 5841 | 5841 | toastr.info('t`Same character name provided, so name did not change.'`, 't`Rename Character'`); |
| 5842 | 5842 | return false; |
| 5843 | 5843 | } |
| 5844 | 5844 | |
| @@ -5885,9 +5885,9 @@ export async function renameCharacter(name = null, { silent = false, renameChats | ||
| 5885 | 5885 | if (renamePastChatsConfirm) { |
| 5886 | 5886 | await renamePastChats(newAvatar, newValue); |
| 5887 | 5887 | await reloadCurrentChat(); |
| 5888 | 5888 | toastr.success('t`Character renamed and past chats updated!'`, 't`Rename Character'`); |
| 5889 | 5889 | } else { |
| 5890 | 5890 | toastr.success('t`Character renamed!'`, 't`Rename Character'`); |
| 5891 | 5891 | } |
| 5892 | 5892 | } |
| 5893 | 5893 | else { |
| @@ -5900,8 +5900,8 @@ export async function renameCharacter(name = null, { silent = false, renameChats | ||
| 5900 | 5900 | } |
| 5901 | 5901 | catch (error) { |
| 5902 | 5902 | // Reloading to prevent data corruption |
| 5903 | 5903 | if (!silent) await callPopup('t`Something went wrong. The page will be reloaded.'`, 'text'); |
| 5904 | 5904 | else toastr.error('t`Something went wrong. The page will be reloaded.'`, 't`Rename Character'`); |
| 5905 | 5905 | |
| 5906 | 5906 | console.log('Renaming character error:', error); |
| 5907 | 5907 | location.reload(); |
| @@ -5958,7 +5958,7 @@ async function renamePastChats(newAvatar, newValue) { | ||
| 5958 | 5958 | } |
| 5959 | 5959 | } |
| 5960 | 5960 | } catch (error) { |
| 5961 | 5961 | toastr.error(t`Past chat could not be updated: ${file_name}`); |
| 5962 | 5962 | console.error(error); |
| 5963 | 5963 | } |
| 5964 | 5964 | } |
| @@ -6007,7 +6007,7 @@ export async function saveChat(chatName, withMetadata, mesId) { | ||
| 6007 | 6007 | characters[this_chid]['date_last_chat'] = Date.now(); |
| 6008 | 6008 | chat.forEach(function (item, i) { |
| 6009 | 6009 | if (item['is_group']) { |
| 6010 | 6010 | toastr.error('t`Trying to save group chat with regular saveChat function. Aborting to prevent corruption.'`); |
| 6011 | 6011 | throw new Error('Group chat saved from saveChat'); |
| 6012 | 6012 | } |
| 6013 | 6013 | /* |
| @@ -6052,7 +6052,7 @@ export async function saveChat(chatName, withMetadata, mesId) { | ||
| 6052 | 6052 | contentType: 'application/json', |
| 6053 | 6053 | success: function (data) { }, |
| 6054 | 6054 | error: function (jqXHR, exception) { |
| 6055 | 6055 | toastr.error('t`Check the server connection and reload the page to prevent data loss.'`, 't`Chat could not be saved'`); |
| 6056 | 6056 | console.log(exception); |
| 6057 | 6057 | console.log(jqXHR); |
| 6058 | 6058 | }, |
| @@ -6449,7 +6449,7 @@ export async function getSettings() { | ||
| 6449 | 6449 | |
| 6450 | 6450 | if (!response.ok) { |
| 6451 | 6451 | reloadLoop(); |
| 6452 | 6452 | toastr.error('t`Settings could not be loaded after multiple attempts. Please try again later.'`); |
| 6453 | 6453 | throw new Error('Error getting settings'); |
| 6454 | 6454 | } |
| 6455 | 6455 | |
| @@ -6676,7 +6676,7 @@ export async function saveSettings(type) { | ||
| 6676 | 6676 | eventSource.emit(event_types.SETTINGS_UPDATED); |
| 6677 | 6677 | }, |
| 6678 | 6678 | error: function (jqXHR, exception) { |
| 6679 | 6679 | toastr.error('t`Check the server connection and reload the page to prevent data loss.'t`, 't`Settings could not be saved'`); |
| 6680 | 6680 | console.log(exception); |
| 6681 | 6681 | console.log(jqXHR); |
| 6682 | 6682 | }, |
| @@ -6942,7 +6942,7 @@ export async function displayPastChats() { | ||
| 6942 | 6942 | const data = await (selected_group ? getGroupPastChats(selected_group) : getPastCharacterChats()); |
| 6943 | 6943 | |
| 6944 | 6944 | if (!data) { |
| 6945 | 6945 | toastr.error('t`Could not load chat data. Try reloading the page.'`); |
| 6946 | 6946 | return; |
| 6947 | 6947 | } |
| 6948 | 6948 | |
| @@ -7075,7 +7075,7 @@ export function selectRightMenuWithAnimation(selectedMenuId) { | ||
| 7075 | 7075 | |
| 7076 | 7076 | export function select_rm_info(type, charId, previousCharId = null) { |
| 7077 | 7077 | if (!type) { |
| 7078 | 7078 | toastr.error('t`Invalid process (no \'type\')'`); |
| 7079 | 7079 | return; |
| 7080 | 7080 | } |
| 7081 | 7081 | if (type !== 'group_create') { |
| @@ -7083,20 +7083,20 @@ export function select_rm_info(type, charId, previousCharId = null) { | ||
| 7083 | 7083 | } |
| 7084 | 7084 | |
| 7085 | 7085 | if (type === 'char_delete') { |
| 7086 | 7086 | toastr.warning(t`Character Deleted: ${displayName}`); |
| 7087 | 7087 | } |
| 7088 | 7088 | if (type === 'char_create') { |
| 7089 | 7089 | toastr.success(t`Character Created: ${displayName}`); |
| 7090 | 7090 | } |
| 7091 | 7091 | if (type === 'group_create') { |
| 7092 | 7092 | toastr.success('t`Group Created'`); |
| 7093 | 7093 | } |
| 7094 | 7094 | if (type === 'group_delete') { |
| 7095 | 7095 | toastr.warning('t`Group Deleted'`); |
| 7096 | 7096 | } |
| 7097 | 7097 | |
| 7098 | 7098 | if (type === 'char_import') { |
| 7099 | 7099 | toastr.success(t`Character Imported: ${displayName}`); |
| 7100 | 7100 | } |
| 7101 | 7101 | |
| 7102 | 7102 | selectRightMenuWithAnimation('rm_characters_block'); |
| @@ -7554,25 +7554,25 @@ export function hideSwipeButtons() { | ||
| 7554 | 7554 | */ |
| 7555 | 7555 | export async function deleteSwipe(swipeId = null) { |
| 7556 | 7556 | if (swipeId && (isNaN(swipeId) || swipeId < 0)) { |
| 7557 | 7557 | toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`); |
| 7558 | 7558 | return; |
| 7559 | 7559 | } |
| 7560 | 7560 | |
| 7561 | 7561 | const lastMessage = chat[chat.length - 1]; |
| 7562 | 7562 | if (!lastMessage || !Array.isArray(lastMessage.swipes) || !lastMessage.swipes.length) { |
| 7563 | 7563 | toastr.warning('t`No messages to delete swipes from.'`); |
| 7564 | 7564 | return; |
| 7565 | 7565 | } |
| 7566 | 7566 | |
| 7567 | 7567 | if (lastMessage.swipes.length <= 1) { |
| 7568 | 7568 | toastr.warning('t`Can\'t delete the last swipe.'`); |
| 7569 | 7569 | return; |
| 7570 | 7570 | } |
| 7571 | 7571 | |
| 7572 | 7572 | swipeId = swipeId ?? lastMessage.swipe_id; |
| 7573 | 7573 | |
| 7574 | 7574 | if (swipeId < 0 || swipeId >= lastMessage.swipes.length) { |
| 7575 | 7575 | toastr.warning(t`Invalid swipe ID: ${swipeId + 1}`); |
| 7576 | 7576 | return; |
| 7577 | 7577 | } |
| 7578 | 7578 | |
| @@ -7711,7 +7711,7 @@ export function setGenerationProgress(progress) { | ||
| 7711 | 7711 | |
| 7712 | 7712 | function isHordeGenerationNotAllowed() { |
| 7713 | 7713 | if (main_api == 'koboldhorde' && preset_settings == 'gui') { |
| 7714 | 7714 | toastr.error('t`GUI Settings preset is not supported for Horde. Please select another preset.'`); |
| 7715 | 7715 | return true; |
| 7716 | 7716 | } |
| 7717 | 7717 | |
| @@ -7760,7 +7760,7 @@ function openCharacterWorldPopup() { | ||
| 7760 | 7760 | } |
| 7761 | 7761 | |
| 7762 | 7762 | $('#character_json_data').val(JSON.stringify(data)); |
| 7763 | 7763 | toastr.info('t`Embedded lorebook will be removed from this character.'`); |
| 7764 | 7764 | } catch { |
| 7765 | 7765 | console.error('Failed to parse character JSON data.'); |
| 7766 | 7766 | } |
| @@ -7951,11 +7951,11 @@ async function createOrEditCharacter(e) { | ||
| 7951 | 7951 | |
| 7952 | 7952 | if ($('#form_create').attr('actiontype') == 'createcharacter') { |
| 7953 | 7953 | if (String($('#character_name_pole').val()).length === 0) { |
| 7954 | 7954 | toastr.error('t`Name is required'`); |
| 7955 | 7955 | return; |
| 7956 | 7956 | } |
| 7957 | 7957 | if (is_group_generating || is_send_press) { |
| 7958 | 7958 | toastr.error('t`Cannot create characters while generating. Stop the request and try again.'`, 't`Creation aborted'`); |
| 7959 | 7959 | return; |
| 7960 | 7960 | } |
| 7961 | 7961 | try { |
| @@ -8039,7 +8039,7 @@ async function createOrEditCharacter(e) { | ||
| 8039 | 8039 | |
| 8040 | 8040 | } catch (error) { |
| 8041 | 8041 | console.error('Error creating character', error); |
| 8042 | 8042 | toastr.error('t`Failed to create character'`); |
| 8043 | 8043 | } |
| 8044 | 8044 | } else { |
| 8045 | 8045 | try { |
| @@ -8098,7 +8098,7 @@ async function createOrEditCharacter(e) { | ||
| 8098 | 8098 | } |
| 8099 | 8099 | } catch (error) { |
| 8100 | 8100 | console.log(error); |
| 8101 | 8101 | toastr.error('t`Something went wrong while saving the character, or the image file provided was in an invalid format. Double check that the image is not a webp.'`); |
| 8102 | 8102 | } |
| 8103 | 8103 | } |
| 8104 | 8104 | } |
| @@ -8604,7 +8604,7 @@ async function selectContextCallback(args, name) { | ||
| 8604 | 8604 | const result = fuse.search(name); |
| 8605 | 8605 | |
| 8606 | 8606 | if (result.length === 0) { |
| 8607 | 8607 | !quiet && toastr.warning(t`Context template "'${name}"' not found`); |
| 8608 | 8608 | return ''; |
| 8609 | 8609 | } |
| 8610 | 8610 | |
| @@ -8624,7 +8624,7 @@ async function selectInstructCallback(args, name) { | ||
| 8624 | 8624 | const result = fuse.search(name); |
| 8625 | 8625 | |
| 8626 | 8626 | if (result.length === 0) { |
| 8627 | 8627 | !quiet && toastr.warning(t`Instruct template "'${name}"' not found`); |
| 8628 | 8628 | return ''; |
| 8629 | 8629 | } |
| 8630 | 8630 | |
| @@ -8676,7 +8676,7 @@ async function connectAPISlash(args, text) { | ||
| 8676 | 8676 | |
| 8677 | 8677 | const apiConfig = CONNECT_API_MAP[text.toLowerCase()]; |
| 8678 | 8678 | if (!apiConfig) { |
| 8679 | 8679 | toastr.error(t`Error: ${text} is not a valid API`); |
| 8680 | 8680 | return ''; |
| 8681 | 8681 | } |
| 8682 | 8682 | |
| @@ -8705,7 +8705,7 @@ async function connectAPISlash(args, text) { | ||
| 8705 | 8705 | } |
| 8706 | 8706 | |
| 8707 | 8707 | const quiet = isTrueBoolean(args?.quiet); |
| 8708 | 8708 | const toast = quiet ? jQuery() : toastr.info(t`API set to ${text}, trying to connect..`); |
| 8709 | 8709 | |
| 8710 | 8710 | try { |
| 8711 | 8711 | await waitUntilCondition(() => online_status !== 'no_connection', 10000, 100); |
| @@ -8744,7 +8744,7 @@ export async function processDroppedFiles(files, data = new Map()) { | ||
| 8744 | 8744 | const preservedName = data instanceof Map && data.get(file); |
| 8745 | 8745 | await importCharacter(file, preservedName); |
| 8746 | 8746 | } else { |
| 8747 | 8747 | toastr.warning('t`Unsupported file type: '` + file.name); |
| 8748 | 8748 | } |
| 8749 | 8749 | } |
| 8750 | 8750 | } |
| @@ -8757,7 +8757,7 @@ export async function processDroppedFiles(files, data = new Map()) { | ||
| 8757 | 8757 | */ |
| 8758 | 8758 | async function importCharacter(file, preserveFileName = '') { |
| 8759 | 8759 | if (is_group_generating || is_send_press) { |
| 8760 | 8760 | toastr.error('t`Cannot import characters while generating. Stop the request and try again.'`, 't`Import aborted'`); |
| 8761 | 8761 | throw new Error('Cannot import character while generating'); |
| 8762 | 8762 | } |
| 8763 | 8763 | |
| @@ -8784,7 +8784,7 @@ async function importCharacter(file, preserveFileName = '') { | ||
| 8784 | 8784 | }); |
| 8785 | 8785 | |
| 8786 | 8786 | if (data.error) { |
| 8787 | 8787 | toastr.error('t`The file is likely invalid or corrupted.'`, 't`Could not import character'`); |
| 8788 | 8788 | return; |
| 8789 | 8789 | } |
| 8790 | 8790 | |
| @@ -8837,7 +8837,7 @@ async function doImpersonate(args, prompt) { | ||
| 8837 | 8837 | await waitUntilCondition(() => !is_send_press && !is_group_generating, 10000, 100); |
| 8838 | 8838 | } catch { |
| 8839 | 8839 | console.warn('Timeout waiting for generation unlock'); |
| 8840 | 8840 | toastr.warning('t`Cannot run /impersonate command while the reply is being generated.'`); |
| 8841 | 8841 | return ''; |
| 8842 | 8842 | } |
| 8843 | 8843 | |
| @@ -8899,19 +8899,19 @@ async function doDeleteChat() { | ||
| 8899 | 8899 | |
| 8900 | 8900 | async function doRenameChat(_, chatName) { |
| 8901 | 8901 | if (!chatName) { |
| 8902 | 8902 | toastr.warning('t`Name must be provided as an argument to rename this chat.'`); |
| 8903 | 8903 | return ''; |
| 8904 | 8904 | } |
| 8905 | 8905 | |
| 8906 | 8906 | const currentChatName = getCurrentChatId(); |
| 8907 | 8907 | if (!currentChatName) { |
| 8908 | 8908 | toastr.warning('t`No chat selected that can be renamed.'`); |
| 8909 | 8909 | return ''; |
| 8910 | 8910 | } |
| 8911 | 8911 | |
| 8912 | 8912 | await renameChat(currentChatName, chatName); |
| 8913 | 8913 | |
| 8914 | 8914 | toastr.success(t`Successfully renamed chat to: ${chatName}`); |
| 8915 | 8915 | return ''; |
| 8916 | 8916 | } |
| 8917 | 8917 | |
| @@ -9026,7 +9026,7 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {}) | ||
| 9026 | 9026 | for (const key of characterKey) { |
| 9027 | 9027 | const character = characters.find(x => x.avatar == key); |
| 9028 | 9028 | if (!character) { |
| 9029 | 9029 | toastr.warning(t`Character ${key} not found. Skipping deletion.`); |
| 9030 | 9030 | continue; |
| 9031 | 9031 | } |
| 9032 | 9032 | |
| @@ -9043,7 +9043,7 @@ export async function deleteCharacter(characterKey, { deleteChats = true } = {}) | ||
| 9043 | 9043 | }); |
| 9044 | 9044 | |
| 9045 | 9045 | if (!response.ok) { |
| 9046 | 9046 | toastr.error(`${response.status} ${response.statusText}`, 't`Failed to delete character'`); |
| 9047 | 9047 | continue; |
| 9048 | 9048 | } |
| 9049 | 9049 | |
| @@ -9802,12 +9802,7 @@ jQuery(async function () { | ||
| 9802 | 9802 | |
| 9803 | 9803 | let deleteChats = false; |
| 9804 | 9804 | |
| 9805 | 9805 | const confirm = await Popup.show.confirm('t`Delete the character?`, await renderTemplateAsync('deleteConfirm'), `{ |
| 9806 | - <b>THIS IS PERMANENT!<br><br> | |
| 9807 | - <label for="del_char_checkbox" class="checkbox_label justifyCenter"> | |
| 9808 | - <input type="checkbox" id="del_char_checkbox" /> | |
| 9809 | - <small>Also delete the chat files</small> | |
| 9810 | - </label></b>`, { | |
| 9811 | 9806 | onClose: () => deleteChats = !!$('#del_char_checkbox').prop('checked'), |
| 9812 | 9807 | }); |
| 9813 | 9808 | if (!confirm) { |
| @@ -8,6 +8,7 @@ import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; | ||
| 8 | 8 | import { debounce_timeout } from './constants.js'; |
| 9 | 9 | import { renderTemplateAsync } from './templates.js'; |
| 10 | 10 | import { Popup } from './popup.js'; |
| 11 | +import { t } from './i18n.js'; | |
| 11 | 12 | |
| 12 | 13 | function debouncePromise(func, delay) { |
| 13 | 14 | let timeoutId; |
| @@ -455,7 +456,7 @@ class PromptManager { | ||
| 455 | 456 | |
| 456 | 457 | // Delete selected prompt from list form and close edit form |
| 457 | 458 | this.handleDeletePrompt = async (event) => { |
| 458 | 459 | Popup.show.confirm('t`Are you sure you want to delete this prompt?'`, null).then((userChoice) => { |
| 459 | 460 | if (!userChoice) return; |
| 460 | 461 | const promptID = document.getElementById(this.configuration.prefix + 'prompt_manager_footer_append_prompt').value; |
| 461 | 462 | const prompt = this.getPromptById(promptID); |
| @@ -531,7 +532,7 @@ class PromptManager { | ||
| 531 | 532 | |
| 532 | 533 | // Import prompts for the selected character |
| 533 | 534 | this.handleImport = () => { |
| 534 | 535 | Popup.show.confirm('t`Existing prompts with the same ID will be overridden. Do you want to proceed?'`, null) |
| 535 | 536 | .then(userChoice => { |
| 536 | 537 | if (!userChoice) return; |
| 537 | 538 | |
| @@ -552,7 +553,7 @@ class PromptManager { | ||
| 552 | 553 | const data = JSON.parse(fileContent); |
| 553 | 554 | this.import(data); |
| 554 | 555 | } catch (err) { |
| 555 | 556 | toastr.error('t`An error occurred while importing prompts. More info available in console.'`); |
| 556 | 557 | console.log('An error occurred while importing prompts'); |
| 557 | 558 | console.log(err.toString()); |
| 558 | 559 | } |
| @@ -567,7 +568,7 @@ class PromptManager { | ||
| 567 | 568 | |
| 568 | 569 | // Restore default state of a characters prompt order |
| 569 | 570 | this.handleCharacterReset = () => { |
| 570 | 571 | Popup.show.confirm('t`This will reset the prompt order for this character. You will not lose any prompts.'`, null) |
| 571 | 572 | .then(userChoice => { |
| 572 | 573 | if (!userChoice) return; |
| 573 | 574 | |
| @@ -1649,7 +1650,7 @@ class PromptManager { | ||
| 1649 | 1650 | }; |
| 1650 | 1651 | |
| 1651 | 1652 | if (false === this.validateObject(controlObj, importData)) { |
| 1652 | 1653 | toastr.warning('t`Could not import prompts. Export failed validation.'`); |
| 1653 | 1654 | return; |
| 1654 | 1655 | } |
| 1655 | 1656 | |
| @@ -1672,7 +1673,7 @@ class PromptManager { | ||
| 1672 | 1673 | throw new Error('Prompt order strategy not supported.'); |
| 1673 | 1674 | } |
| 1674 | 1675 | |
| 1675 | 1676 | toastr.success('t`Prompt import complete.'`); |
| 1676 | 1677 | this.saveServiceSettings().then(() => this.render()); |
| 1677 | 1678 | } |
| 1678 | 1679 | |
| @@ -16,6 +16,7 @@ import { SlashCommandParser } from './slash-commands/SlashCommandParser.js'; | ||
| 16 | 16 | import { SlashCommand } from './slash-commands/SlashCommand.js'; |
| 17 | 17 | import { ARGUMENT_TYPE, SlashCommandArgument } from './slash-commands/SlashCommandArgument.js'; |
| 18 | 18 | export { MODULE_NAME as NOTE_MODULE_NAME }; |
| 19 | +import { t } from './i18n.js'; | |
| 19 | 20 | |
| 20 | 21 | const MODULE_NAME = '2_floating_prompt'; // <= Deliberate, for sorting lower than memory |
| 21 | 22 | |
| @@ -37,7 +38,7 @@ const chara_note_position = { | ||
| 37 | 38 | |
| 38 | 39 | function setNoteTextCommand(_, text) { |
| 39 | 40 | $('#extension_floating_prompt').val(text).trigger('input'); |
| 40 | 41 | toastr.success('t`Author\'s Note text updated'`); |
| 41 | 42 | return ''; |
| 42 | 43 | } |
| 43 | 44 | |
| @@ -45,12 +46,12 @@ function setNoteDepthCommand(_, text) { | ||
| 45 | 46 | const value = Number(text); |
| 46 | 47 | |
| 47 | 48 | if (Number.isNaN(value)) { |
| 48 | 49 | toastr.error('t`Not a valid number'`); |
| 49 | 50 | return; |
| 50 | 51 | } |
| 51 | 52 | |
| 52 | 53 | $('#extension_floating_depth').val(Math.abs(value)).trigger('input'); |
| 53 | 54 | toastr.success('t`Author\'s Note depth updated'`); |
| 54 | 55 | return ''; |
| 55 | 56 | } |
| 56 | 57 | |
| @@ -58,12 +59,12 @@ function setNoteIntervalCommand(_, text) { | ||
| 58 | 59 | const value = Number(text); |
| 59 | 60 | |
| 60 | 61 | if (Number.isNaN(value)) { |
| 61 | 62 | toastr.error('t`Not a valid number'`); |
| 62 | 63 | return; |
| 63 | 64 | } |
| 64 | 65 | |
| 65 | 66 | $('#extension_floating_interval').val(Math.abs(value)).trigger('input'); |
| 66 | 67 | toastr.success('t`Author\'s Note frequency updated'`); |
| 67 | 68 | return ''; |
| 68 | 69 | } |
| 69 | 70 | |
| @@ -76,12 +77,12 @@ function setNotePositionCommand(_, text) { | ||
| 76 | 77 | const position = validPositions[text?.trim()]; |
| 77 | 78 | |
| 78 | 79 | if (Number.isNaN(position)) { |
| 79 | 80 | toastr.error('t`Not a valid position'`); |
| 80 | 81 | return; |
| 81 | 82 | } |
| 82 | 83 | |
| 83 | 84 | $(`input[name="extension_floating_position"][value="${position}"]`).prop('checked', true).trigger('input'); |
| 84 | 85 | toastr.info('t`Author\'s Note position updated'`); |
| 85 | 86 | return ''; |
| 86 | 87 | } |
| 87 | 88 | |
| @@ -206,7 +207,7 @@ function onExtensionFloatingCharaPromptInput() { | ||
| 206 | 207 | extension_settings.note.chara.push(tempCharaNote); |
| 207 | 208 | } else { |
| 208 | 209 | console.log('Character author\'s note error: No avatar name key could be found.'); |
| 209 | 210 | toastr.error('t`Something went wrong. Could not save character\'s author\'s note.'`); |
| 210 | 211 | |
| 211 | 212 | // Don't save settings if something went wrong |
| 212 | 213 | return; |
| @@ -397,7 +398,7 @@ function onANMenuItemClick() { | ||
| 397 | 398 | //because this listener takes priority |
| 398 | 399 | $('#options').stop().fadeOut(animation_duration); |
| 399 | 400 | } else { |
| 400 | 401 | toastr.warning('t`Select a character before trying to use Author\'s Note'`, '', { timeOut: 2000 }); |
| 401 | 402 | } |
| 402 | 403 | } |
| 403 | 404 | |
| @@ -40,6 +40,7 @@ import { POPUP_RESULT, POPUP_TYPE, Popup, callGenericPopup } from './popup.js'; | ||
| 40 | 40 | import { ScraperManager } from './scrapers.js'; |
| 41 | 41 | import { DragAndDropHandler } from './dragdrop.js'; |
| 42 | 42 | import { renderTemplateAsync } from './templates.js'; |
| 43 | +import { t } from './i18n.js'; | |
| 43 | 44 | |
| 44 | 45 | /** |
| 45 | 46 | * @typedef {Object} FileAttachment |
| @@ -206,7 +207,7 @@ export async function populateFileAttachment(message, inputId = 'file_form_input | ||
| 206 | 207 | const fileText = await converter(file); |
| 207 | 208 | base64Data = window.btoa(unescape(encodeURIComponent(fileText))); |
| 208 | 209 | } catch (error) { |
| 209 | 210 | toastr.error(String(error), 't`Could not convert file'`); |
| 210 | 211 | console.error('Could not convert file', error); |
| 211 | 212 | } |
| 212 | 213 | } |
| @@ -257,7 +258,7 @@ export async function uploadFileAttachment(fileName, base64Data) { | ||
| 257 | 258 | const responseData = await result.json(); |
| 258 | 259 | return responseData.path; |
| 259 | 260 | } catch (error) { |
| 260 | 261 | toastr.error(String(error), 't`Could not upload file'`); |
| 261 | 262 | console.error('Could not upload file', error); |
| 262 | 263 | } |
| 263 | 264 | } |
| @@ -283,7 +284,7 @@ export async function getFileAttachment(url) { | ||
| 283 | 284 | const text = await result.text(); |
| 284 | 285 | return text; |
| 285 | 286 | } catch (error) { |
| 286 | 287 | toastr.error(error, 't`Could not download file'`); |
| 287 | 288 | console.error('Could not download file', error); |
| 288 | 289 | } |
| 289 | 290 | } |
| @@ -299,13 +300,13 @@ async function validateFile(file) { | ||
| 299 | 300 | const isBinary = /^[\x00-\x08\x0E-\x1F\x7F-\xFF]*$/.test(fileText); |
| 300 | 301 | |
| 301 | 302 | if (!isImage && file.size > fileSizeLimit) { |
| 302 | 303 | toastr.error(t`File is too big. Maximum size is ${humanFileSize(fileSizeLimit)}.`); |
| 303 | 304 | return false; |
| 304 | 305 | } |
| 305 | 306 | |
| 306 | 307 | // If file is binary |
| 307 | 308 | if (isBinary && !isImage && !isConvertible(file.type)) { |
| 308 | 309 | toastr.error('t`Binary files are not supported. Select a text file or image.'`); |
| 309 | 310 | return false; |
| 310 | 311 | } |
| 311 | 312 | |
| @@ -521,7 +522,7 @@ async function openExternalMediaOverridesDialog() { | ||
| 521 | 522 | const entityId = getCurrentEntityId(); |
| 522 | 523 | |
| 523 | 524 | if (!entityId) { |
| 524 | 525 | toastr.info('t`No character or group selected'`); |
| 525 | 526 | return; |
| 526 | 527 | } |
| 527 | 528 | |
| @@ -646,7 +647,7 @@ async function deleteFileFromServer(url, silent = false) { | ||
| 646 | 647 | await eventSource.emit(event_types.FILE_ATTACHMENT_DELETED, url); |
| 647 | 648 | return true; |
| 648 | 649 | } catch (error) { |
| 649 | 650 | toastr.error(String(error), 't`Could not delete file'`); |
| 650 | 651 | console.error('Could not delete file', error); |
| 651 | 652 | return false; |
| 652 | 653 | } |
| @@ -1054,7 +1055,7 @@ async function openAttachmentManager() { | ||
| 1054 | 1055 | const selectedAttachments = document.querySelectorAll('.attachmentListItemCheckboxContainer .attachmentListItemCheckbox:checked'); |
| 1055 | 1056 | |
| 1056 | 1057 | if (selectedAttachments.length === 0) { |
| 1057 | 1058 | toastr.info('t`No attachments selected.'`, 't`Data Bank'`); |
| 1058 | 1059 | return; |
| 1059 | 1060 | } |
| 1060 | 1061 | |
| @@ -1168,7 +1169,7 @@ async function runScraper(scraperId, target, callback) { | ||
| 1168 | 1169 | |
| 1169 | 1170 | if (files.length === 0) { |
| 1170 | 1171 | console.warn('Scraping returned no files'); |
| 1171 | 1172 | toastr.info('t`No files were scraped.'`, 't`Data Bank'`); |
| 1172 | 1173 | return; |
| 1173 | 1174 | } |
| 1174 | 1175 | |
| @@ -1176,12 +1177,12 @@ async function runScraper(scraperId, target, callback) { | ||
| 1176 | 1177 | await uploadFileAttachmentToServer(file, target); |
| 1177 | 1178 | } |
| 1178 | 1179 | |
| 1179 | 1180 | toastr.success(t`Scraped ${files.length} files from ${scraperId} to ${target}.`, 't`Data Bank'`); |
| 1180 | 1181 | callback(); |
| 1181 | 1182 | } |
| 1182 | 1183 | catch (error) { |
| 1183 | 1184 | console.error('Scraping failed', error); |
| 1184 | 1185 | toastr.error('t`Check browser console for details.'`, 't`Scraping failed'`); |
| 1185 | 1186 | } |
| 1186 | 1187 | } |
| 1187 | 1188 | |
| @@ -1208,7 +1209,7 @@ export async function uploadFileAttachmentToServer(file, target) { | ||
| 1208 | 1209 | const fileText = await converter(file); |
| 1209 | 1210 | base64Data = window.btoa(unescape(encodeURIComponent(fileText))); |
| 1210 | 1211 | } catch (error) { |
| 1211 | 1212 | toastr.error(String(error), 't`Could not convert file'`); |
| 1212 | 1213 | console.error('Could not convert file', error); |
| 1213 | 1214 | } |
| 1214 | 1215 | } else { |
| @@ -132,7 +132,7 @@ | ||
| 132 | 132 | <small data-i18n="ext_regex_other_options" data-i18n="Ephemerality">Ephemerality</small> |
| 133 | 133 | <span class="fa-solid fa-circle-question note-link-span" title="By default, regex scripts alter the chat file directly and irreversibly. Enabling either (or both) of the options below will prevent chat file alteration, while still altering the specified item(s)."></span> |
| 134 | 134 | </span> |
| 135 | 135 | <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."> |
| 136 | 136 | <input type="checkbox" name="only_format_display" /> |
| 137 | 137 | <span data-i18n="Only Format Display">Alter Chat Display</span> |
| 138 | 138 | </label> |
| @@ -189,8 +189,8 @@ async function validateGroup(group) { | ||
| 189 | 189 | group.members = group.members.filter(member => { |
| 190 | 190 | const character = characters.find(x => x.avatar === member || x.name === member); |
| 191 | 191 | if (!character) { |
| 192 | 192 | const msg = t`Warning: Listed member ${member} does not exist as a character. It will be removed from the group.`; |
| 193 | 193 | toastr.warning(msg, 't`Group Validation'`); |
| 194 | 194 | console.warn(msg); |
| 195 | 195 | dirty = true; |
| 196 | 196 | } |
| @@ -522,7 +522,7 @@ async function saveGroupChat(groupId, shouldSaveGroup) { | ||
| 522 | 522 | }); |
| 523 | 523 | |
| 524 | 524 | if (!response.ok) { |
| 525 | 525 | toastr.error('t`Check the server connection and reload the page to prevent data loss.'`, 't`Group Chat could not be saved'`); |
| 526 | 526 | console.error('Group chat could not be saved', response); |
| 527 | 527 | return; |
| 528 | 528 | } |
| @@ -837,7 +837,7 @@ async function generateGroupWrapper(by_auto_mode, type = null, params = {}) { | ||
| 837 | 837 | activatedMembers = activateSwipe(group.members); |
| 838 | 838 | |
| 839 | 839 | if (activatedMembers.length === 0) { |
| 840 | 840 | toastr.warning('t`Deleted group member swiped. To get a reply, add them back to the group.'`); |
| 841 | 841 | throw new Error('Deleted group member swiped'); |
| 842 | 842 | } |
| 843 | 843 | } |
| @@ -1368,15 +1368,15 @@ function isGroupMemberDisabled(avatarId) { | ||
| 1368 | 1368 | |
| 1369 | 1369 | async function onDeleteGroupClick() { |
| 1370 | 1370 | if (!openGroupId) { |
| 1371 | 1371 | toastr.warning('t`Currently no group selected.'`); |
| 1372 | 1372 | return; |
| 1373 | 1373 | } |
| 1374 | 1374 | if (is_group_generating) { |
| 1375 | 1375 | toastr.warning('t`Not so fast! Wait for the characters to stop typing before deleting the group.'`); |
| 1376 | 1376 | return; |
| 1377 | 1377 | } |
| 1378 | 1378 | |
| 1379 | 1379 | 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>'); |
| 1380 | 1380 | if (confirm) { |
| 1381 | 1381 | deleteGroup(openGroupId); |
| 1382 | 1382 | } |
| @@ -1630,7 +1630,7 @@ function updateFavButtonState(state) { | ||
| 1630 | 1630 | |
| 1631 | 1631 | export async function openGroupById(groupId) { |
| 1632 | 1632 | if (isChatSaving) { |
| 1633 | 1633 | toastr.info('t`Please wait until the chat is saved before switching characters.'`, 't`Your chat is still saving...'`); |
| 1634 | 1634 | return; |
| 1635 | 1635 | } |
| 1636 | 1636 | |
| @@ -1659,7 +1659,7 @@ export async function openGroupById(groupId) { | ||
| 1659 | 1659 | |
| 1660 | 1660 | function openCharacterDefinition(characterSelect) { |
| 1661 | 1661 | if (is_group_generating) { |
| 1662 | 1662 | toastr.warning('t`Can\'t peek a character while group reply is being generated'`); |
| 1663 | 1663 | console.warn('Can\'t peek a character def while group reply is being generated'); |
| 1664 | 1664 | return; |
| 1665 | 1665 | } |
| @@ -1908,7 +1908,7 @@ export async function saveGroupBookmarkChat(groupId, name, metadata, mesId) { | ||
| 1908 | 1908 | }); |
| 1909 | 1909 | |
| 1910 | 1910 | if (!response.ok) { |
| 1911 | 1911 | toastr.error('t`Check the server connection and reload the page to prevent data loss.'`, 't`Group chat could not be saved'`); |
| 1912 | 1912 | console.error('Group chat could not be saved', response); |
| 1913 | 1913 | } |
| 1914 | 1914 | } |
| @@ -388,7 +388,7 @@ async function validateReverseProxy() { | ||
| 388 | 388 | new URL(oai_settings.reverse_proxy); |
| 389 | 389 | } |
| 390 | 390 | catch (err) { |
| 391 | 391 | toastr.error('t`Entered reverse proxy address is not a valid URL'`); |
| 392 | 392 | setOnlineStatus('no_connection'); |
| 393 | 393 | resultCheckStatus(); |
| 394 | 394 | throw err; |
| @@ -399,7 +399,7 @@ async function validateReverseProxy() { | ||
| 399 | 399 | const confirmation = skipConfirm || await Popup.show.confirm(t`Connecting To Proxy`, await renderTemplateAsync('proxyConnectionWarning', { proxyURL: DOMPurify.sanitize(oai_settings.reverse_proxy) })); |
| 400 | 400 | |
| 401 | 401 | if (!confirmation) { |
| 402 | 402 | toastr.error('t`Update or remove your reverse proxy settings.'`); |
| 403 | 403 | setOnlineStatus('no_connection'); |
| 404 | 404 | resultCheckStatus(); |
| 405 | 405 | throw new Error('Proxy connection denied.'); |
| @@ -1231,15 +1231,15 @@ export async function prepareOpenAIMessages({ | ||
| 1231 | 1231 | await populateChatCompletion(prompts, chatCompletion, { bias, quietPrompt, quietImage, type, cyclePrompt, messages, messageExamples }); |
| 1232 | 1232 | } catch (error) { |
| 1233 | 1233 | if (error instanceof TokenBudgetExceededError) { |
| 1234 | 1234 | toastr.error('t`An error occurred while counting tokens: Token budget exceeded.'`); |
| 1235 | 1235 | chatCompletion.log('Token budget exceeded.'); |
| 1236 | 1236 | promptManager.error = 't`Not enough free tokens for mandatory prompts. Raise your token Limit or disable custom prompts.'`; |
| 1237 | 1237 | } else if (error instanceof InvalidCharacterNameError) { |
| 1238 | 1238 | toastr.warning('t`An error occurred while counting tokens: Invalid character name'`); |
| 1239 | 1239 | chatCompletion.log('Invalid character name'); |
| 1240 | 1240 | promptManager.error = 't`The name of at least one character contained whitespaces or special characters. Please check your user and character name.'`; |
| 1241 | 1241 | } else { |
| 1242 | 1242 | toastr.error('t`An unknown error occurred while counting tokens. Further information may be available in console.'`); |
| 1243 | 1243 | chatCompletion.log('----- Unexpected error while preparing prompts -----'); |
| 1244 | 1244 | chatCompletion.log(error); |
| 1245 | 1245 | chatCompletion.log(error.stack); |
| @@ -1293,11 +1293,8 @@ function tryParseStreamingError(response, decoded) { | ||
| 1293 | 1293 | } |
| 1294 | 1294 | } |
| 1295 | 1295 | |
| 1296 | 1296 | async function checkQuotaError(data) { |
| 1297 | - const errorText = `<h3>Encountered an error while processing your request.<br> | |
| 1297 | + const errorText = await renderTemplateAsync('quotaError'); | |
| 1298 | - Check you have credits available on your | |
| 1299 | - <a href="https://platform.openai.com/account/usage" target="_blank">OpenAI account</a>.<br> | |
| 1300 | - If you have sufficient credits, please try again later.</h3>`; | |
| 1301 | 1298 | |
| 1302 | 1299 | if (!data) { |
| 1303 | 1300 | return; |
| @@ -1933,11 +1930,11 @@ async function sendOpenAIRequest(type, messages, signal) { | ||
| 1933 | 1930 | else { |
| 1934 | 1931 | const data = await response.json(); |
| 1935 | 1932 | |
| 1936 | 1933 | await checkQuotaError(data); |
| 1937 | 1934 | checkModerationError(data); |
| 1938 | 1935 | |
| 1939 | 1936 | if (data.error) { |
| 1940 | 1937 | toastr.error(data.error.message || response.statusText, 't`API returned an error'`); |
| 1941 | 1938 | throw new Error(data); |
| 1942 | 1939 | } |
| 1943 | 1940 | |
| @@ -2184,7 +2181,7 @@ function parseOpenAITextLogprobs(logprobs) { | ||
| 2184 | 2181 | |
| 2185 | 2182 | function handleWindowError(err) { |
| 2186 | 2183 | const text = parseWindowError(err); |
| 2187 | 2184 | toastr.error(text, 't`Window.ai returned an error'`); |
| 2188 | 2185 | throw err; |
| 2189 | 2186 | } |
| 2190 | 2187 | |
| @@ -3257,7 +3254,7 @@ async function getStatusOpen() { | ||
| 3257 | 3254 | } |
| 3258 | 3255 | |
| 3259 | 3256 | function showWindowExtensionError() { |
| 3260 | 3257 | toastr.error('t`Get it here:` + ' <a href="https://windowai.io/" target="_blank">windowai.io</a>', 't`Extension is not installed'`, { |
| 3261 | 3258 | escapeHtml: false, |
| 3262 | 3259 | timeOut: 0, |
| 3263 | 3260 | extendedTimeOut: 0, |
| @@ -3376,7 +3373,7 @@ async function saveOpenAIPreset(name, settings, triggerUi = true) { | ||
| 3376 | 3373 | if (triggerUi) $('#settings_preset_openai').append(option).trigger('change'); |
| 3377 | 3374 | } |
| 3378 | 3375 | } else { |
| 3379 | 3376 | toastr.error('t`Failed to save preset'`); |
| 3380 | 3377 | throw new Error('Failed to save preset'); |
| 3381 | 3378 | } |
| 3382 | 3379 | } |
| @@ -3455,7 +3452,7 @@ async function createNewLogitBiasPreset() { | ||
| 3455 | 3452 | } |
| 3456 | 3453 | |
| 3457 | 3454 | if (name in oai_settings.bias_presets) { |
| 3458 | 3455 | toastr.error('t`Preset name should be unique.'`); |
| 3459 | 3456 | return; |
| 3460 | 3457 | } |
| 3461 | 3458 | |
| @@ -3499,7 +3496,7 @@ async function onPresetImportFileChange(e) { | ||
| 3499 | 3496 | try { |
| 3500 | 3497 | presetBody = JSON.parse(importedFile); |
| 3501 | 3498 | } catch (err) { |
| 3502 | 3499 | toastr.error('t`Invalid file'`); |
| 3503 | 3500 | return; |
| 3504 | 3501 | } |
| 3505 | 3502 | |
| @@ -3540,7 +3537,7 @@ async function onPresetImportFileChange(e) { | ||
| 3540 | 3537 | }); |
| 3541 | 3538 | |
| 3542 | 3539 | if (!savePresetSettings.ok) { |
| 3543 | 3540 | toastr.error('t`Failed to save preset'`); |
| 3544 | 3541 | return; |
| 3545 | 3542 | } |
| 3546 | 3543 | |
| @@ -3565,7 +3562,7 @@ async function onPresetImportFileChange(e) { | ||
| 3565 | 3562 | |
| 3566 | 3563 | async function onExportPresetClick() { |
| 3567 | 3564 | if (!oai_settings.preset_settings_openai) { |
| 3568 | 3565 | toastr.error('t`No preset selected'`); |
| 3569 | 3566 | return; |
| 3570 | 3567 | } |
| 3571 | 3568 | |
| @@ -3606,12 +3603,12 @@ async function onLogitBiasPresetImportFileChange(e) { | ||
| 3606 | 3603 | e.target.value = ''; |
| 3607 | 3604 | |
| 3608 | 3605 | if (name in oai_settings.bias_presets) { |
| 3609 | 3606 | toastr.error('t`Preset name should be unique.'`); |
| 3610 | 3607 | return; |
| 3611 | 3608 | } |
| 3612 | 3609 | |
| 3613 | 3610 | if (!Array.isArray(importedFile)) { |
| 3614 | 3611 | toastr.error('t`Invalid logit bias preset file.'`); |
| 3615 | 3612 | return; |
| 3616 | 3613 | } |
| 3617 | 3614 | |
| @@ -3670,16 +3667,16 @@ async function onDeletePresetClick() { | ||
| 3670 | 3667 | }); |
| 3671 | 3668 | |
| 3672 | 3669 | if (!response.ok) { |
| 3673 | 3670 | toastr.warning('t`Preset was not deleted from server'`); |
| 3674 | 3671 | } else { |
| 3675 | 3672 | toastr.success('t`Preset deleted'`); |
| 3676 | 3673 | } |
| 3677 | 3674 | |
| 3678 | 3675 | saveSettingsDebounced(); |
| 3679 | 3676 | } |
| 3680 | 3677 | |
| 3681 | 3678 | async function onLogitBiasPresetDeleteClick() { |
| 3682 | 3679 | const value = await callPopup('t`Delete the preset?'`, 'confirm'); |
| 3683 | 3680 | |
| 3684 | 3681 | if (!value) { |
| 3685 | 3682 | return; |
| @@ -4816,7 +4813,7 @@ function runProxyCallback(_, value) { | ||
| 4816 | 4813 | const result = fuse.search(value); |
| 4817 | 4814 | |
| 4818 | 4815 | if (result.length === 0) { |
| 4819 | 4816 | toastr.warning(t`Proxy preset "'${value}"' not found`); |
| 4820 | 4817 | return ''; |
| 4821 | 4818 | } |
| 4822 | 4819 | |
| @@ -4990,7 +4987,7 @@ export function initOpenAI() { | ||
| 4990 | 4987 | $('#update_oai_preset').on('click', async function () { |
| 4991 | 4988 | const name = oai_settings.preset_settings_openai; |
| 4992 | 4989 | await saveOpenAIPreset(name, oai_settings); |
| 4993 | 4990 | toastr.success('t`Preset updated'`); |
| 4994 | 4991 | }); |
| 4995 | 4992 | |
| 4996 | 4993 | $('#impersonation_prompt_restore').on('click', function () { |
| @@ -1,3 +1,3 @@ | ||
| 1 | 1 | <div> |
| 2 | 2 | <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> |
| 3 | 3 | </div> |
| @@ -0,0 +1,5 @@ | ||
| 1 | +<b><span data-i18n="THIS IS PERMANENT!">THIS IS PERMANENT!</span><br><br> | |
| 2 | +<label for="del_char_checkbox" class="checkbox_label justifyCenter"> | |
| 3 | + <input type="checkbox" id="del_char_checkbox" /> | |
| 4 | + <small data-i18n="Also delete the chat files">Also delete the chat files</small> | |
| 5 | +</label></b> | |
| 5 | \ No newline at end of file | |
| @@ -1,5 +1,5 @@ | ||
| 1 | 1 | <div> |
| 2 | 2 | <h3 data-i18n="Are you sure you want to duplicate this character?">Are you sure you want to duplicate this character?</h3> |
| 3 | 3 | <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> |
| 4 | 4 | <br> |
| 5 | 5 | </div> |
| @@ -14,18 +14,18 @@ | ||
| 14 | 14 | <li><kbd data-i18n="help_hotkeys_19">Ctrl+Shift+Down</kbd> = <span data-i18n="help_hotkeys_20">Scroll chat to bottom</span></li> |
| 15 | 15 | </ul> |
| 16 | 16 | <div> |
| 17 | 17 | <strong data-i18n="help_hotkeys_20">Markdown Hotkeys</strong> |
| 18 | 18 | </div> |
| 19 | 19 | <div> |
| 20 | 20 | <small> |
| 21 | 21 | <span data-i18n="help_hotkeys_21">Works in the chatbar and textareas marked with this icon:</span> |
| 22 | 22 | <code><i class="fa-brands fa-markdown"></i></code> |
| 23 | 23 | </small> |
| 24 | 24 | </div> |
| 25 | 25 | <ul> |
| 26 | 26 | <li><kbd>Ctrl+B</kbd> = <span data-i18n="help_hotkeys_22">**bold**</span></li> |
| 27 | 27 | <li><kbd>Ctrl+I</kbd> = <span data-i18n="help_hotkeys_23">*italic*</span></li> |
| 28 | 28 | <li><kbd>Ctrl+U</kbd> = <span data-i18n="help_hotkeys_24">__underline__</span></li> |
| 29 | 29 | <li><kbd>Ctrl+K</kbd> = <span data-i18n="help_hotkeys_25">`inline code`</span></li> |
| 30 | 30 | <li><kbd>Ctrl+Shift+~</kbd> = <span data-i18n="help_hotkeys_26">~~strikethrough~~</span></li> |
| 31 | 31 | </ul> |
| @@ -0,0 +1,4 @@ | ||
| 1 | +<h3><span data-i18n="Encountered an error while processing your request.">Encountered an error while processing your request.</span><br> | |
| 2 | + <span data-i18n="Check you have credits available on your">Check you have credits available on your</span> | |
| 3 | + <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> | |
| 4 | + <span data-i18n="If you have sufficient credits, please try again later.">If you have sufficient credits, please try again later.</span></h3> | |
| 4 | \ No newline at end of file | |