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