Work on tl

11908f7363651bf434cf23c1d8bb39feab12e9ad

Yokayo <nonameutubecomm@gmail.com>

13 files changed, +191 -61Showing whitespace changes
public/css/rm-groups.css+2 -2
@@ -87,7 +87,7 @@
8787}
8888
8989#rm_group_members:empty::before {
90- content: 'Group is empty';
90+ content: attr(group_empty_text);
9191
9292 font-weight: bolder;
9393 width: 100%;
@@ -115,7 +115,7 @@
115115}
116116
117117#rm_group_add_members:empty::before {
118- content: 'No characters available';
118+ content: attr(no_characters_text);
119119
120120 font-weight: bolder;
121121 width: 100%;
public/index.html+8 -8
@@ -2052,8 +2052,8 @@
20522052 <div class="flex-container oneline-dropdown" title="Constrains effort on reasoning for reasoning models.&#10;Reducing reasoning effort can result in faster responses and fewer tokens used on reasoning in a response." data-i18n="[title]Constrains effort on reasoning for reasoning models.">
20532053 <label for="openai_reasoning_effort">
20542054 <span data-i18n="Reasoning Effort">Reasoning Effort</span>
20552055 <i data-source="openai,custom,xai,openrouter" class="opacity50p fa-solid fa-circle-info" title="OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level." data-i18n="[title]OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level."></i>
20562056 <i data-source="claude,makersuite" class="opacity50p fa-solid fa-circle-info" title="Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent." data-i18n="[title]Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent."></i>
20572057 </label>
20582058 <select id="openai_reasoning_effort">
20592059 <option data-i18n="openai_reasoning_effort_auto" value="auto">Auto</option>
@@ -2498,8 +2498,8 @@
24982498 <option value="search" data-i18n="Search" hidden>A-Z</option>
24992499 <option value="asc">A-Z</option>
25002500 <option value="desc">Z-A</option>
25012501 <option data-i18n="Date Asc" value="date_asc">Date Asc</option>
25022502 <option data-i18n="Date Desc" value="date_desc">Date Desc</option>
25032503 </select>
25042504 <select id="featherless_category_selection" class="text_pole">
25052505 <option value="" disabled selected data-i18n="category">category</option>
@@ -2509,7 +2509,7 @@
25092509 <option value="All" data-i18n="All">All</option>
25102510 </select>
25112511 <select id="featherless_class_selection" class="text_pole">
25122512 <option value="" selected data-i18n="classAll Classes">All Classes</option>
25132513 </select>
25142514 <div id="featherless_model_pagination_container" class="flex1"></div>
25152515 <i id="featherless_model_grid_toggle" class="fa-solid fa-table-cells-large menu_button" data-i18n="[title]Toggle grid view" title="Toggle grid view"></i>
@@ -5534,7 +5534,7 @@
55345534 <div class="inline-drawer-content">
55355535 <div id="currentGroupMembers" name="Current Group Members" class="flex-container flexFlowColumn overflowYAuto flex1">
55365536 <div id="rm_group_members_pagination" class="rm_group_members_pagination group_pagination"></div>
55375537 <div id="rm_group_members" class="rm_group_members overflowYAuto flex-container" group_empty_text="Group is empty." data-i18n="[group_empty_text]Group is empty."></div>
55385538 </div>
55395539 </div>
55405540 </div>
@@ -5552,7 +5552,7 @@
55525552 <div class="tags rm_tag_filter"></div>
55535553 </div>
55545554 <div id="rm_group_add_members_pagination" class="group_pagination"></div>
55555555 <div id="rm_group_add_members" class="overflowYAuto flex-container" no_characters_text="No characters available" data-i18n="[no_characters_text]No characters available"></div>
55565556 </div>
55575557 </div>
55585558 </div>
@@ -5972,7 +5972,7 @@
59725972 <div class="tag_view_color_picker" data-value="color"></div>
59735973 <div class="tag_view_color_picker" data-value="color2"></div>
59745974 <div class="tag_view_name" contenteditable="true"></div>
59755975 <div class="tag_view_counter"><span class="tag_view_counter_value"></span>&nbsp;<span data-i18n="tag_entries">entries</span></div>
59765976 <div title="Delete tag" class="tag_delete fa-solid fa-trash-can right_menu_button" data-i18n="[title]Delete tag"></div>
59775977 </div>
59785978 </div>
public/locales/ru-ru.json+104 -22
@@ -52,7 +52,7 @@
5252 "Presence Penalty": "Штраф за присутствие",
5353 "Top A": "Top А",
5454 "Tail Free Sampling": "Tail Free Sampling",
5555 "Rep. Pen. Slope": "Rep.Рост Pen.штрафа Slopeза повтор к концу промпта",
5656 "Top K": "Top K",
5757 "Top P": "Top P",
5858 "Do Sample": "Включить сэмплинг",
@@ -162,9 +162,9 @@
162162 "Story String": "Строка истории",
163163 "Example Separator": "Разделитель примеров сообщений",
164164 "Chat Start": "Начало чата",
165165 "Activation Regex": "RegexРег. выражение для активации",
166166 "Instruct Mode": "Режим Instruct",
167167 "Wrap Sequences with Newline": "ОтделятьКаждая строкистрока символомиз шаблона на новой строкистроке",
168168 "Include Names": "Добавлять имена",
169169 "Force for Groups and Personas": "Также для групп и персон",
170170 "System Prompt": "Системный промпт",
@@ -299,7 +299,7 @@
299299 "AI Horde": "AI Horde",
300300 "NovelAI": "NovelAI",
301301 "OpenAI API key": "Ключ для API OpenAI",
302302 "Trim spaces": "Обрезать пробелы в начале и конце",
303303 "Trim Incomplete Sentences": "Удалять неоконченные предложения",
304304 "Include Newline": "Добавлять новую строку",
305305 "Non-markdown strings": "Строки без разметки",
@@ -510,7 +510,7 @@
510510 "New preset": "Новый пресет",
511511 "Delete preset": "Удалить пресет",
512512 "API Connections": "Соединения с API",
513513 "Can help with bad responses by queueing only the approved workers. May slowdown the response time.": "Может помочь с плохимипри ответамиплохих ставяответах, вделая очередьзапросы только подтвержденныхк работниковдоверенным рабочим машинам. Может замедлить время ответа.",
514514 "Clear your API key": "Стереть ключ от API",
515515 "Refresh models": "Обновить модели",
516516 "Get your OpenRouter API token using OAuth flow. You will be redirected to openrouter.ai": "Получите свой OpenRouter API токен используя OAuth. У вас будет открыта вкладка openrouter.ai",
@@ -551,7 +551,7 @@
551551 "Token counts may be inaccurate and provided just for reference.": "Счетчик токенов может быть неточным, используйте как ориентир",
552552 "Click to select a new avatar for this character": "Нажмите чтобы выбрать новый аватар для этого персонажа",
553553 "Example: [{{user}} is a 28-year-old Romanian cat girl.]": "Пример:\n [{{user}} is a 28-year-old Romanian cat girl.]",
554554 "Toggle grid view": "ПереключитьСменить вид сетки",
555555 "Add to Favorites": "Добавить в Избранное",
556556 "Advanced Definition": "Расширенное описание",
557557 "Character Lore": "Лор персонажа",
@@ -624,7 +624,7 @@
624624 "UI Theme": "Тема UI",
625625 "This message is invisible for the AI": "Это сообщение невидимо для ИИ",
626626 "Sampler Priority": "Приоритет сэмплеров",
627627 "Ooba only. Determines the order of samplers.": "Только для oobabooga. Определяет порядок сэмплеров.",
628628 "Load default order": "Загрузить стандартный порядок",
629629 "Max Tokens Second": "Макс. кол-во токенов в секунду",
630630 "CFG": "CFG",
@@ -695,7 +695,7 @@
695695 "Medium": "Средний",
696696 "Aggressive": "Агрессивный",
697697 "Very aggressive": "Очень агрессивный",
698698 "Eta_Cutoff_desc": "Eta cutoff - основной параметр специальной техники сэмплинга под названием Eta Sampling.&#13;В\nВ единицах 1e-4; разумное значение - 3.&#13;Установите\nУстановите в 0, чтобы отключить.&#13;См\nСм. статью Truncation Sampling as Language Model Desmoothing от Хьюитт и др. (2022) для получения подробной информации.",
699699 "Learn how to contribute your idle GPU cycles to the Horde": "Узнайте, как использовать время простоя вашего GPU для помощи Horde",
700700 "Use the appropriate tokenizer for Google models via their API. Slower prompt processing, but offers much more accurate token counting.": "Используйте соответствующий токенизатор для моделей Google через их API. Медленная обработка подсказок, но предлагает намного более точный подсчет токенов.",
701701 "Load koboldcpp order": "Загрузить порядок из koboldcpp",
@@ -964,7 +964,7 @@
964964 "char_import_3": "Персонаж с JanitorAI (прямая ссылка или UUID)",
965965 "char_import_4": "Персонаж с Pygmalion.chat (прямая ссылка или UUID)",
966966 "char_import_5": "Персонаж с AICharacterCards.com (прямая ссылка или ID)",
967967 "char_import_6": "Прямая ссылка на PNG-файл (чтобы узнать список разрешённых хостов, заглянитенаходится в",
968968 "char_import_7": ")",
969969 "Grammar String": "Грамматика",
970970 "GBNF or EBNF, depends on the backend in use. If you're using this you should know which.": "GBNF или EBNF, зависит от бэкенда. Если вы это используете, то, скорее всего, сами знаете, какой именно.",
@@ -1016,7 +1016,7 @@
10161016 "prompt_manager_relative": "Относительная",
10171017 "prompt_manager_depth": "Глубина",
10181018 "Injection depth. 0 = after the last message, 1 = before the last message, etc.": "Глубина вставки. 0 = после последнего сообщения, 1 = перед последним сообщением, и т.д.",
10191019 "The prompt to be sent.": "Отправляемый ИИТекст промптпромпта.",
10201020 "prompt_manager_forbid_overrides": "Запретить перезапись",
10211021 "This prompt cannot be overridden by character cards, even if overrides are preferred.": "Карточка персонажа не сможет перезаписать этот промпт, даже если настройки отдают приоритет именно ей.",
10221022 "image_inlining_hint_1": "Отправлять картинки как часть промпта, если позволяет модель (такой функционал поддерживают GPT-4V, Claude 3 или Llava 13B). Чтобы добавить в чат изображение, используйте на нужном сообщении действие",
@@ -1232,7 +1232,7 @@
12321232 "Top P & Min P": "Top P & Min P",
12331233 "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.": "llama.cpp only. Determines the order of samplers. If Mirostat mode is not 0, sampler order is ignored.",
12341234 "Helps the model to associate messages with characters.": "Помогает модели связывать сообщения с персонажами.",
12351235 "character_names_default": "ExceptДобавлять forпрефиксы groupsдля andгрупповых pastчатов personasи предыдущих персон. Otherwise,В makeостальных sureслучаях youуказывайте provideимена namesв inпромпте theиными promptспособами.",
12361236 "Completion": "Completion Object",
12371237 "character_names_completion": "Только латинские буквы, цифры и знак подчёркивания. Работает не для всех бэкендов, в частности для Claude, MistralAI, Google.",
12381238 "Use AI21 Tokenizer": "Использовать токенайзер AI21",
@@ -1278,7 +1278,7 @@
12781278 "Will be inserted as a last prompt line when using system/neutral generation.": "Will be inserted as a last prompt line when using system/neutral generation.",
12791279 "If a stop sequence is generated, everything past it will be removed from the output (inclusive).": "Если ИИ генерирует стоп-строку, то всё после неё будет вырезано из ответа (включая и саму стоп-строку).",
12801280 "Will be inserted at the start of the chat history if it doesn't start with a User message.": "Вставляется в начале истории чата, если она начинается не с сообщения пользователя.",
12811281 "Global World Info/Lorebook activation settings": "НастройкиГлобальные активациинастройки глобальногоактивации лорбука / Информации о мире",
12821282 "Click to expand": "Щёлкните, чтобы развернуть",
12831283 "Insertion Strategy": "Как инжектить",
12841284 "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "Only the entries with the most number of key matches will be selected for Inclusion Group filtering",
@@ -1647,8 +1647,8 @@
16471647 "mui_reset": "Сброс",
16481648 "Quick 'Impersonate' button": "Быстрое перевоплощение",
16491649 "Show a button in the input area to ask the AI to impersonate your character for a single message": "Показать в поле ввода кнопку, по нажатии на которую ИИ сгенерирует одно сообщение от лица вашего персонажа.",
16501650 "Separators as Stop Strings": "Разделители какв качестве стоп-строкистрок",
16511651 "Names as Stop Strings": "Имена какв качестве стоп-строкистрок",
16521652 "Add Character and User names to a list of stopping strings.": "Добавлять имена персонажа и пользователя в список стоп-строк.",
16531653 "Allow Post-History Instructions": "Разрешить инструкции после истории",
16541654 "context_allow_post_history_instructions": "Добавлять в конец промпта инструкции после истории. Работает только при наличии таких инструкций в карточке И при включенной опции ''Приоритет инструкциям из карточек''.\nНЕ РЕКОМЕНДУЕТСЯ ДЛЯ МОДЕЛЕЙ TEXT COMPLETION, МОЖЕТ ПОРТИТЬ ВЫХОДНОЙ ТЕКСТ.",
@@ -1916,8 +1916,8 @@
19161916 "Cannot restore GUI preset": "Пресет для Gui восстановить нельзя",
19171917 "Default preset cannot be restored": "Невозможно восстановить пресет по умолчанию",
19181918 "Default template cannot be restored": "Невозможно восстановить шаблон по умолчанию",
19191919 "Resetting a <b>default preset</b> will restore the default settings.": "Сброс <b>стандартногокомплектного пресета</b> восстановит настройки по умолчанию.",
19201920 "Resetting a <b>default template</b> will restore the default settings.": "Сброс <b>стандартногокомплектного шаблона</b> восстановит настройки по умолчанию.",
19211921 "Are you sure?": "Вы уверены?",
19221922 "Default preset restored": "Стандартный пресет восстановлен",
19231923 "Default template restored": "Стандартный шаблон восстановлен",
@@ -2048,11 +2048,11 @@
20482048 "prompt_post_processing_merge": "Объединять идущие подряд сообщения с одной ролью",
20492049 "prompt_post_processing_semi": "Semi-strict (чередовать роли)",
20502050 "prompt_post_processing_strict": "Strict (чередовать роли, сначала пользователь)",
20512051 "Select Horde models": "ВыбратьВыберите модель из Horde",
20522052 "Model ID (optional)": "Идентификатор модели (необязательно)",
20532053 "Derive context size from backend": "Использовать бэкенд для определения размера контекста",
20542054 "Rename current preset": "Переименовать пресет",
20552055 "No Worlds active. Click here to select.": "Нет активныхАктивных миров. Нажмитенет, чтобыЛКМ выбратьдля выбора.",
20562056 "Title/Memo": "Название",
20572057 "Strategy": "Статус",
20582058 "Position": "Позиция",
@@ -2171,7 +2171,7 @@
21712171 "instruct_derived": "Считывать из метаданных модели (по возможности)",
21722172 "Confirm token parsing with": "Чтобы убедиться в правильности выделения токенов, используйте",
21732173 "Reasoning Effort": "Рассуждения",
21742174 "Constrains effort on reasoning for reasoning models.": "Регулирует объём внутренних рассуждений модели (reasoning), для моделей, которые поддерживают эту возможность.\nНа данный момент поддерживаются три значения: Подробные, Обычные, Поверхностные.\nПри менее подробном рассуждении ответ получается быстрее, а также экономятся токены, уходящие на рассуждения.",
21752175 "openai_reasoning_effort_low": "Поверхностные",
21762176 "openai_reasoning_effort_medium": "Обычные",
21772177 "openai_reasoning_effort_high": "Подробные",
@@ -2276,8 +2276,8 @@
22762276 "Persona Name Not Set": "У персоны отсутствует имя",
22772277 "You must bind a name to this persona before you can set a lorebook.": "Перед привязкой лорбука персоне необходимо присвоить имя.",
22782278 "Default Persona Removed": "Персона по умолчанию снята",
22792279 "Persona is locked to the current character": "Персона закреплена за этимтекущим персонажем",
22802280 "Persona is locked to the current chat": "Персона закреплена за этимтекущим чатом",
22812281 "characters": "перс.",
22822282 "character": "персонаж",
22832283 "in this group": "в группе",
@@ -2338,5 +2338,87 @@
23382338 "Reasoning already exists.": "Рассуждения уже присутствуют.",
23392339 "Edit Message": "Редактирование",
23402340 "Status check bypassed": "Проверка статуса отключена",
23412341 "Valid": "Работает",
2342+ "Use Group Scoring": "Использовать Group Scoring",
2343+ "Only the entries with the most number of key matches will be selected for Inclusion Group filtering": "До групповых фильтров будут допущены только записи с наибольшим кол-вом совпадений",
2344+ "Can be used to automatically activate Quick Replies": "Используется для автоматической активации быстрых ответов (Quick Replies)",
2345+ "( None )": "(Отсутствует)",
2346+ "Tie this entry to specific characters or characters with specific tags": "Привязать запись к опред. персонажам или персонажам с заданными тегами",
2347+ "Move Entry to Another Lorebook": "Переместить запись в другой лорбук",
2348+ "There are no other lorebooks to move to.": "Некуда перемещать: не найдено других лорбуков.",
2349+ "Select Target Lorebook": "Выберите куда переместить",
2350+ "Move '${0}' to:": "Переместить '${0}' в:",
2351+ "Please select a target lorebook.": "Выберите лорбук, в который будет перемещена запись.",
2352+ "Scan depth cannot be negative": "Глубина сканирования не может быть отрицательной",
2353+ "Scan depth cannot exceed ${0}": "Глубина сканирования не может превышать ${0}",
2354+ "Select your current Reasoning Template": "Выберите текущий Шаблон рассуждений",
2355+ "Delete template": "Удалить шаблон",
2356+ "Reasoning Template": "Шаблон рассуждений",
2357+ "openai_reasoning_effort_auto": "Авто",
2358+ "openai_reasoning_effort_minimum": "Минимальные",
2359+ "openai_reasoning_effort_maximum": "Максимальные",
2360+ "OpenAI-style options: low, medium, high. Minimum and maximum are aliased to low and high. Auto does not send an effort level.": "OpenAI принимает следующее: low (Поверхностные), medium (Обычные), high (Подробные). Minimum (Минимальные) - то же самое, что low. Maximum (Максимальные) - то же самое, что high. При выборе Auto (Авто) значение не отсылается вообще.",
2361+ "Allocates a portion of the response length for thinking (low: 10%, medium: 25%, high: 50%). Other options are model-dependent.": "Резервирует часть ответа для рассуждений (Поверхностные: 10% ответа, Обычные: 25%, Подробные: 50%). Остальные значения зависят от конкретной модели.",
2362+ "xAI Model": "Модель xAI",
2363+ "xAI API Key": "Ключ от API xAI",
2364+ "HuggingFace Token": "Токен HuggingFace",
2365+ "Endpoint URL": "Адрес эндпоинта",
2366+ "Example: https://****.endpoints.huggingface.cloud": "Пример: https://****.endpoints.huggingface.cloud",
2367+ "Featherless Model Selection": "Выбор модели из Featherless",
2368+ "category": "категория",
2369+ "Top": "Топовые",
2370+ "All Classes": "Все классы",
2371+ "Date Asc": "Дата, возрастание",
2372+ "Date Desc": "Дата, убывание",
2373+ "Background Image": "Фоновое изображение",
2374+ "Delete the background?": "Удалить фон?",
2375+ "Tags_as_Folders_desc": "Чтобы тег отображался как папка, его нужно отметить таковым в меню управления тегами. Нажмите сюда, чтобы открыть его.",
2376+ "tag_entries": "раз исп.",
2377+ "Multiple personas are connected to this character.\nSelect a persona to use for this chat.": "К этому персонажу привязано несколько персон.\nВыберите персону, которую хотите использовать в этом чате.",
2378+ "Select Persona": "Выберите персону",
2379+ "Completion Object": "Как часть Completion Object",
2380+ "Move ${0} to:": "Переместить '${0}' в:",
2381+ "Chat Scenario Override": "Перезапись сценария чата",
2382+ "Unique to this chat.": "Действует только в рамках текущего чата.",
2383+ "All group members will use the following scenario text instead of what is specified in their character cards.": "Все участники группы будут использовать этот сценарий вместо того, который указан в карточке.",
2384+ "Checkpoints inherit the scenario override from their parent, and can be changed individually after that.": "Чекпоинты наследуют сценарий родителя, после отделения его можно менять.",
2385+ "Delete Tag": "Удалить тег",
2386+ "Do you want to delete the tag": "Вы точно хотите удалить тег",
2387+ "If you want to merge all references to this tag into another tag, select it below:": "Если хотите заменить ссылки на этот тег на какой-то другой, то выберите из списка:",
2388+ "Open Folder (Show all characters even if not selected)": "Открытая папка (показать всех персонажей, включая невыбранных)",
2389+ "Closed Folder (Hide all characters unless selected)": "Закрытая папка (скрыть всех персонажей, кроме выбранных)",
2390+ "No Folder": "Не папка",
2391+ "Show only favorites": "Показать только избранных персонажей",
2392+ "Show only groups": "Показать только группы",
2393+ "Show only folders": "Показать только папки",
2394+ "Manage tags": "Панель управления тегами",
2395+ "Show Tag List": "Показать список тегов",
2396+ "Clear all filters": "Сбросить все фильтры",
2397+ "There are no items to display.": "Отображать абсолютно нечего.",
2398+ "Characters and groups hidden by filters or closed folders": "Персонажи и группы скрыты настройками фильтров либо закрытыми папками",
2399+ "Otterly empty": "Всё что можно, всё выдрано",
2400+ "Here be dragons": "Список настолько очистился, что в него вернулись драконы",
2401+ "Kiwibunga": "Настолько пусто, что киви прилетела посидеть",
2402+ "Pump-a-Rum": "Пу-пу-пу",
2403+ "Croak it": "Только кваканье лягушек и стрёкот сверчков",
2404+ "${0} ${1} hidden.": "Персонажей скрыто: ${0}.",
2405+ "pagination_of": "из",
2406+ "/ page": "/ стр.",
2407+ "Context Length": "Размер контекста",
2408+ "Added On": "Добавлена",
2409+ "Class": "Класс",
2410+ "Bulk_edit_characters": "Массовое редактирование персонажей\n\nЛКМ, чтобы выделить либо отменить выделение персонажа\nShift+ЛКМ, чтобы массово выделить либо отменить выделение персонажей\nПКМ, чтобы выбрать действие",
2411+ "Bulk select all characters": "Выбрать всех персонажей",
2412+ "Duplicate": "Клонировать",
2413+ "Next page": "След. страница",
2414+ "Previous page": "Пред. страница",
2415+ "Group:": "Группа:",
2416+ "You deleted a character/chat and arrived back here for safety reasons! Pick another character!": "Вы удалили персонажа или чат, и мы из соображений безопасности перенесли вас на эту страницу! Выберите другого персонажа!",
2417+ "Group is empty.": "Группа пуста.",
2418+ "No characters available": "Персонажей нет",
2419+ "Choose what to export": "Выберите, что экспортировать",
2420+ "Text Completion Preset": "Пресет для режима Text Completion",
2421+ "Update enabled": "Обновить включенные",
2422+ "Could not connect to API": "Не удалось подключиться к API",
2423+ "Connected to API": "Соединение с API установлено"
23422424}
public/script.js+9 -5
@@ -143,6 +143,7 @@ import {
143143 getHordeModels,
144144 adjustHordeGenerationParams,
145145 MIN_LENGTH,
146+ initHorde
146147} from './scripts/horde.js';
147148
148149import {
@@ -175,6 +176,7 @@ import {
175176 saveBase64AsFile,
176177 uuidv4,
177178 equalsIgnoreCaseAndAccents,
179+ localizePagination
178180} from './scripts/utils.js';
179181import { debounce_timeout, IGNORE_SYMBOL } from './scripts/constants.js';
180182
@@ -229,7 +231,7 @@ import {
229231 instruct_presets,
230232 selectContextPreset,
231233} from './scripts/instruct-mode.js';
232234import { initLocales, t, translate } from './scripts/i18n.js';
233235import { getFriendlyTokenizerName, getTokenCount, getTokenCountAsync, initTokenizers, saveTokenCache, TOKENIZER_SUPPORTED_KEY } from './scripts/tokenizers.js';
234236import {
235237 user_avatar,
@@ -994,6 +996,7 @@ async function firstLoadInit() {
994996 initAuthorsNote();
995997 await initPersonas();
996998 initWorldInfo();
999+ initHorde();
9971000 initRossMods();
9981001 initStats();
9991002 initCfg();
@@ -1425,13 +1428,13 @@ function getBackBlock() {
14251428
14261429function getEmptyBlock() {
14271430 const icons = ['fa-dragon', 'fa-otter', 'fa-kiwi-bird', 'fa-crow', 'fa-frog'];
14281431 const texts = ['t`Here be dragons'`, 't`Otterly empty'`, 't`Kiwibunga'`, 't`Pump-a-Rum'`, 't`Croak it'`];
14291432 const roll = new Date().getMinutes() % icons.length;
14301433 const emptyBlock = `
14311434 <div class="text_block empty_block">
14321435 <i class="fa-solid ${icons[roll]} fa-4x"></i>
14331436 <h1>${texts[roll]}</h1>
14341437 <p>` + t`There are no items to display.` + `</p>
14351438 </div>`;
14361439 return $(emptyBlock);
14371440}
@@ -1443,7 +1446,7 @@ function getHiddenBlock(hidden) {
14431446 const hiddenBlock = `
14441447 <div class="text_block hidden_block">
14451448 <small>
14461449 <p>` + t`${hidden} ${hidden > 1 ? 'characters' : 'character'} hidden.` + `</p>
14471450 <div class="fa-solid fa-circle-info opacity50p" data-i18n="[title]Characters and groups hidden by filters or closed folders" title="Characters and groups hidden by filters or closed folders"></div>
14481451 </small>
14491452 </div>`;
@@ -1568,6 +1571,7 @@ export async function printCharacters(fullRefresh = false) {
15681571 if (hidden > 0 && entitiesFilter.hasAnyFilter()) {
15691572 $(listId).append(getHiddenBlock(hidden));
15701573 }
1574+ localizePagination($('#rm_print_characters_pagination'));
15711575
15721576 eventSource.emit(event_types.CHARACTER_PAGE_LOADED);
15731577 },
@@ -8429,7 +8433,7 @@ export function callPopup(text, type, inputValue = '', { okButton, rows, wide, w
84298433 } else if (['delete_extension'].includes(popup_type)) {
84308434 return okButton ?? 'Ok';
84318435 } else if (['new_chat', 'confirm'].includes(popup_type)) {
84328436 return okButton ?? 't`Yes'`;
84338437 } else if (['input'].includes(popup_type)) {
84348438 return okButton ?? t`Save`;
84358439 }
public/scripts/backgrounds.js+1 -1
@@ -291,7 +291,7 @@ async function onDeleteBackgroundClick(e) {
291291 const bgToDelete = $(this).closest('.bg_example');
292292 const url = bgToDelete.data('url');
293293 const isCustom = bgToDelete.attr('custom') === 'true';
294294 const confirm = await callPopup('<h3>' + t`Delete the background?` + '</h3>', 'confirm');
295295 const bg = bgToDelete.attr('bgfile');
296296
297297 if (confirm) {
public/scripts/group-chats.js+5 -1
@@ -13,6 +13,7 @@ import {
1313 getBase64Async,
1414 resetScrollHeight,
1515 initScrollHeight,
16+ localizePagination
1617} from './utils.js';
1718import { RA_CountCharTokens, humanizedDateTime, dragElement, favsToHotswap, getMessageTimeStamp } from './RossAscends-mods.js';
1819import { power_user, loadMovingUIState, sortEntitiesList } from './power-user.js';
@@ -1394,6 +1395,7 @@ function printGroupCandidates() {
13941395 for (const i of data) {
13951396 $('#rm_group_add_members').append(getGroupCharacterBlock(i.item));
13961397 }
1398+ localizePagination($('#rm_group_add_members_pagination'));
13971399 },
13981400 });
13991401}
@@ -1401,6 +1403,7 @@ function printGroupCandidates() {
14011403function printGroupMembers() {
14021404 const storageKey = 'GroupMembers_PerPage';
14031405 $('.rm_group_members_pagination').each(function () {
1406+ let that = this;
14041407 $(this).pagination({
14051408 dataSource: getGroupCharacters({ doFilter: false, onlyMembers: true }),
14061409 pageRange: 1,
@@ -1421,6 +1424,7 @@ function printGroupMembers() {
14211424 for (const i of data) {
14221425 $('.rm_group_members').append(getGroupCharacterBlock(i.item));
14231426 }
1427+ localizePagination($(that));
14241428 },
14251429 });
14261430 });
@@ -1804,7 +1808,7 @@ async function createGroup() {
18041808 const memberNames = characters.filter(x => members.includes(x.avatar)).map(x => x.name).join(', ');
18051809
18061810 if (!name) {
18071811 name = t`Group:` + ` ${memberNames}`;
18081812 }
18091813
18101814 const avatar_url = $('#group_avatar_preview img').attr('src');
public/scripts/horde.js+3 -3
@@ -394,7 +394,7 @@ function getHordeModelTemplate(option) {
394394 `));
395395}
396396
397397jQuery(export function initHorde () {
398398 $('#horde_model').on('mousedown change', async function (e) {
399399 console.log('Horde model change', e);
400400 horde_settings.models = $('#horde_model').val();
@@ -441,7 +441,7 @@ jQuery(function () {
441441 if (!isMobile()) {
442442 $('#horde_model').select2({
443443 width: '100%',
444444 placeholder: 't`Select Horde models'`,
445445 allowClear: true,
446446 closeOnSelect: false,
447447 templateSelection: function (data) {
@@ -451,5 +451,5 @@ jQuery(function () {
451451 templateResult: getHordeModelTemplate,
452452 });
453453 }
454454});
455455
public/scripts/openai.js+1 -1
@@ -3851,7 +3851,7 @@ function createLogitBiasListItem(entry) {
38513851}
38523852
38533853async function createNewLogitBiasPreset() {
38543854 const name = await callPopup('t`Preset name:'`, 'input');
38553855
38563856 if (!name) {
38573857 return;
public/scripts/personas.js+4 -2
@@ -22,12 +22,12 @@ import {
2222} from '../script.js';
2323import { persona_description_positions, power_user } from './power-user.js';
2424import { getTokenCountAsync } from './tokenizers.js';
2525import { PAGINATION_TEMPLATE, clearInfoBlock, debounce, delay, download, ensureImageFormatSupported, flashHighlight, getBase64Async, getCharIndex, isFalseBoolean, isTrueBoolean, onlyUnique, parseJsonFile, setInfoBlock, localizePagination } from './utils.js';
2626import { debounce_timeout } from './constants.js';
2727import { FILTER_TYPES, FilterHelper } from './filters.js';
2828import { groups, selected_group } from './group-chats.js';
2929import { POPUP_TYPE, Popup, callGenericPopup } from './popup.js';
3030import { t, translate } from './i18n.js';
3131import { openWorldInfoEditor, world_names } from './world-info.js';
3232import { renderTemplateAsync } from './templates.js';
3333import { saveMetadataDebounced } from './extensions.js';
@@ -263,6 +263,7 @@ export async function getUserAvatars(doRender = true, openPageAt = '') {
263263 prevText: '<',
264264 nextText: '>',
265265 formatNavigator: PAGINATION_TEMPLATE,
266+ afterRender: function(a) {console.log(a)},
266267 showNavigator: true,
267268 callback: function (data) {
268269 $(listId).empty();
@@ -270,6 +271,7 @@ export async function getUserAvatars(doRender = true, openPageAt = '') {
270271 $(listId).append(getUserAvatarBlock(item));
271272 }
272273 updatePersonaUIStates();
274+ localizePagination($('#persona_pagination_container'));
273275 },
274276 afterSizeSelectorChange: function (e) {
275277 accountStorage.setItem(storageKey, e.target.value);
public/scripts/tags.js+6 -5
@@ -27,7 +27,7 @@ import { debounce_timeout } from './constants.js';
2727import { INTERACTABLE_CONTROL_CLASS } from './keyboard.js';
2828import { commonEnumProviders } from './slash-commands/SlashCommandCommonEnumsProvider.js';
2929import { renderTemplateAsync } from './templates.js';
3030import { t, translate } from './i18n.js';
3131
3232export {
3333 TAG_FOLDER_TYPES,
@@ -1057,7 +1057,7 @@ function appendTagToList(listElement, tag, { removable = false, isFilter = false
10571057 tagElement.attr('title', tag.title);
10581058 }
10591059 if (tag.icon) {
10601060 tagElement.find('.tag_name').text('').attr('title', `${translate(tag.name)} ${tag.title || ''}`.trim()).addClass(tag.icon);
10611061 tagElement.addClass('actionable');
10621062 }
10631063
@@ -1644,6 +1644,7 @@ function updateDrawTagFolder(element, tag) {
16441644
16451645 // Draw/update css attributes for this class
16461646 folderElement.attr('title', tagFolder.tooltip);
1647+ folderElement.attr('data-i18n', '[title]' + tagFolder.tooltip);
16471648 const indicator = folderElement.find('.tag_folder_indicator');
16481649 indicator.text(tagFolder.icon);
16491650 indicator.css('color', tagFolder.color);
@@ -1656,9 +1657,9 @@ async function onTagDeleteClick() {
16561657 const otherTags = sortTags(tags.filter(x => x.id !== id).map(x => ({ id: x.id, name: x.name })));
16571658
16581659 const popupContent = $(`
16591660 <h3>` + t`Delete Tag` + `</h3>
16601661 <div>` + t`Do you want to delete the tag` + ` <div id="tag_to_delete" class="tags_inline inline-flex margin-r2"></div>?</div>
16611662 <div class="m-t-2 marginBot5">` + t`If you want to merge all references to this tag into another tag, select it below:` + `</div>
16621663 <select id="merge_tag_select">
16631664 <option value="">--- None ---</option>
16641665 ${otherTags.map(x => `<option value="${x.id}">${x.name}</option>`).join('')}
public/scripts/textgen-models.js+16 -5
@@ -5,8 +5,9 @@ import { textgenerationwebui_settings as textgen_settings, textgen_types } from
55import { tokenizers } from './tokenizers.js';
66import { renderTemplateAsync } from './templates.js';
77import { POPUP_TYPE, callGenericPopup } from './popup.js';
88import { t, translate } from './i18n.js';
99import { accountStorage } from './util/AccountStorage.js';
10+import { localizePagination } from './utils.js';
1011
1112let mancerModels = [];
1213let togetherModels = [];
@@ -368,7 +369,16 @@ export async function loadFeatherlessModels(data) {
368369 prevText: '<',
369370 nextText: '>',
370371 formatNavigator: function (currentPage, totalPage) {
371- return (currentPage - 1) * perPage + 1 + ' - ' + currentPage * perPage + ' of ' + totalPage * perPage;
372+ let translated_of;
373+ try {
374+ translated_of = translate('pagination_of');
375+ if (translated_of == 'pagination_of') {
376+ translated_of = 'of';
377+ }
378+ } catch (e) {
379+ translated_of = 'of';
380+ }
381+ return (currentPage - 1) * perPage + 1 + ' - ' + currentPage * perPage + ` ${translated_of} ` + totalPage * perPage;
372382 },
373383 showNavigator: true,
374384 callback: function (modelsOnPage, pagination) {
@@ -391,15 +401,15 @@ export async function loadFeatherlessModels(data) {
391401
392402 const modelClassDiv = document.createElement('div');
393403 modelClassDiv.classList.add('model-class');
394404 modelClassDiv.textContent = t`Class` + `: ${model.model_class || 'N/A'}`;
395405
396406 const contextLengthDiv = document.createElement('div');
397407 contextLengthDiv.classList.add('model-context-length');
398408 contextLengthDiv.textContent = t`Context Length` + `: ${model.context_length}`;
399409
400410 const dateAddedDiv = document.createElement('div');
401411 dateAddedDiv.classList.add('model-date-added');
402412 dateAddedDiv.textContent = t`Added On` + `: ${new Date(model.created * 1000).toLocaleDateString()}`;
403413
404414 detailsContainer.appendChild(modelClassDiv);
405415 detailsContainer.appendChild(contextLengthDiv);
@@ -423,6 +433,7 @@ export async function loadFeatherlessModels(data) {
423433
424434 // Update the current page value whenever the page changes
425435 featherlessCurrentPage = pagination.pageNumber;
436+ localizePagination(paginationContainer);
426437 },
427438 afterSizeSelectorChange: function (e) {
428439 const newPerPage = e.target.value;
public/scripts/utils.js+30 -4
@@ -14,13 +14,39 @@ import { Popup, POPUP_RESULT, POPUP_TYPE } from './popup.js';
1414import { SlashCommandClosure } from './slash-commands/SlashCommandClosure.js';
1515import { getTagsList } from './tags.js';
1616import { groups, selected_group } from './group-chats.js';
1717import { getCurrentLocale, t, translate } from './i18n.js';
1818
1919/**
2020 * PaginationFunction returning pagination status string template.
2121 * @type {stringfunction}
2222 */
23-export const PAGINATION_TEMPLATE = '<%= rangeStart %>-<%= rangeEnd %> of <%= totalNumber %>';
23+export const PAGINATION_TEMPLATE = function() {
24+ let translated_of;
25+ try {
26+ translated_of = translate('pagination_of');
27+ if (translated_of == 'pagination_of') {
28+ translated_of = 'of';
29+ }
30+ } catch (e) {
31+ translated_of = 'of';
32+ }
33+ return `<%= rangeStart %>-<%= rangeEnd %> ${translated_of} <%= totalNumber %>`
34+};
35+
36+export const localizePagination = function(container) {
37+ let options = container.find('option');
38+ for (let option of options) {
39+ option = $(option);
40+ try {
41+ option.text(option.text().replace('/ page', translate('/ page')));
42+ } catch (e) {
43+ console.error(e);
44+ break;
45+ }
46+ }
47+ container.find("[title='Next page']").attr('title', translate('Next page'));
48+ container.find("[title='Previous page']").attr('title', translate('Previous page'));
49+}
2450
2551/**
2652 * Navigation options for pagination.
public/scripts/world-info.js+2 -2
@@ -2658,7 +2658,7 @@ export async function getWorldEntry(name, data, entry) {
26582658 if (!isMobile()) {
26592659 $(characterFilter).select2({
26602660 width: '100%',
26612661 placeholder: 't`Tie this entry to specific characters or characters with specific tags'`,
26622662 allowClear: true,
26632663 closeOnSelect: false,
26642664 });
@@ -3258,7 +3258,7 @@ export async function getWorldEntry(name, data, entry) {
32583258
32593259 // Create wrapper div
32603260 const wrapper = document.createElement('div');
32613261 wrapper.textContent = t`Move "'${sourceName}"' to:`;
32623262
32633263 // Create container and append elements
32643264 const container = document.createElement('div');