diff --git a/public/index.html b/public/index.html index c2f391e53..c299d9223 100644 --- a/public/index.html +++ b/public/index.html @@ -751,7 +751,7 @@ <div data-newbie-hidden class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> <small> <span data-i18n="Top K">Top K</span> - <div class="fa-solid fa-circle-info opacity50p" title="Top K sets a maximum amount of top tokens that can be chosen from. E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited). Set to 0 to disable."></div> + <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Top K sets a maximum amount of top tokens that can be chosen from" title="Top K sets a maximum amount of top tokens that can be chosen from. E.g Top K is 20, this means only the 20 highest ranking tokens will be kept (regardless of their probabilities being diverse or limited). Set to 0 to disable."></div> </small> <input class="neo-range-slider" type="range" id="top_k" name="volume" min="0" max="100" step="1"> <input class="neo-range-input" type="number" min="0" max="100" step="1" data-for="top_k" id="top_k_counter"> @@ -759,7 +759,7 @@ <div data-newbie-hidden class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> <small> Top P - <div class="fa-solid fa-circle-info opacity50p" title="Top P (a.k.a. nucleus sampling) adds up all the top tokens required to add up to the target percentage. E.g If the Top 2 tokens are both 25%, and Top P is 0.50, only the Top 2 tokens are considered. Set to 1.0 to disable."></div> + <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Top P (a.k.a. nucleus sampling)" title="Top P (a.k.a. nucleus sampling) adds up all the top tokens required to add up to the target percentage. E.g If the Top 2 tokens are both 25%, and Top P is 0.50, only the Top 2 tokens are considered. Set to 1.0 to disable."></div> </small> <input class="neo-range-slider" type="range" id="top_p" name="volume" min="0" max="1" step="0.01"> <input class="neo-range-input" type="number" min="0" max="1" step="0.01" data-for="top_p" id="top_p_counter"> @@ -767,7 +767,7 @@ <div data-newbie-hidden class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> <small> <span data-i18n="Typical P">Typical P</span> - <div class="fa-solid fa-circle-info opacity50p" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set. It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content. Set to 1.0 to disable."></div> + <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set" title="Typical P Sampling prioritizes tokens based on their deviation from the average entropy of the set. It maintains tokens whose cumulative probability is close to a predefined threshold (e.g., 0.5), emphasizing those with average information content. Set to 1.0 to disable."></div> </small> <input class="neo-range-slider" type="range" id="typical_p" name="volume" min="0" max="1" step="0.001"> <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="typical_p" id="typical_p_counter"> @@ -775,7 +775,7 @@ <div class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> <small> <span data-i18n="Min P">Min P</span> - <div class="fa-solid fa-circle-info opacity50p" title="Min P sets a base minimum probability. This is scaled according to the top token's probability. E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered. Set to 0 to disable."></div> + <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Min P sets a base minimum probability" title="Min P sets a base minimum probability. This is scaled according to the top token's probability. E.g If Top token is 80% probability, and Min P is 0.1, only tokens higher than 8% would be considered. Set to 0 to disable."></div> </small> <input class="neo-range-slider" type="range" id="min_p" name="volume" min="0" max="1" step="0.001"> <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="min_p" id="min_p_counter"> @@ -783,7 +783,7 @@ <div data-newbie-hidden class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> <small> <span data-i18n="Top A">Top A</span> - <div class="fa-solid fa-circle-info opacity50p" title="Top A sets a threshold for token selection based on the square of the highest token probability. E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded. Set to 0 to disable."></div> + <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Top A sets a threshold for token selection based on the square of the highest token probability" title="Top A sets a threshold for token selection based on the square of the highest token probability. E.g if the Top-A value is 0.2 and the top token's probability is 50%, tokens with probabilities below 5% (0.2 * 0.5^2) are excluded. Set to 0 to disable."></div> </small> <input class="neo-range-slider" type="range" id="top_a" name="volume" min="0" max="1" step="0.001"> <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="top_a" id="top_a_counter"> @@ -791,7 +791,7 @@ <div data-newbie-hidden class="alignitemscenter flex-container flexFlowColumn flexBasis30p flexGrow flexShrink gap0"> <small> <span data-i18n="Tail Free Sampling">TFS</span> - <div class="fa-solid fa-circle-info opacity50p" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution, by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative. The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div> + <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Tail-Free Sampling (TFS)" title="Tail-Free Sampling (TFS) searches for a tail of low-probability tokens in the distribution, by analyzing the rate of change in token probabilities using derivatives. It retains tokens up to a threshold (e.g., 0.3) based on the normalized second derivative. The closer to 0, the more discarded tokens. Set to 1.0 to disable."></div> </small> <input class="neo-range-slider" type="range" id="tfs" name="volume" min="0" max="1" step="0.001"> <input class="neo-range-input" type="number" min="0" max="1" step="0.001" data-for="tfs" id="tfs_counter"> @@ -868,7 +868,7 @@ </small> </a> </h4> - <textarea id="grammar" rows="4" class="text_pole textarea_compact monospace" placeholder="Type in the desired custom grammar"></textarea> + <textarea id="grammar" rows="4" class="text_pole textarea_compact monospace" data-i18n="[placeholder]Type in the desired custom grammar" placeholder="Type in the desired custom grammar"></textarea> </div> <div data-newbie-hidden name="KoboldSamplerOrderBlock" class="range-block flexFlowColumn"> <hr class="wide100p"> @@ -1684,9 +1684,9 @@ <input id="openai_image_inlining" type="checkbox" /> <span data-i18n="Send inline images">Send inline images</span> <div id="image_inlining_hint" class="flexBasis100p toggle-description justifyLeft"> - Sends images in prompts if the model supports it (e.g. GPT-4V, Claude 3 or Llava 13B). - Use the <code><i class="fa-solid fa-paperclip"></i></code> action on any message or the - <code><i class="fa-solid fa-wand-magic-sparkles"></i></code> menu to attach an image file to the chat. + <span data-i18n="image_inlining_hint_1">Sends images in prompts if the model supports it (e.g. GPT-4V, Claude 3 or Llava 13B). + Use the</span> <code><i class="fa-solid fa-paperclip"></i></code> <span data-i18n="image_inlining_hint_2">action on any message or the</span> + <code><i class="fa-solid fa-wand-magic-sparkles"></i></code> <span data-i18n="image_inlining_hint_3">menu to attach an image file to the chat.</span> </div> </label> </div> @@ -3850,7 +3850,7 @@ Character Handling </h4> <div title="If set in the advanced character definitions, this field will be displayed in the characters list." data-i18n="[title]If set in the advanced character definitions, this field will be displayed in the characters list."> - <label for="aux_field" data-i18n="Char List Subheader"><small>Char List Subheader</small></label> + <label for="aux_field"><small data-i18n="Char List Subheader">Char List Subheader</small></label> <select id="aux_field"> <option data-i18n="Character Version" value="character_version">Character Version</option> <option data-i18n="Created by" value="creator">Created by</option> @@ -4744,7 +4744,7 @@ </div> </div> <!-- various fullscreen popups --> - <template id="shadow_popup_template"> + <template id="shadow_popup_template" data-i18n="[popup_text_save]popup_text_save;[popup_text_yes]popup_text_yes;[popup_text_no]popup_text_no;[popup_text_cancel]popup_text_cancel;[popup_text_import]popup_text_import" popup_text_save="Save" popup_text_yes="Yes" popup_text_no="No" popup_text_cancel="Cancel" popup_text_import="Import"> <!-- localization data holder for popups --> <div class="shadow_popup"> <div class="dialogue_popup"> <div class="dialogue_popup_holder"> @@ -4983,11 +4983,11 @@ </div> <div id="background_template" class="template_element"> <div class="bg_example flex-container" bgfile="" class="bg_example_img" title=""> - <div title="Copy to system backgrounds" class="bg_button bg_example_copy fa-solid fa-file-arrow-up"></div> - <div title="Rename background" class="bg_button bg_example_edit fa-solid fa-pencil"></div> - <div title="Lock" class="bg_button bg_example_lock fa-solid fa-lock"></div> - <div title="Unlock" class="bg_button bg_example_unlock fa-solid fa-lock-open"></div> - <div title="Delete background" class="bg_button bg_example_cross fa-solid fa-circle-xmark"></div> + <div title="Copy to system backgrounds" data-i18n="[title]Copy to system backgrounds" class="bg_button bg_example_copy fa-solid fa-file-arrow-up"></div> + <div title="Rename background" data-i18n="[title]Rename background" class="bg_button bg_example_edit fa-solid fa-pencil"></div> + <div title="Lock" data-i18n="[title]Lock" class="bg_button bg_example_lock fa-solid fa-lock"></div> + <div title="Unlock" data-i18n="[title]Unlock" class="bg_button bg_example_unlock fa-solid fa-lock-open"></div> + <div title="Delete background" data-i18n="[title]Delete background" class="bg_button bg_example_cross fa-solid fa-circle-xmark"></div> <div class="BGSampleTitle"> </div> </div> @@ -5416,45 +5416,45 @@ </div> </div> <div id="completion_prompt_manager_popup_edit"> - <h3>Edit</h3> + <h3 data-i18n="prompt_manager_edit">Edit</h3> <div class="completion_prompt_manager_popup_entry"> <form class="completion_prompt_manager_popup_entry_form"> <div class="flex-container gap10px"> <div class="completion_prompt_manager_popup_entry_form_control flex1"> <label for="completion_prompt_manager_popup_entry_form_name"> - <span>Name</span> + <span data-i18n="prompt_manager_name">Name</span> </label> - <div class="text_muted">A name for this prompt.</div> + <div class="text_muted" data-i18n="A name for this prompt.">A name for this prompt.</div> <input id="completion_prompt_manager_popup_entry_form_name" class="text_pole" type="text" name="name" /> </div> <div class="completion_prompt_manager_popup_entry_form_control flex1"> <label for="completion_prompt_manager_popup_entry_form_role"> - <span>Role</span> + <span data-i18n="Role">Role</span> </label> - <div class="text_muted">To whom this message will be attributed.</div> + <div class="text_muted" data-i18n="To whom this message will be attributed.">To whom this message will be attributed.</div> <select id="completion_prompt_manager_popup_entry_form_role" class="text_pole" name="role"> - <option value="system">System</option> - <option value="user">User</option> - <option value="assistant">AI Assistant</option> + <option data-i18n="System" value="system">System</option> + <option data-i18n="User" value="user">User</option> + <option data-i18n="AI Assistant" value="assistant">AI Assistant</option> </select> </div> </div> <div class="flex-container gap10px"> <div class="completion_prompt_manager_popup_entry_form_control flex1"> <label for="completion_prompt_manager_popup_entry_form_injection_position"> - <span>Position</span> + <span data-i18n="prompt_manager_position">Position</span> </label> - <div class="text_muted">Injection position. Next to other prompts (relative) or in-chat (absolute).</div> + <div class="text_muted" data-i18n="Injection position. Next to other prompts (relative) or in-chat (absolute).">Injection position. Next to other prompts (relative) or in-chat (absolute).</div> <select id="completion_prompt_manager_popup_entry_form_injection_position" class="text_pole" name="injection_position"> - <option value="0">Relative</option> - <option value="1">Absolute</option> + <option data-i18n="prompt_manager_relative" value="0">Relative</option> + <option data-i18n="prompt_manager_absolute" value="1">Absolute</option> </select> </div> <div id="completion_prompt_manager_depth_block" class="completion_prompt_manager_popup_entry_form_control flex1"> <label for="completion_prompt_manager_popup_entry_form_injection_depth"> - <span>Depth</span> + <span data-i18n="prompt_manager_depth">Depth</span> </label> - <div class="text_muted">Injection depth. 0 = after the last message, 1 = before the last message, etc.</div> + <div class="text_muted" data-i18n="Injection depth. 0 = after the last message, 1 = before the last message, etc.">Injection depth. 0 = after the last message, 1 = before the last message, etc.</div> <input id="completion_prompt_manager_popup_entry_form_injection_depth" class="text_pole" type="number" name="injection_depth" min="0" max="999" value="4" /> </div> </div> @@ -5462,14 +5462,14 @@ <div class="flex-container alignItemsCenter"> <div class="flex1"> <label for="completion_prompt_manager_popup_entry_form_prompt"> - <span>Prompt</span> + <span data-i18n="Prompt">Prompt</span> </label> - <div class="text_muted">The prompt to be sent.</div> + <div class="text_muted" data-i18n="The prompt to be sent.">The prompt to be sent.</div> </div> <div id="completion_prompt_manager_forbid_overrides_block"> - <label class="checkbox_label" for="completion_prompt_manager_popup_entry_form_forbid_overrides" title="This prompt cannot be overridden by character cards, even if overrides are preferred."> + <label class="checkbox_label" for="completion_prompt_manager_popup_entry_form_forbid_overrides" data-i18n="[title]This prompt cannot be overridden by character cards, even if overrides are preferred." title="This prompt cannot be overridden by character cards, even if overrides are preferred."> <input type="checkbox" id="completion_prompt_manager_popup_entry_form_forbid_overrides" name="forbid_overrides" /> - <span>Forbid Overrides</span> + <span data-i18n="prompt_manager_forbid_overrides">Forbid Overrides</span> </label> </div> </div> @@ -5578,6 +5578,10 @@ <li><span data-i18n="welcome_message_part_4">Type</span> <code>/help</code> <span data-i18n="welcome_message_part_5">in chat for commands and macros.</span></li> <li><span data-i18n="welcome_message_part_6">Join the</span> <a href="https://discord.gg/sillytavern" data-i18n="Discord server" target="_blank">Discord server</a> <span data-i18n="welcome_message_part_7">for info and announcements.</span></li> </ul> + <div id="onboarding-UI-language-block" class="flex-container alignItemsBaseline"> + <span data-i18n="UI Language">Language:</span> + <select id="onboarding_ui_language_select" class="flex1 margin0"> + <option value="en">English</option></select></div> <b data-i18n="SillyTavern is aimed at advanced users."> SillyTavern is aimed at advanced users. </b> @@ -5603,7 +5607,7 @@ <span> <span class="menu_button menu_button_icon external_import_button"> <i class="fa-solid fa-cloud-arrow-down"></i> - <span>Import</span> + <span data-i18n="onboarding_import">Import</span> </span> <span data-i18n="from supported sources or view"> from supported sources or view diff --git a/public/locales/ru-ru.json b/public/locales/ru-ru.json index 6c730a669..9e0953316 100644 --- a/public/locales/ru-ru.json +++ b/public/locales/ru-ru.json @@ -33,7 +33,7 @@ "Variability parameter for Mirostat outputs": "Параметр изменчивости для выходных данных Mirostat.", "Learning rate of Mirostat": "Скорость обучения Mirostat.", "Strength of the Contrastive Search regularization term. Set to 0 to disable CS": "Сила условия регуляризации контрастивного поиска. Установите значение 0, чтобы отключить CS.", - "Temperature Last": "Temperature Last", + "Temperature Last": "Температура последней", "Use the temperature sampler last": "Использовать Temperature сэмплер в последнюю очередь. Это почти всегда разумно.\nПри включении: сначала выборка набора правдоподобных токенов, затем применение Temperature для корректировки их относительных вероятностей (технически, логитов).\nПри отключении: сначала применение Temperature для корректировки относительных вероятностей ВСЕХ токенов, затем выборка правдоподобных токенов из этого.\nОтключение Temperature Last увеличивает вероятности в хвосте распределения, что увеличивает шансы получить несогласованный ответ.", "LLaMA / Mistral / Yi models only": "Только для моделей LLaMA / Mistral / Yi. Перед этим обязательно выберите подходящий токенизатор.\nПоследовательности, которых не должно быть на выходе.\nОдна на строку. Текст или [идентификаторы токенов].\nМногие токены имеют пробел впереди. Используйте счетчик токенов, если не уверены.", "Example: some text [42, 69, 1337]": "Пример:\nкакой-то текст\n[42, 69, 1337]", @@ -128,7 +128,7 @@ "Jailbreak prompt": "Джейлбрейк-промпт", "Prompt that is used when the Jailbreak toggle is on": "Промпт, применяемый при включенном джейлбрейке.", "Impersonation prompt": "Промпт для перевоплощения", - "Prompt that is used for Impersonation function": "Промпт, применяемый при генерации действий за пользователя", + "Prompt that is used for Impersonation function": "Промпт, применяемый при генерации действий от лица пользователя", "Logit Bias": "Смещение логитов", "Helps to ban or reenforce the usage of certain words": "Запрещает или поощряет использование определенных слов", "View / Edit bias preset": "Просмотр / Редактирование пресета смещения", @@ -179,8 +179,8 @@ "Novel AI Model": "Модель NovelAI", "If you are using:": "Если вы используете:", "oobabooga/text-generation-webui": "", - "Make sure you run it with": "Убедитесь, что вы запустили его с", - "flag": "флажком", + "Make sure you run it with": "Обязательно запускайте его с флагом", + "flag": "", "API key (optional)": "Ключ API (опционально)", "Server url": "URL-адрес сервера", "Custom model (optional)": "Пользовательская модель (опционально)", @@ -195,13 +195,13 @@ "Example: ws://127.0.0.1:5005/api/v1/stream": "Пример: ws://127.0.0.1:5005/api/v1/stream", "Mancer API key": "Ключ от Mancer API", "Example: https://neuro.mancer.tech/webui/MODEL/api": "Пример: https://neuro.mancer.tech/webui/MODEL/api", - "to get your OpenAI API key.": "для получения ключа от OpenAI API", + "to get your OpenAI API key.": "для получения ключа от API OpenAI", "Window AI Model": "Модель Window AI", "OpenAI Model": "Модель OpenAI", "Claude API Key": "Ключ от Claude API", "Get your key from": "Получите ключ в", "Anthropic's developer console": "консоли разработчика Anthropic", - "Slack and Poe cookies will not work here, do not bother trying.": "Файлы cookie Slack и Poe здесь не подойдут, можете их не пробовать.", + "Slack and Poe cookies will not work here, do not bother trying.": "Cookie от Slack и Poe здесь не подойдут, можете их не пробовать.", "Claude Model": "Модель Claude", "Scale API Key": "Ключ от Scale API", "Alt Method": "Альтернативный метод", @@ -228,7 +228,7 @@ "Disable example chats formatting": "Отключить форматирование примеров чата", "Disable chat start formatting": "Отключить форматирование начала чата", "Custom Chat Separator": "Кастомный разделитель для чата", - "Replace Macro in Custom Stopping Strings": "Заменить макрос в пользовательских стоп-строках", + "Replace Macro in Custom Stopping Strings": "Заменить макросы в пользовательских стоп-строках", "Strip Example Messages from Prompt": "Удалить примеры сообщений из подсказки", "Story String": "Строка истории", "Example Separator": "Пример разделителя", @@ -535,13 +535,13 @@ "Streaming FPS": "FPS для стриминга", "Gestures": "Жесты", "Message IDs": "ID сообщений", - "Prefer Character Card Prompt": "Предпочитать промпт из карточки персонажа", - "Prefer Character Card Jailbreak": "Предпочитать джейлбрейк из карточки керсонажа", + "Prefer Character Card Prompt": "Приоритет промпту из карточки персонажа", + "Prefer Character Card Jailbreak": "Приоритет джейлбрейку из карточки персонажа", "Press Send to continue": "Кнопка отправки продолжает сообщение", "Quick 'Continue' button": "Кнопка быстрого продолжения", "Log prompts to console": "Выводить промпты в консоль", - "Never resize avatars": "Никогда не менять размер аватаров", - "Show avatar filenames": "Показывать названия файлов аватаров", + "Never resize avatars": "Не менять размер аватарок", + "Show avatar filenames": "Показывать названия файлов аватарок", "Import Card Tags": "Импорт тегов карточки", "Confirm message deletion": "Подтверждение удаления сообщений", "Spoiler Free Mode": "Режим без спойлеров", @@ -562,7 +562,7 @@ "Reduce chat height, and put a static sprite behind the chat window": "Уменьшить высоту чата и поместить статичный спрайт за окном чата.", "Always show the full list of the Message Actions context items for chat messages, instead of hiding them behind '...'": "Всегда показывать полный список действий с сообщением, а не прятать их за '...'.", "Alternative UI for numeric sampling parameters with fewer steps": "Альтернативный пользовательский интерфейс для числовых параметров выборки с меньшим количеством шагов.", - "Entirely unrestrict all numeric sampling parameters": "Полностью разграничить все числовые параметры выборки.", + "Entirely unrestrict all numeric sampling parameters": "Снять ограничения со всех числовых сэмплеров.", "Time the AI's message generation, and show the duration in the chat log": "Время генерации сообщений ИИ и его показ в журнале чата.", "Show a timestamp for each message in the chat log": "Показывать временную метку для каждого сообщения в журнале чата.", "Show an icon for the API that generated the message": "Показать значок API, сгенерировавшего сообщение.", @@ -834,7 +834,7 @@ "Sampler Priority": "Приоритет сэмплеров", "Ooba only. Determines the order of samplers.": "Только Ooba. Определяет порядок сэмплеров.", "Load default order": "Загрузить стандартный порядок", - "Max Tokens Second": "Максимальное количество токенов в секунду", + "Max Tokens Second": "Макс. кол-во токенов в секунду", "CFG": "CFG", "No items": "Нет элементов", "Extras API key (optional)": "Ключ от Extras API (необязательно)", @@ -868,10 +868,10 @@ "Send names in the message objects. Helps the model to associate messages with characters.": "Отправить имена в объектах сообщений. Помогает модели ассоциировать сообщения с персонажами.", "Continue prefill": "Префилл для продолжения", "Continue sends the last message as assistant role instead of system message with instruction.": "Продолжение отправляет последнее сообщение в роли ассистента, вместо системного сообщения с инструкцией.", - "Squash system messages": "Склеивать сообщения системыы", - "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Объединяет последовательные системные сообщения в одно (за исключением примеров диалогов). Может улучшить согласованность для некоторых моделей.", - "Send inline images": "Отправлять встроенные изображения", - "Assistant Prefill": "Префилл от ассистента", + "Squash system messages": "Склеивать сообщения системы", + "Combines consecutive system messages into one (excluding example dialogues). May improve coherence for some models.": "Объединяет последовательные системные сообщения в одно (за исключением примеров диалогов). У некоторых моделей может улучшить логичность ответов.", + "Send inline images": "Отправлять inline-картинки", + "Assistant Prefill": "Префилл для ассистента", "Start Claude's answer with...": "Начать ответ Клода с...", "Use system prompt (Claude 2.1+ only)": "Использовать системный промпт (только Claude 2.1+)", "Send the system prompt for supported models. If disabled, the user message is added to the beginning of the prompt.": "Отправлять системный промпт для поддерживаемых моделей. Если отключено, сообщение пользователя добавляется в начало промпта.", @@ -880,7 +880,7 @@ "Insert prompt": "Вставить промпт", "Delete prompt": "Удалить промпт", "Import a prompt list": "Импортировать список промптов", - "Export this prompt list": "Экспортировать этот список промпт", + "Export this prompt list": "Экспортировать этот список промптов", "Reset current character": "Сбросить текущего персонажа", "New prompt": "Новый промпт", "Tokens": "токенов", @@ -1176,5 +1176,89 @@ "ext_sum_injection_template": "Шаблон для инжекта", "ext_sum_memory_template_placeholder": "Макрос {{summary}} будет заменён на содержимое пересказа", "ext_sum_injection_position": "Куда инжектить", - "How many messages before the current end of the chat.": "Сколько сообщений от конца чата." + "How many messages before the current end of the chat.": "Сколько сообщений от конца чата.", + "Official Documentation": "официальной документацией", + "Change it later in the 'User Settings' panel.": "Его можно будет выключить в меню \"Настройки пользователя\"", + "Looking for AI characters?": "Ищете ИИ-персонажей?", + "onboarding_import": "Импортируйте", + "from supported sources or view": "из источника или посмотрите", + "Sample characters": "Стандартных персонажей", + "popup_text_save": "Сохранить", + "popup_text_yes": "Да", + "popup_text_no": "Нет", + "popup_text_cancel": "Отмена", + "Enter the URL of the content to import": "Введите URL-адрес импортируемого контента", + "Supported sources:": "Поддерживаются следующие источники:", + "char_import_example": "Пример:", + "char_import_1": "Персонаж с Chub (прямая ссылка или ID)", + "char_import_2": "Лорбук с Chub (прямая ссылка или ID)", + "char_import_3": "Персонаж с JanitorAI (прямая ссылка или UUID)", + "char_import_4": "Персонаж с Pygmalion.chat (прямая ссылка или UUID)", + "char_import_5": "Персонаж с AICharacterCard.com (прямая ссылка или ID)", + "char_import_6": "Прямая ссылка на PNG-файл (чтобы узнать список разрешённых хостов, загляните в", + "char_import_7": ")", + "popup_text_import": "Импортировать", + "Grammar String": "Грамматика", + "GNBF or ENBF, depends on the backend in use. If you're using this you should know which.": "GNBF или ENBF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.", + "Account": "Аккаунт", + "Hi,": "Привет,", + "To enable multi-account features, restart the SillyTavern server with": "Чтобы активировать систему аккаунтов, перезапустите SillyTavern, выставив", + "set to true in the config.yaml file.": "в файле config.yaml в положение true.", + "Account Info": "Об аккаунте", + "Handle:": "Хэндл:", + "Role:": "Роль:", + "Created:": "Создан:", + "Password:": "Пароль:", + "This account is password protected.": "Аккаунт защищён паролем.", + "This account is not password protected.": "Аккаунт не защищён паролем.", + "Account Actions": "Действия", + "Settings Snapshots": "Снимки настроек", + "Manage your settings snapshots.": "Управление снимками настроек.", + "Download Backup": "Скачать бэкап", + "Download a complete backup of your user data.": "Скачать полный бэкап данных пользователя.", + "Danger Zone": "Опасно", + "Reset Settings": "Сбросить настройки", + "Reset your settings to factory defaults.": "Сбросить настройки до заводских.", + "Reset Everything": "Сбросить всё", + "Wipe all user data and reset your account to factory settings.": "Стереть все данные пользователя и сбросить аккаунт до заводских настроек.", + "Set your custom avatar.": "Установить аватарку", + "Remove your custom avatar.": "Сбросить аватарку", + "Make a Snapshot": "Сделать снимок", + "Avoid cropping and resizing imported character images. When off, crop/resize to 512x768": "Не менять размер картинок у импортируемых персонажей. При отключении все картинки будут приводиться к размеру 512х768", + "Char List Subheader": "Доп. заголовок в списке персонажей", + "# Messages to Load": "Сколько сообщений загружать", + "(0 = All)": "(0 = все)", + "Theme Colors": "Цвета темы", + "Specify colors for your theme.": "Настройте собственные цвета для вашей темы.", + "Update speed of streamed text.": "Скорость обновления текста при стриминге.", + "The number of chat history messages to load before pagination.": "Кол-во сообщений чата, загружаемых перед пагинацией.", + "Chat Width": "Ширина чата", + "Width of the main chat window in % of screen width": "Ширина окна с чатом, в % от ширины экрана", + "Blur strength on UI panels.": "Сила размытия на панелях UI.", + "Font size": "Размер шрифта", + "Strength of the text shadows": "Размер теней, отбрасываемых текстом", + "Total Tokens:": "Всего токенов:", + "prompt_manager_edit": "Редактирование", + "prompt_manager_tokens": "Токенов", + "prompt_manager_name": "Имя", + "A name for this prompt.": "Имя данного промпта.", + "To whom this message will be attributed.": "От чьего лица будет отправляться сообщение.", + "AI Assistant": "ИИ-ассистент", + "prompt_manager_position": "Точка инжекта", + "Injection position. Next to other prompts (relative) or in-chat (absolute).": "Как рассчитывать позицию для инжекта. Она может располагаться по отношению к другим промптам (относительная) либо по отношению к чату (абсолютная).", + "prompt_manager_relative": "Относительная", + "prompt_manager_absolute": "Абсолютная", + "prompt_manager_depth": "Глубина", + "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Глубина вставки. 0 = после последнего сообщения, 1 = перед последним сообщением, и т.д.", + "The prompt to be sent.": "Отправляемый ИИ промпт.", + "prompt_manager_forbid_overrides": "Запретить перезапись", + "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Карточка персонажа не сможет перезаписать этот промпт, даже если настройки отдают приоритет именно ей.", + "image_inlining_hint_1": "Отправлять картинки как часть промпта, если позволяет модель (такой функционал поддерживают GPT-4V, Claude 3 или Llava 13B). Чтобы добавить в чат изображение, используйте на нужном сообщении действие", + "image_inlining_hint_2": ". Также это можно сделать через меню", + "image_inlining_hint_3": ".", + "Contest Winners": "Победители конкурса", + "Rename background": "Переименовать фон", + "Lock": "Закрепить", + "Unlock": "Открепить", + "Delete background": "Удалить фон" } diff --git a/public/script.js b/public/script.js index f9e781b85..5b92efc60 100644 --- a/public/script.js +++ b/public/script.js @@ -205,7 +205,7 @@ import { instruct_presets, selectContextPreset, } from './scripts/instruct-mode.js'; -import { initLocales } from './scripts/i18n.js'; +import { initLocales, applyLocale } from './scripts/i18n.js'; import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, getTokenizerModel, initTokenizers, saveTokenCache } from './scripts/tokenizers.js'; import { user_avatar, @@ -854,12 +854,12 @@ async function firstLoadInit() { throw new Error('Initialization failed'); } - await getSystemMessages(); - sendSystemMessage(system_message_types.WELCOME); await getClientVersion(); await readSecretState(); + initLocales(); // this function needs to be executed this late because otherwise, locale file fails to load on time sometimes + await getSystemMessages(); + sendSystemMessage(system_message_types.WELCOME); await getSettings(); - initLocales(); initTags(); await getUserAvatars(true, user_avatar); await getCharacters(); @@ -10370,17 +10370,17 @@ jQuery(async function () { }); $(document).on('click', '.external_import_button, #external_import_button', async () => { - const html = `<h3>Enter the URL of the content to import</h3> - Supported sources:<br> + const html = applyLocale(`<h3 data-i18n="Enter the URL of the content to import">Enter the URL of the content to import</h3> + <span data-i18n="Supported sources:">Supported sources:</span><br> <ul class="justifyLeft"> - <li>Chub Character (Direct Link or ID)<br>Example: <tt>Anonymous/example-character</tt></li> - <li>Chub Lorebook (Direct Link or ID)<br>Example: <tt>lorebooks/bartleby/example-lorebook</tt></li> - <li>JanitorAI Character (Direct Link or UUID)<br>Example: <tt>ddd1498a-a370-4136-b138-a8cd9461fdfe_character-aqua-the-useless-goddess</tt></li> - <li>Pygmalion.chat Character (Direct Link or UUID)<br>Example: <tt>a7ca95a1-0c88-4e23-91b3-149db1e78ab9</tt></li> - <li>AICharacterCard.com Character (Direct Link or ID)<br>Example: <tt>AICC/aicharcards/the-game-master</tt></li> - <li>Direct PNG Link (refer to <code>config.yaml</code> for allowed hosts)<br>Example: <tt>https://files.catbox.moe/notarealfile.png</tt></li> - <ul>`; - const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '', { okButton: 'Import', rows: 4 }); + <li><span data-i18n="char_import_1">Chub Character (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>Anonymous/example-character</tt></li> + <li><span data-i18n="char_import_2">Chub Lorebook (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>lorebooks/bartleby/example-lorebook</tt></li> + <li><span data-i18n="char_import_3">JanitorAI Character (Direct Link or UUID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>ddd1498a-a370-4136-b138-a8cd9461fdfe_character-aqua-the-useless-goddess</tt></li> + <li><span data-i18n="char_import_4">Pygmalion.chat Character (Direct Link or UUID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>a7ca95a1-0c88-4e23-91b3-149db1e78ab9</tt></li> + <li><span data-i18n="char_import_5">AICharacterCard.com Character (Direct Link or ID)</span><br><span data-i18n="char_import_example">Example:</span> <tt>AICC/aicharcards/the-game-master</tt></li> + <li><span data-i18n="char_import_6">Direct PNG Link (refer to</span> <code>config.yaml</code><span data-i18n="char_import_7"> for allowed hosts)</span><br><span data-i18n="char_import_example">Example:</span> <tt>https://files.catbox.moe/notarealfile.png</tt></li> + <ul>`); + const input = await callGenericPopup(html, POPUP_TYPE.INPUT, '', { okButton: $('#shadow_popup_template').attr('popup_text_import'), rows: 4 }); if (!input) { console.debug('Custom content import cancelled'); diff --git a/public/scripts/PromptManager.js b/public/scripts/PromptManager.js index d45da25bf..97d44164c 100644 --- a/public/scripts/PromptManager.js +++ b/public/scripts/PromptManager.js @@ -6,6 +6,7 @@ import { Message, TokenHandler } from './openai.js'; import { power_user } from './power-user.js'; import { debounce, waitUntilCondition, escapeHtml } from './utils.js'; import { debounce_timeout } from './constants.js'; +import { applyLocale } from './i18n.js' function debouncePromise(func, delay) { let timeoutId; @@ -1097,12 +1098,12 @@ class PromptManager { createQuickEdit(identifier, title) { const prompt = this.getPromptById(identifier); const textareaIdentifier = `${identifier}_prompt_quick_edit_textarea`; - const html = `<div class="range-block m-t-1"> + const html = applyLocale(`<div class="range-block m-t-1"> <div class="justifyLeft" data-i18n="${title}">${title}</div> <div class="wide100p"> <textarea id="${textareaIdentifier}" class="text_pole textarea_compact" rows="6" placeholder="">${prompt.content}</textarea> </div> - </div>`; + </div>`); const quickEditContainer = document.getElementById('quick-edit-container'); quickEditContainer.insertAdjacentHTML('afterbegin', html); @@ -1355,18 +1356,18 @@ class PromptManager { const totalActiveTokens = this.tokenUsage; - promptManagerDiv.insertAdjacentHTML('beforeend', ` + promptManagerDiv.insertAdjacentHTML('beforeend', applyLocale(` <div class="range-block"> ${this.error ? errorDiv : ''} <div class="${this.configuration.prefix}prompt_manager_header"> <div class="${this.configuration.prefix}prompt_manager_header_advanced"> <span data-i18n="Prompts">Prompts</span> </div> - <div>Total Tokens: ${totalActiveTokens} </div> + <div><span data-i18n="Total Tokens:">Total Tokens:</span> ${totalActiveTokens} </div> </div> <ul id="${this.configuration.prefix}prompt_manager_list" class="text_pole"></ul> </div> - `); + `)); this.listElement = promptManagerDiv.querySelector(`#${this.configuration.prefix}prompt_manager_list`); @@ -1384,7 +1385,7 @@ class PromptManager { selectedPromptIndex = 0; } - const footerHtml = ` + const footerHtml = applyLocale(` <div class="${this.configuration.prefix}prompt_manager_footer"> <select id="${this.configuration.prefix}prompt_manager_footer_append_prompt" class="text_pole" name="append-prompt"> ${promptsHtml} @@ -1396,7 +1397,7 @@ class PromptManager { <a class="menu_button fa-undo fa-solid" id="prompt-manager-reset-character" title="Reset current character" data-i18n="[title]Reset current character"></a> <a class="menu_button fa-plus-square fa-solid" title="New prompt" data-i18n="[title]New prompt"></a> </div> - `; + `); const rangeBlockDiv = promptManagerDiv.querySelector('.range-block'); const headerDiv = promptManagerDiv.querySelector('.completion_prompt_manager_header'); @@ -1410,12 +1411,12 @@ class PromptManager { footerDiv.querySelector('select').selectedIndex = selectedPromptIndex; // Add prompt export dialogue and options - const exportForCharacter = ` + const exportForCharacter = applyLocale(` <div class="row"> <a class="export-promptmanager-prompts-character list-group-item" data-i18n="Export for character">Export for character</a> <span class="tooltip fa-solid fa-info-circle" title="Export prompts for this character, including their order."></span> - </div>`; - const exportPopup = ` + </div>`); + const exportPopup = applyLocale(` <div id="prompt-manager-export-format-popup" class="list-group"> <div class="prompt-manager-export-format-popup-flex"> <div class="row"> @@ -1425,7 +1426,7 @@ class PromptManager { ${'global' === this.configuration.promptOrder.strategy ? '' : exportForCharacter} </div> </div> - `; + `); rangeBlockDiv.insertAdjacentHTML('beforeend', exportPopup); @@ -1468,16 +1469,16 @@ class PromptManager { const { prefix } = this.configuration; - let listItemHtml = ` + let listItemHtml = applyLocale(` <li class="${prefix}prompt_manager_list_head"> <span data-i18n="Name">Name</span> <span></span> - <span class="prompt_manager_prompt_tokens" data-i18n="Tokens">Tokens</span> + <span class="prompt_manager_prompt_tokens" data-i18n="Tokens;prompt_manager_tokens">Tokens</span> </li> <li class="${prefix}prompt_manager_list_separator"> <hr> </li> - `; + `); this.getPromptsForCharacter(this.activeCharacter).forEach(prompt => { if (!prompt) return; diff --git a/public/scripts/i18n.js b/public/scripts/i18n.js index c4e837939..5f2d05bca 100644 --- a/public/scripts/i18n.js +++ b/public/scripts/i18n.js @@ -126,16 +126,17 @@ export function applyLocale(root = document) { function addLanguagesToDropdown() { + const uiLanguageSelects = $('#ui_language_select, #onboarding_ui_language_select'); for (const langObj of langs) { // Set the value to the language code const option = document.createElement('option'); option.value = langObj['lang']; // Set the value to the language code option.innerText = langObj['display']; // Set the display text to the language name - $('#ui_language_select').append(option); + uiLanguageSelects.append(option); } const selectedLanguage = localStorage.getItem(storageKey); if (selectedLanguage) { - $('#ui_language_select').val(selectedLanguage); + uiLanguageSelects.val(selectedLanguage); } } @@ -144,7 +145,7 @@ export function initLocales() { addLanguagesToDropdown(); updateSecretDisplay(); - $('#ui_language_select').on('change', async function () { + $('#ui_language_select, #onboarding_ui_language_select').on('change', async function () { const language = String($(this).val()); if (language) { diff --git a/public/scripts/popup.js b/public/scripts/popup.js index c69aa6e60..f7dfe9f81 100644 --- a/public/scripts/popup.js +++ b/public/scripts/popup.js @@ -68,9 +68,10 @@ export class Popup { if (allowHorizontalScrolling) dlg.classList.add('horizontal_scrolling_dialogue_popup'); if (allowVerticalScrolling) dlg.classList.add('vertical_scrolling_dialogue_popup'); + const localeDataHolder = $('#shadow_popup_template'); this.ok.textContent = okButton ?? 'OK'; - this.cancel.textContent = cancelButton ?? 'Cancel'; - + this.cancel.textContent = cancelButton ?? localeDataHolder.attr('popup_text_cancel'); + switch (type) { case POPUP_TYPE.TEXT: { this.input.style.display = 'none'; @@ -79,13 +80,13 @@ export class Popup { } case POPUP_TYPE.CONFIRM: { this.input.style.display = 'none'; - this.ok.textContent = okButton ?? 'Yes'; - this.cancel.textContent = cancelButton ?? 'No'; + this.ok.textContent = okButton ?? localeDataHolder.attr('popup_text_yes'); + this.cancel.textContent = cancelButton ?? localeDataHolder.attr('popup_text_no'); break; } case POPUP_TYPE.INPUT: { this.input.style.display = 'block'; - this.ok.textContent = okButton ?? 'Save'; + this.ok.textContent = okButton ?? localeDataHolder.attr('popup_text_save'); break; } default: { diff --git a/public/scripts/templates/userProfile.html b/public/scripts/templates/userProfile.html index cf17c9c85..e1eb34ecd 100644 --- a/public/scripts/templates/userProfile.html +++ b/public/scripts/templates/userProfile.html @@ -1,17 +1,17 @@ <div class="flex-container flexFlowColumn justifyLeft flexGap10"> <div> <h2 class="marginBot10 flex-container"> - <span>Hi,</span><span class="userName margin0"></span> + <span data-i18n="Hi,">Hi,</span><span class="userName margin0"></span> <div data-require-accounts class="userChangeNameButton right_menu_button" title="Change display name."> <i class="fa-fw fa-solid fa-pencil fa-xs"></i> </div> </h2> <div class="accountsDisabledHint" style="display: none;"> - To enable multi-account features, restart the SillyTavern server with <code>enableUserAccounts</code> set to true in the config.yaml file. + <span data-i18n="To enable multi-account features, restart the SillyTavern server with">To enable multi-account features, restart the SillyTavern server with</span> <code>enableUserAccounts</code> <span data-i18n="set to true in the config.yaml file.">set to true in the config.yaml file.</span> </div> </div> <div> - <h3> + <h3 data-i18n="Account Info"> Account Info </h3> <div class="flex-container flexGap10"> @@ -20,10 +20,10 @@ <img src="img/ai4.png" alt="avatar"> </div> <div class="flex-container alignItemsCenter"> - <div class="userAvatarChange right_menu_button" title="Set your custom avatar."> + <div class="userAvatarChange right_menu_button" data-i18n="[title]Set your custom avatar." title="Set your custom avatar."> <i class="fa-fw fa-solid fa-image"></i> </div> - <div class="userAvatarRemove right_menu_button" title="Remove your custom avatar."> + <div class="userAvatarRemove right_menu_button" data-i18n="[title]Remove your custom avatar." title="Remove your custom avatar."> <i class="fa-fw fa-solid fa-trash"></i> </div> </div> @@ -49,15 +49,15 @@ </div> <div> <span data-i18n="Password:">Password:</span> - <i class="hasPassword fa-fw fa-solid fa-lock" title="This account is password protected."></i> - <i class="noPassword fa-fw fa-solid fa-lock-open" title="This account is not password protected."></i> + <i class="hasPassword fa-fw fa-solid fa-lock" data-i18n="[title]This account is password protected." title="This account is password protected."></i> + <i class="noPassword fa-fw fa-solid fa-lock-open" data-i18n="[title]This account is not password protected." title="This account is not password protected."></i> </div> </div> </div> </div> </div> <div> - <h3> + <h3 data-i18n="Account Actions"> Account Actions </h3> <div class="flex-container flexFlowColumn flexNoGap"> @@ -68,11 +68,11 @@ </div> </div> <div class="flex-container"> - <div class="userSettingsSnapshotsButton menu_button menu_button_icon" title="Manage your settings snapshots."> + <div class="userSettingsSnapshotsButton menu_button menu_button_icon" data-i18n="[title]Manage your settings snapshots." title="Manage your settings snapshots."> <i class="fa-fw fa-solid fa-camera"></i> <span data-i18n="Settings Snapshots">Settings Snapshots</span> </div> - <div class="userBackupButton menu_button menu_button_icon" title="Download a complete backup of your user data."> + <div class="userBackupButton menu_button menu_button_icon" data-i18n="[title]Download a complete backup of your user data." title="Download a complete backup of your user data."> <i class="fa-fw fa-solid fa-download"></i> <span data-i18n="Download Backup">Download Backup</span> </div> @@ -80,15 +80,15 @@ </div> </div> <div> - <h3> + <h3 data-i18n="Danger Zone"> Danger Zone </h3> <div class="flex-container"> - <div class="userResetSettingsButton menu_button menu_button_icon" title="Reset your settings to factory defaults."> + <div class="userResetSettingsButton menu_button menu_button_icon" data-i18n="[title]Reset your settings to factory defaults." title="Reset your settings to factory defaults."> <i class="fa-fw fa-solid fa-cog warning"></i> <span data-i18n="Reset Settings">Reset Settings</span> </div> - <div class="userResetAllButton menu_button menu_button_icon" title="Wipe all user data and reset your account to factory settings."> + <div class="userResetAllButton menu_button menu_button_icon" data-i18n="[title]Wipe all user data and reset your account to factory settings." title="Wipe all user data and reset your account to factory settings."> <i class="fa-fw fa-solid fa-skull warning"></i> <span data-i18n="Reset Everything">Reset Everything</span> </div>