@goodandready/dsh-russian-lang 0.3.22 → 0.3.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,16 +5,16 @@
5
5
  <h3>Полная русская локализация, умная типографика и исправление раскладки клавиатуры для DeepSeek Harness</h3>
6
6
 
7
7
  <p align="center">
8
- <a href="https://www.npmjs.com/package/@goodandready/dsh-russian-lang"><img src="https://img.shields.io/badge/npm-v0.3.18-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="npm version"></a>
8
+ <a href="https://www.npmjs.com/package/@goodandready/dsh-russian-lang"><img src="https://img.shields.io/badge/npm-v0.3.24-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="npm version"></a>
9
9
  <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-10b981.svg?style=for-the-badge&color=10b981&labelColor=064e3b" alt="license"></a>
10
10
  <a href="https://github.com/topics/dsh-plugin"><img src="https://img.shields.io/badge/DSH-Plugin-8b5cf6.svg?style=for-the-badge&labelColor=2e1065" alt="DSH Plugin"></a>
11
11
  <a href="https://nodejs.org"><img src="https://img.shields.io/badge/Node-20%2B-f59e0b.svg?style=for-the-badge&labelColor=451a03" alt="Node version"></a>
12
12
  </p>
13
13
 
14
14
  <p align="center">
15
- <img src="https://img.shields.io/badge/DSH-v0.2.0--rc.1%2B-blue.svg?style=for-the-badge&labelColor=1e1b4b" alt="DSH v0.1.7-rc.2+">
15
+ <img src="https://img.shields.io/badge/DSH-v0.2.0--rc.2%2B-blue.svg?style=for-the-badge&labelColor=1e1b4b" alt="DSH v0.1.7-rc.2+">
16
16
  <img src="https://img.shields.io/badge/Покрытие-100%25-10b981.svg?style=for-the-badge&labelColor=064e3b" alt="Покрытие 100%">
17
- <img src="https://img.shields.io/badge/Ключей_UI-8523-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="8110 ключей">
17
+ <img src="https://img.shields.io/badge/Ключей_UI-8576-6366f1.svg?style=for-the-badge&labelColor=1e1b4b" alt="8576 ключей">
18
18
  <img src="https://img.shields.io/badge/Ручная_вычитка-100%25-0ea5e9.svg?style=for-the-badge&labelColor=082f49" alt="100% ручная вычитка">
19
19
  </p>
20
20
 
@@ -52,9 +52,9 @@ graph LR
52
52
  DSH[Web UI Интерфейс] --> Loader[Загрузчик локализации dsh-russian-lang]
53
53
  end
54
54
 
55
- subgraph TranslationLayer [Слой перевода и адаптации — 8523 ключа / 100% вычитано]
56
- Loader --> CoreDict[59 Пространств имён ядра DSH / 2421 ключ]
57
- Loader --> PluginDict[65+ Плагинов экосистемы DSH / 6102 ключа]
55
+ subgraph TranslationLayer [Слой перевода и адаптации — 8576 ключей / 100% вычитано]
56
+ Loader --> CoreDict[58 Пространств имён ядра DSH / 2442 ключа]
57
+ Loader --> PluginDict[64 Плагина экосистемы DSH / 6134 ключа]
58
58
  Loader --> PluralEngine[Движок грамматических Plural-форм: 1/2/5]
59
59
  end
60
60
 
package/lib/client.js CHANGED
@@ -394,8 +394,8 @@ return results.sort((a, b) => b.score - a.score).map((r) => r.item)
394
394
  }
395
395
  const RU = {"common":{"back":"Назад","cancel":"Отмена","close":"Закрыть","collapse":"Свернуть","copied":"Скопировано","copy":"Копировать","delete":"Удалить","edit":"Изменить","expand":"Развернуть","loading":"Загрузка…","more":"Ещё","next":"Дальше","ok":"ОК","retry":"Повторить","save":"Сохранить","search":"Поиск","submit":"Отправить"},"dsh-cron":{"sidebar.label":"Задачи по расписанию"},"dsh-usage-stats":{"footer.todayLabel":"Сегодня"},"pluginMarket":{"trigger":"Магазин плагинов"}}
396
396
  const ZH_RU = {}
397
- RU['russian-lang'] = {"cardTitle":"Русская локализация","cardSub":"Язык интерфейса, типографика, раскладка","badgeRu":"🟢 RU активен","badgeEn":"⚪ EN активен","badgeCoverage":"🟢 100% (7,902 ключа)","badgeSmartUx":"⚡ Smart UX активен","secLanguage":"🌐 Язык интерфейса","secLanguageDesc":"Нативное переключение языка интерфейса DSH на русский без перезагрузки страницы.","enabled":"Русский язык включён","enabledDesc":"Переключает язык интерфейса DeepSeek Harness на русский.","quickSwitchNote":"Быстрый переключатель RU ⇄ EN доступен в шапке сессии рядом с кнопками диалога.","secTypography":"✍️ Умная типографика и ввод (Smart UX)","secTypographyDesc":"Нормы русской типографики во время диалога и набора.","typography":"Типографика вывода","typographyDesc":"Кавычки «», тире — вместо дефисов, неразрывные пробелы.","yo":"Буква «ё»","yoDesc":"Восстановление «ё» в частых словах (ещё, идёт и др.).","liveInput":"Живая типографика инпута","liveInputDesc":"Кавычки «», тире — и неразрывные пробелы перед отправкой.","slashAliases":"Русские алиасы команд","slashAliasesDesc":"Команды: /цель, /сжать, /план, /справка, /память.","altLHintText":"Конвертация раскладки текущего поля (ghbdtn ⇄ привет).","secAgentPrompt":"🤖 Системный промпт агента","secAgentPromptDesc":"Официальная секция расширения DSH systemPrompt для ведения диалога на русском языке.","agentPrompt":"Русский промпт агента","agentPromptDesc":"Добавляет в системный промпт инструкцию отвечать по-русски в выбранном стиле.","agentPromptPreset":"Стиль ответов агента","presetExpert":"Технический эксперт (строгая терминология, чистый код)","presetWriter":"Технический писатель (Markdown, таблицы, ГОСТ)","presetConcise":"Лаконичный режим (кратко, без лишней воды)","presetReviewer":"Код-ревьюер (поиск багов, безопасность, аудит)","presetArchitect":"Системный архитектор (контракты, масштабируемость)","presetTutor":"Наставник (понятные объяснения, пошаговый разбор)","secUpdater":"🔄 Обновление языкового пакета","secUpdaterDesc":"Проверка наличия новых релизов в реестре npm и обновление в один клик.","updaterCurrent":"Текущая версия: v{version}","updaterLatest":"Доступна новая версия: v{version}","updaterUpToDate":"Установлена актуальная версия","updaterChecking":"Проверка…","updaterCheckBtn":"Проверить обновления","updaterBtn":"Обновить до v{version} в 1 клик","updaterUpdating":"Установка обновления…","updaterSuccess":"✅ Плагин успешно обновлён! Перезапустите DSH для применения.","updaterFailed":"❌ Не удалось проверить/обновить плагин. Проверьте сеть или логи сервера.","badgeUpdateAvailable":"Доступно обновление","badgeUpToDate":"Актуальная версия","secTranslator":"🌐 Перевод сообщений ассистента","secTranslatorDesc":"Перевод ответов модели в чате на русский язык.","translateEngine":"Движок перевода","engineOff":"Выключен (по умолчанию, без сетевых вызовов)","engineLocal":"Локальный LibreTranslate (приватно, ~600 МБ RAM)","engineGoogle":"Google Translate (онлайн)","googleWarn":"⚠️ Текст сообщений передаётся на публичные серверы Google.","localStatusRunning":"🟢 Контейнер LibreTranslate активен","localStatusStopped":"⚪ Контейнер LibreTranslate не запущен","localStartBtn":"Запустить LibreTranslate в Docker (~600 МБ RAM)","localStarting":"Запуск контейнера…","localInfo":"LibreTranslate в Docker: изолированно, ~600 МБ RAM.","secOverrides":"✍️ Пользовательские переопределения (Custom Overrides)","secOverridesDesc":"Замена любой формулировки интерфейса DSH на собственную.","overrideKeyPlaceholder":"Ключ (например, common.back или settings.title)","overrideValuePlaceholder":"Ваш русский перевод","overrideAddBtn":"Добавить","overrideEmpty":"Переопределений пока нет.","overrideDelete":"Удалить","overrideTip":"💡 Зажмите Alt и кликните на элемент UI для быстрой правки.","secSupport":"📊 Покрытие экосистемы и поддержка","secSupportDesc":"100% UI-покрытие ядра и плагинов DSH.","statNamespaces":"Пространств имён","statCoreKeys":"Ключей ядра","statPluginKeys":"Ключей плагинов","overridesCount":"Своих переопределений","statusLoading":"Настройки загружаются…","statusUnavailable":"Настройки недоступны на этом хосте","translateTurn":"Перевести на русский","reportIssue":"Сообщить о неточности перевода","exportMdHint":"Экспорт диалога в Markdown доступен по кнопке [ 📥 MD ] в шапке сессии.","translateTurnHint":"Перевод ответов ассистента на русский доступен по кнопке [ RU ↗ ] на блоках сообщений.","inspectorToggleOff":"🔍 Включить инспектор перевода (Alt+I)","inspectorToggleOn":"🔍 Инспектор перевода (включён)","exportJsonBtn":"📤 Экспорт JSON","importJsonBtn":"📥 Импорт JSON","overridesCopied":"Оверрайды скопированы в буфер обмена как JSON!","overridesImportPrompt":"Вставьте JSON с оверрайдами:","overridesImportError":"Ошибка разбора JSON: "}
398
- const CARD_EN = {cardTitle: 'Russian localization',cardSub: 'Interface language, typography, keyboard layout',badgeRu: '🟢 RU active',badgeEn: '⚪ EN active',badgeCoverage: '🟢 100% (7,902 keys)',badgeSmartUx: '⚡ Smart UX active',secLanguage: '🌐 Interface language',secLanguageDesc: 'Switch the DSH interface language to Russian natively, without reloading the page.',enabled: 'Russian language enabled',enabledDesc: 'Switches the DeepSeek Harness interface to Russian.',quickSwitchNote: 'The RU ⇄ EN quick switch is available in the session header next to the dialog buttons.',secTypography: '✍️ Smart typography & input (Smart UX)',secTypographyDesc: 'Russian typography rules applied while you chat and type.',typography: 'Output typography',typographyDesc: 'Guillemets «», em dashes — instead of hyphens, non-breaking spaces.',yo: 'Letter «ё»',yoDesc: 'Restores «ё» in frequent words (ещё, идёт, etc.).',liveInput: 'Live input typography',liveInputDesc: 'Guillemets «», em dashes — and non-breaking spaces before sending.',slashAliases: 'Russian command aliases',slashAliasesDesc: 'Commands: /цель, /сжать, /план, /справка, /память.',altLHintText: 'Converts the keyboard layout of the current field (ghbdtn ⇄ привет).',secAgentPrompt: '🤖 Agent system prompt',secAgentPromptDesc: 'An official DSH systemPrompt extension section for conversing in Russian.',agentPrompt: 'Russian agent prompt',agentPromptDesc: 'Adds an instruction to reply in Russian in the selected style to the system prompt.',agentPromptPreset: 'Reply style',presetExpert: 'Technical expert (strict terminology, clean code)',presetWriter: 'Technical writer (Markdown, tables, GOST)',presetConcise: 'Concise mode (brief, no fluff)',presetReviewer: 'Code reviewer (bug hunting, security, audit)',presetArchitect: 'System architect (contracts, scalability)',presetTutor: 'Mentor (clear explanations, step-by-step)',secUpdater: '🔄 Language pack updates',secUpdaterDesc: 'Check for new releases in the npm registry and update in one click.',updaterCurrent: 'Current version: v{version}',updaterLatest: 'New version available: v{version}',updaterUpToDate: 'You are on the latest version',updaterChecking: 'Checking…',updaterCheckBtn: 'Check for updates',updaterBtn: 'Update to v{version} in 1 click',updaterUpdating: 'Installing update…',updaterSuccess: '✅ Plugin updated successfully! Restart DSH to apply.',updaterFailed: '❌ Failed to check or update the plugin. Check your network or server logs.',badgeUpdateAvailable: 'Update available',badgeUpToDate: 'Up to date',secTranslator: '🌐 Assistant message translation',secTranslatorDesc: 'Translate model replies in chat into Russian.',translateEngine: 'Translation engine',engineOff: 'Off (default, no network calls)',engineLocal: 'Local LibreTranslate (private, ~600 MB RAM)',engineGoogle: 'Google Translate (online)',googleWarn: '⚠️ Message text is sent to public Google servers.',localStatusRunning: '🟢 LibreTranslate container is running',localStatusStopped: '⚪ LibreTranslate container is not running',localStartBtn: 'Start LibreTranslate in Docker (~600 MB RAM)',localStarting: 'Starting container…',localInfo: 'LibreTranslate in Docker: isolated, ~600 MB RAM.',secOverrides: '✍️ Custom overrides',secOverridesDesc: 'Replace any DSH interface wording with your own.',overrideKeyPlaceholder: 'Key (e.g. common.back or settings.title)',overrideValuePlaceholder: 'Your translation',overrideAddBtn: 'Add',overrideEmpty: 'No overrides yet.',overrideDelete: 'Delete',overrideTip: '💡 Hold Alt and click a UI element for quick editing.',secSupport: '📊 Ecosystem coverage & support',secSupportDesc: '100% UI coverage of the DSH core and plugins.',inspectorToggleOff: '🔍 Enable translation inspector (Alt+I)',inspectorToggleOn: '🔍 Translation inspector (on)',exportJsonBtn: '📤 Export JSON',importJsonBtn: '📥 Import JSON',overridesCopied: 'Overrides copied to clipboard as JSON!',overridesImportPrompt: 'Paste overrides JSON:',overridesImportError: 'JSON parse error: ',statNamespaces: 'Namespaces',statCoreKeys: 'Core keys',statPluginKeys: 'Plugin keys',overridesCount: 'Custom overrides',statusLoading: 'Loading settings…',statusUnavailable: 'Settings unavailable on this host',translateTurn: 'Translate to Russian',reportIssue: 'Report a translation issue',exportMdHint: 'Export the dialog to Markdown via the [ 📥 MD ] button in the session header.',translateTurnHint: 'Translate assistant replies to Russian via the [ RU ↗ ] button on message blocks.',}
397
+ RU['russian-lang'] = {"cardTitle":"Русская локализация","cardSub":"Язык интерфейса, типографика, раскладка","badgeRu":"🟢 RU активен","badgeEn":"⚪ EN активен","badgeCoverage":"🟢 100% (7,902 ключа)","badgeSmartUx":"⚡ Smart UX активен","badgeSmartUxOff":"Smart UX выключен","secLanguage":"🌐 Язык интерфейса","secLanguageDesc":"Нативное переключение языка интерфейса DSH на русский без перезагрузки страницы.","enabled":"Русский язык включён","enabledDesc":"Переключает язык интерфейса DeepSeek Harness на русский.","quickSwitchNote":"Быстрый переключатель RU ⇄ EN доступен в шапке сессии рядом с кнопками диалога.","quickSwitch":"Быстрый переключатель языка","quickSwitchDesc":"Показывать переключатель RU ⇄ EN в шапке сессии.","secTypography":"✍️ Умная типографика и ввод (Smart UX)","secTypographyDesc":"Нормы русской типографики во время диалога и набора.","typography":"Типографика вывода","typographyDesc":"Кавычки «», тире — вместо дефисов, неразрывные пробелы.","yo":"Буква «ё»","yoDesc":"Восстановление «ё» в частых словах (ещё, идёт и др.).","liveInput":"Живая типографика инпута","liveInputDesc":"Кавычки «», тире — и неразрывные пробелы перед отправкой.","slashAliases":"Русские алиасы команд","slashAliasesDesc":"Команды: /цель, /сжать, /план, /справка, /память.","altLHintText":"Подсказки и конвертация раскладки","layoutConversionDesc":"Подсказки при вводе; ⌨ Alt+L и значок RU/EN конвертируют текст текущего поля (ghbdtn ⇄ привет).","secAgentPrompt":"🤖 Системный промпт агента","secAgentPromptDesc":"Официальная секция расширения DSH systemPrompt для ведения диалога на русском языке.","agentPrompt":"Русский промпт агента","agentPromptDesc":"Добавляет в системный промпт инструкцию отвечать по-русски в выбранном стиле.","agentPromptPreset":"Стиль ответов агента","presetExpert":"Технический эксперт (строгая терминология, чистый код)","presetWriter":"Технический писатель (Markdown, таблицы, ГОСТ)","presetConcise":"Лаконичный режим (кратко, без лишней воды)","presetReviewer":"Код-ревьюер (поиск багов, безопасность, аудит)","presetArchitect":"Системный архитектор (контракты, масштабируемость)","presetTutor":"Наставник (понятные объяснения, пошаговый разбор)","secUpdater":"🔄 Обновление языкового пакета","secUpdaterDesc":"Проверка наличия новых релизов в реестре npm и обновление в один клик.","updaterCurrent":"Текущая версия: v{version}","updaterLatest":"Доступна новая версия: v{version}","updaterUpToDate":"Установлена актуальная версия","updaterChecking":"Проверка…","updaterCheckBtn":"Проверить обновления","updaterBtn":"Обновить до v{version} в 1 клик","updaterUpdating":"Установка обновления…","updaterSuccess":"✅ Плагин успешно обновлён! Перезапустите DSH для применения.","updaterFailed":"❌ Не удалось проверить/обновить плагин. Проверьте сеть или логи сервера.","badgeUpdateAvailable":"Доступно обновление","badgeUpToDate":"Актуальная версия","secTranslator":"🌐 Перевод сообщений ассистента","secTranslatorDesc":"Перевод ответов модели в чате на русский язык.","translateEngine":"Движок перевода","engineOff":"Выключен (по умолчанию, без сетевых вызовов)","engineLocal":"Локальный LibreTranslate (приватно, ~600 МБ RAM)","engineGoogle":"Google Translate (онлайн)","googleWarn":"⚠️ Текст сообщений передаётся на публичные серверы Google.","localStatusRunning":"🟢 Контейнер LibreTranslate активен","localStatusStopped":"⚪ Контейнер LibreTranslate не запущен","localStartBtn":"Запустить LibreTranslate в Docker (~600 МБ RAM)","localStarting":"Запуск контейнера…","localInfo":"LibreTranslate в Docker: изолированно, ~600 МБ RAM.","secOverrides":"✍️ Пользовательские переопределения (Custom Overrides)","secOverridesDesc":"Замена любой формулировки интерфейса DSH на собственную.","overrideKeyPlaceholder":"Ключ (например, common.back или settings.title)","overrideValuePlaceholder":"Ваш русский перевод","overrideAddBtn":"Добавить","overrideEmpty":"Переопределений пока нет.","overrideDelete":"Удалить","overrideTip":"💡 Зажмите Alt и кликните на элемент UI для быстрой правки.","secSupport":"📊 Покрытие экосистемы и поддержка","secSupportDesc":"100% UI-покрытие ядра и плагинов DSH.","statNamespaces":"Пространств имён","statCoreKeys":"Ключей ядра","statPluginKeys":"Ключей плагинов","overridesCount":"Своих переопределений","statusLoading":"Настройки загружаются…","statusUnavailable":"Настройки недоступны на этом хосте","translateTurn":"Перевести на русский","reportIssue":"Сообщить о неточности перевода","exportMdHint":"Экспорт диалога в Markdown доступен по кнопке [ 📥 MD ] в шапке сессии.","translateTurnHint":"Перевод ответов ассистента на русский доступен по кнопке [ RU ↗ ] на блоках сообщений.","inspectorToggleOff":"🔍 Включить инспектор перевода (Alt+I)","inspectorToggleOn":"🔍 Инспектор перевода (включён)","exportJsonBtn":"📤 Экспорт JSON","importJsonBtn":"📥 Импорт JSON","overridesCopied":"Оверрайды скопированы в буфер обмена как JSON!","overridesImportPrompt":"Вставьте JSON с оверрайдами:","overridesImportError":"Ошибка разбора JSON: "}
398
+ const CARD_EN = {cardTitle: 'Russian localization',cardSub: 'Interface language, typography, keyboard layout',badgeRu: '🟢 RU active',badgeEn: '⚪ EN active',badgeCoverage: '🟢 100% (7,902 keys)',badgeSmartUx: '⚡ Smart UX active',badgeSmartUxOff: 'Smart UX off',secLanguage: '🌐 Interface language',secLanguageDesc: 'Switch the DSH interface language to Russian natively, without reloading the page.',enabled: 'Russian language enabled',enabledDesc: 'Switches the DeepSeek Harness interface to Russian.',quickSwitchNote: 'The RU ⇄ EN quick switch is available in the session header next to the dialog buttons.',quickSwitch: 'Quick language switch',quickSwitchDesc: 'Show the RU ⇄ EN switch in the session header.',secTypography: '✍️ Smart typography & input (Smart UX)',secTypographyDesc: 'Russian typography rules applied while you chat and type.',typography: 'Output typography',typographyDesc: 'Guillemets «», em dashes — instead of hyphens, non-breaking spaces.',yo: 'Letter «ё»',yoDesc: 'Restores «ё» in frequent words (ещё, идёт, etc.).',liveInput: 'Live input typography',liveInputDesc: 'Guillemets «», em dashes — and non-breaking spaces before sending.',slashAliases: 'Russian command aliases',slashAliasesDesc: 'Commands: /цель, /сжать, /план, /справка, /память.',altLHintText: 'Keyboard layout hints and conversion',layoutConversionDesc: 'Hints while typing; ⌨ Alt+L and the RU/EN badge convert the current field (ghbdtn ⇄ привет).',secAgentPrompt: '🤖 Agent system prompt',secAgentPromptDesc: 'An official DSH systemPrompt extension section for conversing in Russian.',agentPrompt: 'Russian agent prompt',agentPromptDesc: 'Adds an instruction to reply in Russian in the selected style to the system prompt.',agentPromptPreset: 'Reply style',presetExpert: 'Technical expert (strict terminology, clean code)',presetWriter: 'Technical writer (Markdown, tables, GOST)',presetConcise: 'Concise mode (brief, no fluff)',presetReviewer: 'Code reviewer (bug hunting, security, audit)',presetArchitect: 'System architect (contracts, scalability)',presetTutor: 'Mentor (clear explanations, step-by-step)',secUpdater: '🔄 Language pack updates',secUpdaterDesc: 'Check for new releases in the npm registry and update in one click.',updaterCurrent: 'Current version: v{version}',updaterLatest: 'New version available: v{version}',updaterUpToDate: 'You are on the latest version',updaterChecking: 'Checking…',updaterCheckBtn: 'Check for updates',updaterBtn: 'Update to v{version} in 1 click',updaterUpdating: 'Installing update…',updaterSuccess: '✅ Plugin updated successfully! Restart DSH to apply.',updaterFailed: '❌ Failed to check or update the plugin. Check your network or server logs.',badgeUpdateAvailable: 'Update available',badgeUpToDate: 'Up to date',secTranslator: '🌐 Assistant message translation',secTranslatorDesc: 'Translate model replies in chat into Russian.',translateEngine: 'Translation engine',engineOff: 'Off (default, no network calls)',engineLocal: 'Local LibreTranslate (private, ~600 MB RAM)',engineGoogle: 'Google Translate (online)',googleWarn: '⚠️ Message text is sent to public Google servers.',localStatusRunning: '🟢 LibreTranslate container is running',localStatusStopped: '⚪ LibreTranslate container is not running',localStartBtn: 'Start LibreTranslate in Docker (~600 MB RAM)',localStarting: 'Starting container…',localInfo: 'LibreTranslate in Docker: isolated, ~600 MB RAM.',secOverrides: '✍️ Custom overrides',secOverridesDesc: 'Replace any DSH interface wording with your own.',overrideKeyPlaceholder: 'Key (e.g. common.back or settings.title)',overrideValuePlaceholder: 'Your translation',overrideAddBtn: 'Add',overrideEmpty: 'No overrides yet.',overrideDelete: 'Delete',overrideTip: '💡 Hold Alt and click a UI element for quick editing.',secSupport: '📊 Ecosystem coverage & support',secSupportDesc: '100% UI coverage of the DSH core and plugins.',inspectorToggleOff: '🔍 Enable translation inspector (Alt+I)',inspectorToggleOn: '🔍 Translation inspector (on)',exportJsonBtn: '📤 Export JSON',importJsonBtn: '📥 Import JSON',overridesCopied: 'Overrides copied to clipboard as JSON!',overridesImportPrompt: 'Paste overrides JSON:',overridesImportError: 'JSON parse error: ',statNamespaces: 'Namespaces',statCoreKeys: 'Core keys',statPluginKeys: 'Plugin keys',overridesCount: 'Custom overrides',statusLoading: 'Loading settings…',statusUnavailable: 'Settings unavailable on this host',translateTurn: 'Translate to Russian',reportIssue: 'Report a translation issue',exportMdHint: 'Export the dialog to Markdown via the [ 📥 MD ] button in the session header.',translateTurnHint: 'Translate assistant replies to Russian via the [ RU ↗ ] button on message blocks.',}
399
399
  const SETTINGS_NS_NAME = 'russian-lang'
400
400
  const FORM_NS = 'dsh-russian-lang'
401
401
  const LEGACY_NS = 'russian-lang'
@@ -791,6 +791,7 @@ syncTypo()
791
791
  const layout = makeLayout(new Set(["не","что","ты","это","на","он","мы","как","вы","да","мне","нет","меня","так","но","его","все","она","тебя","если","за","бы","тебе","они","чтобы","же","есть","просто","из","для"]), new Set())
792
792
  const layoutFixCandidate = layout.candidate
793
793
  const learnWords = layout.learnWords
794
+ const layoutEnabled = () => scope.getSnapshot().value?.layoutConversion !== false
794
795
  function setNativeInputValue(el, value, cursorStart, cursorEnd) {if (!el) return
795
796
  const oldVal = el.value || ''
796
797
  if (oldVal === value) return
@@ -905,7 +906,8 @@ Object.assign(layoutHintEl.style, {position: 'fixed', zIndex: '99999', backgroun
905
906
  })
906
907
  const label = direction === 'cyr2lat' ? 'Команда, не та раскладка' : 'Не та раскладка'
907
908
  layoutHintEl.textContent = label + ': ' + converted
908
- layoutHintEl.addEventListener('mousedown', (ev) => {ev.preventDefault()
909
+ layoutHintEl.addEventListener('mousedown', (ev) => {if (!layoutEnabled()) return
910
+ ev.preventDefault()
909
911
  setComposerText(inputEl, converted)
910
912
  learnWords(converted)
911
913
  layoutDismiss()
@@ -929,7 +931,8 @@ layoutBadgeEl.dataset.russianLangLayoutBadge = '1'
929
931
  Object.assign(layoutBadgeEl.style, {position: 'fixed', zIndex: '99998', background: 'var(--dsw-alias-bg-layer-3)',color: 'var(--dsw-alias-label-secondary)', border: '1px solid var(--dsw-alias-border-l2)',borderRadius: '6px', padding: '1px 6px', fontSize: '11px', cursor: 'pointer',fontFamily: 'monospace', lineHeight: '1.4', fontWeight: '600'
930
932
  })
931
933
  layoutBadgeEl.title = 'Раскладка — клик: конвертировать (Alt+L)'
932
- layoutBadgeEl.addEventListener('mousedown', (ev) => {ev.preventDefault()
934
+ layoutBadgeEl.addEventListener('mousedown', (ev) => {if (!layoutEnabled()) return
935
+ ev.preventDefault()
933
936
  const v = getComposerText(el)
934
937
  const c = layoutFixCandidate(v, 'lat2cyr') || layoutFixCandidate(v, 'cyr2lat')
935
938
  if (c) {setComposerText(el, c.converted)
@@ -945,6 +948,7 @@ layoutBadgeEl.style.top = (r.top - 22) + 'px'
945
948
  const layoutBadgeHide = () => {if (layoutBadgeEl) { layoutBadgeEl.remove(); layoutBadgeEl = null }}
946
949
  let isFormatting = false
947
950
  const layoutOnInput = (ev) => {if (isFormatting) return
951
+ if (!layoutEnabled()) { layoutDismiss(); layoutBadgeHide(); return }
948
952
  try {const el = layoutCurrentInput(ev)
949
953
  if (!el) { layoutDismiss(); layoutBadgeHide(); return }
950
954
  layoutBadge(el)
@@ -963,7 +967,7 @@ const layoutOnKeydown = (ev) => {const el = layoutCurrentInput(ev)
963
967
  if (!el) return
964
968
  const value = getComposerText(el)
965
969
  const isL = ev.code === 'KeyL' || ev.key.toLowerCase() === 'l' || ev.key.toLowerCase() === 'д'
966
- if (ev.altKey && !ev.ctrlKey && !ev.metaKey && isL) {const sel = typeof window !== 'undefined' && window.getSelection && window.getSelection()
970
+ if (layoutEnabled() && ev.altKey && !ev.ctrlKey && !ev.metaKey && isL) {const sel = typeof window !== 'undefined' && window.getSelection && window.getSelection()
967
971
  const selectedText = (sel && !sel.isCollapsed) ? sel.toString() : ''
968
972
  if (selectedText) {const c = layoutFixCandidate(selectedText, 'lat2cyr') || layoutFixCandidate(selectedText, 'cyr2lat')
969
973
  if (c) {ev.preventDefault()
@@ -1132,7 +1136,7 @@ setTimeout(() => { copyKeyBtn.textContent = '📋' }, 1500)
1132
1136
  }}
1133
1137
  const copyReportBtn = modal.querySelector('.rl-copy-report-btn')
1134
1138
  if (copyReportBtn) {copyReportBtn.onclick = () => {const snippet = typeof generateBugReportSnippet === 'function'
1135
- ? generateBugReportSnippet({ key: k, ns, original: origText || rawText, current: rawText, override: textarea.value.trim(), pkgVersion: '0.3.22' })
1139
+ ? generateBugReportSnippet({ key: k, ns, original: origText || rawText, current: rawText, override: textarea.value.trim(), pkgVersion: '0.3.24' })
1136
1140
  : ('### Репорт: ' + (k || rawText) + '\n- Исходный: ' + (origText || rawText) + '\n- Перевод: ' + textarea.value.trim())
1137
1141
  try { navigator.clipboard.writeText(snippet) } catch (err) { void err; }
1138
1142
  copyReportBtn.textContent = '✓ Скопировано'
@@ -1237,9 +1241,11 @@ targetEl.textContent = h.title + ': ' + h.message
1237
1241
  ctx.effect(() => {if (toastObserver && typeof document !== 'undefined' && document.body) {toastObserver.observe(document.body, { childList: true, subtree: true })
1238
1242
  }
1239
1243
  return () => { if (toastObserver) toastObserver.disconnect() }}, 'dsh-russian-lang: toast-humanizer')
1240
- ctx.effect(() => {document.addEventListener('input', layoutOnInput, true)
1244
+ ctx.effect(() => {const unsubscribeSettings = scope.subscribe(() => {if (!layoutEnabled()) { layoutDismiss(); layoutBadgeHide() }})
1245
+ document.addEventListener('input', layoutOnInput, true)
1241
1246
  document.addEventListener('keydown', layoutOnKeydown, true)
1242
- return () => {unsubscribeLayout()
1247
+ return () => {unsubscribeSettings()
1248
+ unsubscribeLayout()
1243
1249
  document.removeEventListener('input', layoutOnInput, true)
1244
1250
  document.removeEventListener('keydown', layoutOnKeydown, true)
1245
1251
  layoutDismiss()
@@ -1249,7 +1255,7 @@ if (!ctx.slots || !React) return
1249
1255
  const toggleRu = (wantRu) => {try {if (runtime.getLocale().active === wantRu) return
1250
1256
  runtime.setLocale(wantRu ? 'ru' : 'en')
1251
1257
  } catch (err) { console.warn('dsh-russian-lang: toggle failed', err) }}
1252
- const registerPluginsItem = () => {ctx.slots.inject('plugins.item', () =>
1258
+ const registerPluginsItem = () => {return ctx.slots.inject('plugins.item', () =>
1253
1259
  ctx.slots.register({name: 'plugins.item',id: FORM_NS,order: 60,label: () => 'Russian language',locale: SETTINGS_NS_NAME,inject: () => ({ scope, runtime, toggleRu }),}, SettingsCard),)
1254
1260
  }
1255
1261
  if (typeof configForms?.whileServed === 'function') {ctx.effect(() => configForms.whileServed([FORM_NS], registerPluginsItem), 'dsh-russian-lang: plugins.item')
@@ -1258,7 +1264,7 @@ if (typeof configForms?.whileServed === 'function') {ctx.effect(() => configForm
1258
1264
  ctx.slots.inject('plugins.row.config', () =>
1259
1265
  ctx.slots.register({name: 'plugins.row.config',key: ROW_CONFIG_KEY,locale: SETTINGS_NS_NAME,inject: () => ({ scope, runtime, toggleRu }),}, SettingsCard),)
1260
1266
  try {ctx.slots.inject('conversation.session.header.utilities', () =>
1261
- ctx.slots.register({name: 'conversation.session.header.utilities',id: 'dsh-russian-lang-quick-switch',order: 100,locale: SETTINGS_NS_NAME,inject: () => ({ runtime, toggleRu }),}, QuickLangSwitch),)
1267
+ ctx.slots.register({name: 'conversation.session.header.utilities',id: 'dsh-russian-lang-quick-switch',order: 100,locale: SETTINGS_NS_NAME,inject: () => ({ scope, runtime, toggleRu }),}, QuickLangSwitch),)
1262
1268
  } catch (err) { void err; }
1263
1269
  try {ctx.slots.inject('conversation.chat.assistant-actions', () =>
1264
1270
  ctx.slots.register({name: 'conversation.chat.assistant-actions',id: 'dsh-russian-lang-translate-action',order: 50,locale: SETTINGS_NS_NAME,inject: () => ({ runtime }),}, TranslateTurnAction),)
@@ -1267,12 +1273,20 @@ try {ctx.slots.inject('conversation.session.header.utilities', () =>
1267
1273
  ctx.slots.register({name: 'conversation.session.header.utilities',id: 'dsh-russian-lang-md-export',order: 101,locale: SETTINGS_NS_NAME,inject: () => ({ runtime }),}, ExportMarkdownButton),)
1268
1274
  } catch (err) { void err; }}
1269
1275
  function QuickLangSwitch(props) {const inj = typeof props.inject === 'function' ? (props.inject() || {}) : (props.inject || {})
1276
+ const scope = props.scope || inj.scope
1270
1277
  const runtime = props.runtime || inj.runtime
1271
1278
  const toggleRu = props.toggleRu || inj.toggleRu
1279
+ const [snap, setSnap] = React.useState(() => (scope && typeof scope.getSnapshot === 'function' ? scope.getSnapshot() : { status: 'ready', value: {} }))
1272
1280
  const [locale, setLocaleState] = React.useState(runtime ? (runtime.getLocale().active || 'en') : 'ru')
1281
+ React.useEffect(() => {if (!scope || typeof scope.subscribe !== 'function') return
1282
+ const un = scope.subscribe(() => setSnap(scope.getSnapshot()))
1283
+ setSnap(scope.getSnapshot())
1284
+ return un
1285
+ }, [scope])
1273
1286
  React.useEffect(() => {if (!runtime) return
1274
1287
  return runtime.subscribe(() => {try { setLocaleState(runtime.getLocale().active || 'en') } catch (e) { void e; }})
1275
1288
  }, [runtime])
1289
+ if (snap.status !== 'ready' || snap.value?.quickSwitch === false) return null
1276
1290
  const isRu = locale === 'ru'
1277
1291
  return React.createElement('button', {type: 'button',className: 'rl-lang-chip' + (isRu ? ' rl-lang-chip-active' : ''),title: isRu ? 'Интерфейс: Русский (нажмите для переключения на EN)' : 'Interface: English (click for RU)',onClick: () => { if (toggleRu) toggleRu(!isRu) },}, React.createElement('span', { className: 'rl-lang-text' }, isRu ? 'RU' : 'EN'))
1278
1292
  }
@@ -1420,7 +1434,7 @@ const [snap, setSnap] = React.useState(() => (scope && scope.getSnapshot ? scope
1420
1434
  const [ruActive, setRuActive] = React.useState(() => { try { return runtime.getLocale().active === 'ru' } catch (e) { return false } })
1421
1435
  const [typo, setTypoState] = React.useState(() =>
1422
1436
  (snap.value && snap.value.typography) || {})
1423
- const [upStatus, setUpStatus] = React.useState({currentVersion: '0.3.22',latestVersion: undefined,updateAvailable: false
1437
+ const [upStatus, setUpStatus] = React.useState({currentVersion: '0.3.24',latestVersion: undefined,updateAvailable: false
1424
1438
  })
1425
1439
  const [upLoading, setUpLoading] = React.useState(false)
1426
1440
  const [upMsg, setUpMsg] = React.useState(null)
@@ -1474,6 +1488,8 @@ return un
1474
1488
  const status = snap.status || 'loading'
1475
1489
  const value = snap.value || {}
1476
1490
  const typography = typo
1491
+ const smartUxActive = typography.enabled !== false || typography.liveInput !== false ||
1492
+ typography.yo === true || value.slashAliases !== false || value.layoutConversion !== false
1477
1493
  const overrides = value.overrides || {}
1478
1494
  const overridesCount = Object.keys(overrides).length
1479
1495
  const [newKey, setNewKey] = React.useState('')
@@ -1503,8 +1519,9 @@ const presetInfo = typeof SYSTEM_PROMPT_PRESETS !== 'undefined' ? SYSTEM_PROMPT_
1503
1519
  if (props && props.view === 'summary') {return React.createElement('div', { className: 'rl-sub' }, statusLine || t('cardSub'))
1504
1520
  }
1505
1521
  const page = !!(props && props.view === 'page')
1506
- return React.createElement('div', { className: page ? 'rl-page-seat' : 'rl-card' },React.createElement('button', {type: 'button',className: 'rl-head',style: page ? { display: 'none' } : undefined,'aria-expanded': page ? 'true' : String(open),onClick: () => setOpen(!open),},React.createElement('span', { className: 'rl-head-main' },React.createElement('div', { className: 'rl-title' },'🇷🇺 ' + t('cardTitle'),React.createElement('span', { className: 'rl-badge ' + (ruActive ? 'rl-badge-ok' : 'rl-badge-warn') },ruActive ? t('badgeRu') : t('badgeEn')),React.createElement('span', { className: 'rl-badge rl-badge-ok' }, t('badgeCoverage'))),React.createElement('div', { className: 'rl-sub' },statusLine || t('cardSub'))),React.createElement('span', {className: 'rl-chev' + (open ? ' rl-chev-open' : ''),}, React.createElement(Chevron, null))),(page || open) && React.createElement('div', { className: 'rl-body' },React.createElement('div', { className: 'rl-page' },React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secLanguage')),React.createElement('span', { className: 'rl-badge ' + (ruActive ? 'rl-badge-ok' : 'rl-badge-dim') },ruActive ? t('badgeRu') : t('badgeEn'))),React.createElement('div', { className: 'rl-section-desc' }, t('secLanguageDesc')),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(ruActive, onEnabled, disabled),t('enabled'))),React.createElement('div', { className: 'rl-item-desc' }, t('enabledDesc'))),React.createElement('div', { className: 'rl-hint-text' }, t('quickSwitchNote')),overridesCount > 0 ? React.createElement('div', { className: 'rl-badge rl-badge-dim', style: { alignSelf: 'flex-start' } },t('overridesCount') + ': ' + overridesCount) : null
1507
- ),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secTypography')),React.createElement('span', { className: 'rl-badge rl-badge-ok' }, t('badgeSmartUx'))),React.createElement('div', { className: 'rl-section-desc' }, t('secTypographyDesc')),React.createElement('div', { className: 'rl-grid-2' },React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(typography.enabled !== false && ruActive,(ev) => setTypo({ enabled: ev.target.checked }), !ruActive || disabled),t('typography'))),React.createElement('div', { className: 'rl-item-desc' }, t('typographyDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(typography.liveInput !== false && ruActive,(ev) => setTypo({ liveInput: ev.target.checked }), !ruActive || disabled),t('liveInput'))),React.createElement('div', { className: 'rl-item-desc' }, t('liveInputDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(typography.yo === true && ruActive,(ev) => setTypo({ yo: ev.target.checked }), !ruActive || disabled),t('yo'))),React.createElement('div', { className: 'rl-item-desc' }, t('yoDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(value.slashAliases !== false && ruActive,(ev) => {try { scope.set('slashAliases', ev.target.checked) } catch (err) { void err; }}, !ruActive || disabled),t('slashAliases'))),React.createElement('div', { className: 'rl-item-desc' }, t('slashAliasesDesc')))),React.createElement('div', { className: 'rl-hotkey-box' },React.createElement('span', { className: 'rl-hotkey-tag' }, '⌨️ Alt+L'),React.createElement('span', null, t('altLHintText')))),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secAgentPrompt')),React.createElement('span', { className: 'rl-badge ' + (value.agentPrompt ? 'rl-badge-ok' : 'rl-badge-dim') },value.agentPrompt ? 'Активен' : 'Выключен')),React.createElement('div', { className: 'rl-section-desc' }, t('secAgentPromptDesc')),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(value.agentPrompt === true,(ev) => {try {const r = scope.set('agentPrompt', ev.target.checked)
1522
+ return React.createElement('div', { className: page ? 'rl-page-seat' : 'rl-card' },React.createElement('button', {type: 'button',className: 'rl-head',style: page ? { display: 'none' } : undefined,'aria-expanded': page ? 'true' : String(open),onClick: () => setOpen(!open),},React.createElement('span', { className: 'rl-head-main' },React.createElement('div', { className: 'rl-title' },'🇷🇺 ' + t('cardTitle'),React.createElement('span', { className: 'rl-badge ' + (ruActive ? 'rl-badge-ok' : 'rl-badge-warn') },ruActive ? t('badgeRu') : t('badgeEn')),React.createElement('span', { className: 'rl-badge rl-badge-ok' }, t('badgeCoverage'))),React.createElement('div', { className: 'rl-sub' },statusLine || t('cardSub'))),React.createElement('span', {className: 'rl-chev' + (open ? ' rl-chev-open' : ''),}, React.createElement(Chevron, null))),(page || open) && React.createElement('div', { className: 'rl-body' },React.createElement('div', { className: 'rl-page' },React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secLanguage')),React.createElement('span', { className: 'rl-badge ' + (ruActive ? 'rl-badge-ok' : 'rl-badge-dim') },ruActive ? t('badgeRu') : t('badgeEn'))),React.createElement('div', { className: 'rl-section-desc' }, t('secLanguageDesc')),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(ruActive, onEnabled, disabled),t('enabled'))),React.createElement('div', { className: 'rl-item-desc' }, t('enabledDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(value.quickSwitch !== false,(ev) => { try { scope.set('quickSwitch', ev.target.checked) } catch (err) { console.warn('dsh-russian-lang: set quickSwitch failed', err) } }, disabled),t('quickSwitch'))),React.createElement('div', { className: 'rl-item-desc' }, t('quickSwitchDesc'))),overridesCount > 0 ? React.createElement('div', { className: 'rl-badge rl-badge-dim', style: { alignSelf: 'flex-start' } },t('overridesCount') + ': ' + overridesCount) : null
1523
+ ),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secTypography')),status === 'ready' && React.createElement('span', {className: 'rl-badge ' + (smartUxActive ? 'rl-badge-ok' : 'rl-badge-dim')
1524
+ }, t(smartUxActive ? 'badgeSmartUx' : 'badgeSmartUxOff'))),React.createElement('div', { className: 'rl-section-desc' }, t('secTypographyDesc')),React.createElement('div', { className: 'rl-grid-2', style: { gridAutoRows: '1fr' } },React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(typography.enabled !== false && ruActive,(ev) => setTypo({ enabled: ev.target.checked }), !ruActive || disabled),t('typography'))),React.createElement('div', { className: 'rl-item-desc' }, t('typographyDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(typography.liveInput !== false && ruActive,(ev) => setTypo({ liveInput: ev.target.checked }), !ruActive || disabled),t('liveInput'))),React.createElement('div', { className: 'rl-item-desc' }, t('liveInputDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(typography.yo === true && ruActive,(ev) => setTypo({ yo: ev.target.checked }), !ruActive || disabled),t('yo'))),React.createElement('div', { className: 'rl-item-desc' }, t('yoDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(value.slashAliases !== false && ruActive,(ev) => {try { scope.set('slashAliases', ev.target.checked) } catch (err) { void err; }}, !ruActive || disabled),t('slashAliases'))),React.createElement('div', { className: 'rl-item-desc' }, t('slashAliasesDesc'))),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(value.layoutConversion !== false,(ev) => { try { scope.set('layoutConversion', ev.target.checked) } catch (err) { console.warn('dsh-russian-lang: set layoutConversion failed', err) } }, disabled),t('altLHintText'))),React.createElement('div', { className: 'rl-item-desc' }, t('layoutConversionDesc'))))),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secAgentPrompt')),React.createElement('span', { className: 'rl-badge ' + (value.agentPrompt ? 'rl-badge-ok' : 'rl-badge-dim') },value.agentPrompt ? 'Активен' : 'Выключен')),React.createElement('div', { className: 'rl-section-desc' }, t('secAgentPromptDesc')),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { className: 'rl-item-head' },React.createElement('label', { className: 'rl-item-label' },checkbox(value.agentPrompt === true,(ev) => {try {const r = scope.set('agentPrompt', ev.target.checked)
1508
1525
  if (r && typeof r.catch === 'function') r.catch((err) => {console.warn('dsh-russian-lang: scope.set agentPrompt failed', err && err.message || err)
1509
1526
  })
1510
1527
  } catch (err) {console.warn('dsh-russian-lang: scope.set agentPrompt sync threw', err && err.message || err)
@@ -1513,7 +1530,7 @@ scope.set('agentPromptPreset', val)
1513
1530
  } catch (err) { console.warn('dsh-russian-lang: set agentPromptPreset failed', err) }}},React.createElement('option', { value: 'technical_expert' }, t('presetExpert')),React.createElement('option', { value: 'tech_writer' }, t('presetWriter')),React.createElement('option', { value: 'concise' }, t('presetConcise')),React.createElement('option', { value: 'code_reviewer' }, t('presetReviewer')),React.createElement('option', { value: 'architect' }, t('presetArchitect')),React.createElement('option', { value: 'tutor' }, t('presetTutor')))),presetInfo ? React.createElement('div', { className: 'rl-preview-box' },React.createElement('div', { style: { fontWeight: 600, marginBottom: '4px', color: 'var(--dsw-alias-label-primary)' } }, '💬 ' + presetInfo.label + ':'),presetInfo.text
1514
1531
  ) : null
1515
1532
  ) : null
1516
- ),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secUpdater')),React.createElement('span', { className: 'rl-badge ' + (upStatus.updateAvailable ? 'rl-badge-warn' : 'rl-badge-ok') },upStatus.updateAvailable ? t('badgeUpdateAvailable') : t('badgeUpToDate'))),React.createElement('div', { className: 'rl-section-desc' }, t('secUpdaterDesc')),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: '8px' } },React.createElement('div', null,React.createElement('div', { style: { fontWeight: 600, color: 'var(--dsw-alias-label-primary)' } },t('updaterCurrent').replace('{version}', upStatus.currentVersion || '0.3.22')),upStatus.updateAvailable
1533
+ ),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secUpdater')),React.createElement('span', { className: 'rl-badge ' + (upStatus.updateAvailable ? 'rl-badge-warn' : 'rl-badge-ok') },upStatus.updateAvailable ? t('badgeUpdateAvailable') : t('badgeUpToDate'))),React.createElement('div', { className: 'rl-section-desc' }, t('secUpdaterDesc')),React.createElement('div', { className: 'rl-item-card' },React.createElement('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', flexWrap: 'wrap', gap: '8px' } },React.createElement('div', null,React.createElement('div', { style: { fontWeight: 600, color: 'var(--dsw-alias-label-primary)' } },t('updaterCurrent').replace('{version}', upStatus.currentVersion || '0.3.24')),upStatus.updateAvailable
1517
1534
  ? React.createElement('div', { style: { color: 'var(--dsw-alias-state-warning-primary)', marginTop: '2px', fontWeight: 500 } },t('updaterLatest').replace('{version}', upStatus.latestVersion || ''))
1518
1535
  : React.createElement('div', { style: { color: 'var(--dsw-alias-label-secondary)', marginTop: '2px' } },t('updaterUpToDate'))),upStatus.updateAvailable
1519
1536
  ? React.createElement('button', {type: 'button',className: 'rl-btn rl-btn-primary',disabled: upLoading,onClick: triggerUpdate,}, upLoading ? t('updaterUpdating') : t('updaterBtn').replace('{version}', upStatus.latestVersion || ''))
@@ -1551,10 +1568,10 @@ if (!input) return
1551
1568
  try {const parsed = JSON.parse(input)
1552
1569
  if (parsed && typeof parsed === 'object') {const merged = Object.assign({}, overrides, parsed)
1553
1570
  scope.set('overrides', merged)
1554
- }} catch (err) { alert(t('overridesImportError') + (err && err.message || err)) }}}, t('importJsonBtn')))),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secSupport')),React.createElement('span', { className: 'rl-badge rl-badge-ok' }, '🟢 100.0%')),React.createElement('div', { className: 'rl-section-desc' }, t('secSupportDesc')),React.createElement('div', { className: 'rl-grid-3' },React.createElement('div', { className: 'rl-stat-box' },React.createElement('div', { className: 'rl-stat-val' }, '113'),React.createElement('div', { className: 'rl-stat-label' }, t('statNamespaces'))),React.createElement('div', { className: 'rl-stat-box' },React.createElement('div', { className: 'rl-stat-val' }, '1 225'),React.createElement('div', { className: 'rl-stat-label' }, t('statCoreKeys'))),React.createElement('div', { className: 'rl-stat-box' },React.createElement('div', { className: 'rl-stat-val' }, '5 924'),React.createElement('div', { className: 'rl-stat-label' }, t('statPluginKeys')))),React.createElement('div', { className: 'rl-actions-row' },React.createElement('a', {href: makeIssueUrl({}, '0.3.22'),target: '_blank',rel: 'noopener noreferrer',className: 'rl-btn rl-btn-primary'
1571
+ }} catch (err) { alert(t('overridesImportError') + (err && err.message || err)) }}}, t('importJsonBtn')))),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secSupport')),React.createElement('span', { className: 'rl-badge rl-badge-ok' }, '🟢 100.0%')),React.createElement('div', { className: 'rl-section-desc' }, t('secSupportDesc')),React.createElement('div', { className: 'rl-grid-3' },React.createElement('div', { className: 'rl-stat-box' },React.createElement('div', { className: 'rl-stat-val' }, '113'),React.createElement('div', { className: 'rl-stat-label' }, t('statNamespaces'))),React.createElement('div', { className: 'rl-stat-box' },React.createElement('div', { className: 'rl-stat-val' }, '1 225'),React.createElement('div', { className: 'rl-stat-label' }, t('statCoreKeys'))),React.createElement('div', { className: 'rl-stat-box' },React.createElement('div', { className: 'rl-stat-val' }, '5 924'),React.createElement('div', { className: 'rl-stat-label' }, t('statPluginKeys')))),React.createElement('div', { className: 'rl-actions-row' },React.createElement('a', {href: makeIssueUrl({}, '0.3.24'),target: '_blank',rel: 'noopener noreferrer',className: 'rl-btn rl-btn-primary'
1555
1572
  }, '💬 ' + t('reportIssue')),React.createElement('div', { className: 'rl-hint-text', style: { flex: 1 } },t('exportMdHint')))))))
1556
1573
  }
1557
- const RL_CSS = ['.rl-modal-mask{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--dsw-alias-bg-mask);display:flex;align-items:center;justify-content:center;z-index:99999;backdrop-filter:blur(2px)}.rl-modal-box{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:calc(100vw - 40px);max-width:500px;box-shadow:var(--dsw-alias-shadow-l3);display:flex;flex-direction:column;gap:12px;padding:18px}.rl-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;overflow:hidden;transition:border-color .15s ease}.rl-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 18px}.rl-head:hover{background:var(--dsw-alias-bg-layer-2)}.rl-head-main{flex:1;display:flex;flex-direction:column;gap:4px}.rl-title{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:600;line-height:1.4;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.rl-sub{color:var(--dsw-alias-label-secondary);font-size:13px}.rl-chev{margin-left:auto;flex:none;color:var(--dsw-alias-label-tertiary);display:inline-flex;transition:transform .16s}.rl-chev-open{transform:rotate(180deg)}.rl-body{border-top:1px solid var(--dsw-alias-border-l2);padding:18px}.rl-page{display:flex;flex-direction:column;gap:16px;max-width:960px}.rl-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:16px 18px;display:flex;flex-direction:column;gap:12px}.rl-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-section-desc{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:-4px;line-height:1.4}.rl-grid-2{display:grid;grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));gap:10px}.rl-grid-3{display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:10px}.rl-badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);display:inline-flex;align-items:center;gap:4px;font-weight:500}.rl-badge-ok{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent)}.rl-badge-warn{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary) 8%, transparent)}.rl-badge-dim{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3)}.rl-item-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}.rl-item-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-item-label{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;cursor:pointer}.rl-item-desc{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-stat-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:2px}.rl-stat-val{font-size:16px;font-weight:700;color:var(--dsw-alias-label-primary)}.rl-stat-label{font-size:11px;color:var(--dsw-alias-label-secondary);letter-spacing:0.3px}.rl-hotkey-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4;display:flex;align-items:flex-start;gap:10px}.rl-hotkey-tag{font-size:11px;font-weight:700;padding:2px 6px;border-radius:4px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);white-space:nowrap}.rl-preview-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 12px;font-size:12px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;transition:all .15s ease;text-decoration:none}.rl-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-1);border-color:var(--dsw-alias-label-secondary)}.rl-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border-color:transparent}.rl-btn-primary:hover:not(:disabled){opacity:0.9}.rl-select{height:32px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:6px;padding:0 8px;font-size:12px;outline:none;width:100%;max-width:380px}.rl-select:focus{border-color:var(--dsw-alias-state-brand-primary)}.rl-check{width:16px;height:16px;accent-color:var(--dsw-alias-label-primary);cursor:pointer;flex-shrink:0}.rl-hint-text{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-actions-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding-top:4px}.rl-lang-chip{appearance:none;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:700;padding:2px 7px;border-radius:6px;display:inline-flex;align-items:center;transition:all .15s;margin:0 4px}.rl-lang-chip:hover{border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}.rl-lang-chip-active{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rl-action-btn{appearance:none;background:0 0;border:1px solid transparent;border-radius:4px;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:11px;padding:2px 5px;display:inline-flex;align-items:center;transition:all .15s}.rl-action-btn:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3)}.rl-action-btn-active{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.rl-turn-translation{margin:8px 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;font-size:13px;line-height:1.5}.rl-trans-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:4px}.rl-trans-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:0.5px}.rl-trans-tools{display:flex;gap:4px}.rl-trans-btn{appearance:none;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;padding:2px 7px;border-radius:4px;font-size:11px}.rl-trans-btn:hover{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.rl-trans-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;user-select:text}.rl-export-md-btn{appearance:none;border:1px solid var(--dsw-alias-border-l2);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;background:transparent;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;font-weight:500;display:inline-flex;white-space:nowrap;margin-left:6px;transition:all .15s ease}.rl-export-md-btn:hover{background:var(--dsw-alias-interactive-bg-hover)}.rl-inspector-hover{position:absolute;pointer-events:none;border:2px solid var(--dsw-alias-state-brand-primary);border-radius:4px;background:color-mix(in srgb,var(--dsw-alias-state-brand-primary) 12%,transparent);box-shadow:0 0 10px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 30%,transparent);z-index:99998;transition:all .06s ease;display:none}.rl-inspector-badge{position:absolute;bottom:calc(100% + 4px);left:0;background:var(--dsw-alias-state-brand-primary);color:var(--dsw-alias-label-inverse);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;box-shadow:var(--dsw-alias-shadow-l2);pointer-events:none}.rl-inspector-pill{position:fixed;bottom:18px;right:18px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:20px;padding:6px 12px;box-shadow:var(--dsw-alias-shadow-l3);display:none;align-items:center;gap:8px;font-size:12px;z-index:99990;user-select:none}.rl-inspector-pill-active{border-color:var(--dsw-alias-state-brand-primary);box-shadow:0 0 12px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 35%,transparent)}'
1574
+ const RL_CSS = ['.rl-modal-mask{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--dsw-alias-bg-mask);display:flex;align-items:center;justify-content:center;z-index:99999;backdrop-filter:blur(2px)}.rl-modal-box{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:calc(100vw - 40px);max-width:500px;box-shadow:var(--dsw-alias-shadow-l3);display:flex;flex-direction:column;gap:12px;padding:18px}.rl-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;overflow:hidden;transition:border-color .15s ease}.rl-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 18px}.rl-head:hover{background:var(--dsw-alias-bg-layer-2)}.rl-head-main{flex:1;display:flex;flex-direction:column;gap:4px}.rl-title{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:600;line-height:1.4;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.rl-sub{color:var(--dsw-alias-label-secondary);font-size:13px}.rl-chev{margin-left:auto;flex:none;color:var(--dsw-alias-label-tertiary);display:inline-flex;transition:transform .16s}.rl-chev-open{transform:rotate(180deg)}.rl-body{border-top:1px solid var(--dsw-alias-border-l2);padding:18px}.rl-page{display:flex;flex-direction:column;gap:16px;max-width:960px}.rl-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:16px 18px;display:flex;flex-direction:column;gap:12px}.rl-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-section-desc{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:-4px;line-height:1.4}.rl-grid-2{display:grid;grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));gap:10px}.rl-grid-3{display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:10px}.rl-badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);display:inline-flex;align-items:center;gap:4px;font-weight:500}.rl-badge-ok{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent)}.rl-badge-warn{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary) 8%, transparent)}.rl-badge-dim{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3)}.rl-item-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}.rl-item-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-item-label{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;cursor:pointer}.rl-item-desc{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-stat-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:2px}.rl-stat-val{font-size:16px;font-weight:700;color:var(--dsw-alias-label-primary)}.rl-stat-label{font-size:11px;color:var(--dsw-alias-label-secondary);letter-spacing:0.3px}.rl-preview-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 12px;font-size:12px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;transition:all .15s ease;text-decoration:none}.rl-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-1);border-color:var(--dsw-alias-label-secondary)}.rl-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border-color:transparent}.rl-btn-primary:hover:not(:disabled){opacity:0.9}.rl-select{height:32px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:6px;padding:0 8px;font-size:12px;outline:none;width:100%;max-width:380px}.rl-select:focus{border-color:var(--dsw-alias-state-brand-primary)}.rl-check{width:16px;height:16px;accent-color:var(--dsw-alias-label-primary);cursor:pointer;flex-shrink:0}.rl-hint-text{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-actions-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding-top:4px}.rl-lang-chip{appearance:none;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:700;padding:2px 7px;border-radius:6px;display:inline-flex;align-items:center;transition:all .15s;margin:0 4px}.rl-lang-chip:hover{border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}.rl-lang-chip-active{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rl-action-btn{appearance:none;background:0 0;border:1px solid transparent;border-radius:4px;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:11px;padding:2px 5px;display:inline-flex;align-items:center;transition:all .15s}.rl-action-btn:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3)}.rl-action-btn-active{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.rl-turn-translation{margin:8px 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;font-size:13px;line-height:1.5}.rl-trans-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:4px}.rl-trans-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:0.5px}.rl-trans-tools{display:flex;gap:4px}.rl-trans-btn{appearance:none;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;padding:2px 7px;border-radius:4px;font-size:11px}.rl-trans-btn:hover{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.rl-trans-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;user-select:text}.rl-export-md-btn{appearance:none;border:1px solid var(--dsw-alias-border-l2);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;background:transparent;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;font-weight:500;display:inline-flex;white-space:nowrap;margin-left:6px;transition:all .15s ease}.rl-export-md-btn:hover{background:var(--dsw-alias-interactive-bg-hover)}.rl-inspector-hover{position:absolute;pointer-events:none;border:2px solid var(--dsw-alias-state-brand-primary);border-radius:4px;background:color-mix(in srgb,var(--dsw-alias-state-brand-primary) 12%,transparent);box-shadow:0 0 10px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 30%,transparent);z-index:99998;transition:all .06s ease;display:none}.rl-inspector-badge{position:absolute;bottom:calc(100% + 4px);left:0;background:var(--dsw-alias-state-brand-primary);color:var(--dsw-alias-label-inverse);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;box-shadow:var(--dsw-alias-shadow-l2);pointer-events:none}.rl-inspector-pill{position:fixed;bottom:18px;right:18px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:20px;padding:6px 12px;box-shadow:var(--dsw-alias-shadow-l3);display:none;align-items:center;gap:8px;font-size:12px;z-index:99990;user-select:none}.rl-inspector-pill-active{border-color:var(--dsw-alias-state-brand-primary);box-shadow:0 0 12px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 35%,transparent)}'
1558
1575
  ].join('')
1559
1576
  const STYLE_ID = 'dsh-russian-lang-styles'
1560
1577
  if (typeof document !== 'undefined' && (document.getElementById && !document.getElementById(STYLE_ID))) {const tag = document.createElement('style')
@@ -40,11 +40,14 @@ window.__ModuleLoader__.load({
40
40
  badgeEn: '⚪ EN active',
41
41
  badgeCoverage: '🟢 100% (7,902 keys)',
42
42
  badgeSmartUx: '⚡ Smart UX active',
43
+ badgeSmartUxOff: 'Smart UX off',
43
44
  secLanguage: '🌐 Interface language',
44
45
  secLanguageDesc: 'Switch the DSH interface language to Russian natively, without reloading the page.',
45
46
  enabled: 'Russian language enabled',
46
47
  enabledDesc: 'Switches the DeepSeek Harness interface to Russian.',
47
48
  quickSwitchNote: 'The RU ⇄ EN quick switch is available in the session header next to the dialog buttons.',
49
+ quickSwitch: 'Quick language switch',
50
+ quickSwitchDesc: 'Show the RU ⇄ EN switch in the session header.',
48
51
  secTypography: '✍️ Smart typography & input (Smart UX)',
49
52
  secTypographyDesc: 'Russian typography rules applied while you chat and type.',
50
53
  typography: 'Output typography',
@@ -55,7 +58,8 @@ window.__ModuleLoader__.load({
55
58
  liveInputDesc: 'Guillemets «», em dashes — and non-breaking spaces before sending.',
56
59
  slashAliases: 'Russian command aliases',
57
60
  slashAliasesDesc: 'Commands: /цель, /сжать, /план, /справка, /память.',
58
- altLHintText: 'Converts the keyboard layout of the current field (ghbdtn ⇄ привет).',
61
+ altLHintText: 'Keyboard layout hints and conversion',
62
+ layoutConversionDesc: 'Hints while typing; ⌨ Alt+L and the RU/EN badge convert the current field (ghbdtn ⇄ привет).',
59
63
  secAgentPrompt: '🤖 Agent system prompt',
60
64
  secAgentPromptDesc: 'An official DSH systemPrompt extension section for conversing in Russian.',
61
65
  agentPrompt: 'Russian agent prompt',
@@ -1110,6 +1114,7 @@ window.__ModuleLoader__.load({
1110
1114
  const layout = makeLayout(new Set(/*__FREQ_JSON__*/[]), new Set())
1111
1115
  const layoutFixCandidate = layout.candidate
1112
1116
  const learnWords = layout.learnWords
1117
+ const layoutEnabled = () => scope.getSnapshot().value?.layoutConversion !== false
1113
1118
 
1114
1119
  // Отвечаем на real input: input / input_event, слушаем на document.
1115
1120
  // Читаем value у поля, где курсор (textarea/input), не трогая contenteditable.
@@ -1293,6 +1298,7 @@ window.__ModuleLoader__.load({
1293
1298
  const label = direction === 'cyr2lat' ? 'Команда, не та раскладка' : 'Не та раскладка'
1294
1299
  layoutHintEl.textContent = label + ': ' + converted
1295
1300
  layoutHintEl.addEventListener('mousedown', (ev) => {
1301
+ if (!layoutEnabled()) return
1296
1302
  ev.preventDefault()
1297
1303
  setComposerText(inputEl, converted)
1298
1304
  learnWords(converted) // #67: запомнить принятые слова
@@ -1327,6 +1333,7 @@ window.__ModuleLoader__.load({
1327
1333
  })
1328
1334
  layoutBadgeEl.title = 'Раскладка — клик: конвертировать (Alt+L)'
1329
1335
  layoutBadgeEl.addEventListener('mousedown', (ev) => {
1336
+ if (!layoutEnabled()) return
1330
1337
  ev.preventDefault()
1331
1338
  const v = getComposerText(el)
1332
1339
  const c = layoutFixCandidate(v, 'lat2cyr') || layoutFixCandidate(v, 'cyr2lat')
@@ -1349,6 +1356,7 @@ window.__ModuleLoader__.load({
1349
1356
  let isFormatting = false
1350
1357
  const layoutOnInput = (ev) => {
1351
1358
  if (isFormatting) return
1359
+ if (!layoutEnabled()) { layoutDismiss(); layoutBadgeHide(); return }
1352
1360
  try {
1353
1361
  const el = layoutCurrentInput(ev)
1354
1362
  if (!el) { layoutDismiss(); layoutBadgeHide(); return }
@@ -1384,7 +1392,7 @@ window.__ModuleLoader__.load({
1384
1392
 
1385
1393
  // Alt+L (клавиша KeyL, Latin 'l' или русская 'д'): ручной конверт текущего инпута
1386
1394
  const isL = ev.code === 'KeyL' || ev.key.toLowerCase() === 'l' || ev.key.toLowerCase() === 'д'
1387
- if (ev.altKey && !ev.ctrlKey && !ev.metaKey && isL) {
1395
+ if (layoutEnabled() && ev.altKey && !ev.ctrlKey && !ev.metaKey && isL) {
1388
1396
  const sel = typeof window !== 'undefined' && window.getSelection && window.getSelection()
1389
1397
  const selectedText = (sel && !sel.isCollapsed) ? sel.toString() : ''
1390
1398
 
@@ -1804,9 +1812,13 @@ window.__ModuleLoader__.load({
1804
1812
  }, 'dsh-russian-lang: toast-humanizer')
1805
1813
 
1806
1814
  ctx.effect(() => {
1815
+ const unsubscribeSettings = scope.subscribe(() => {
1816
+ if (!layoutEnabled()) { layoutDismiss(); layoutBadgeHide() }
1817
+ })
1807
1818
  document.addEventListener('input', layoutOnInput, true)
1808
1819
  document.addEventListener('keydown', layoutOnKeydown, true)
1809
1820
  return () => {
1821
+ unsubscribeSettings()
1810
1822
  unsubscribeLayout()
1811
1823
  document.removeEventListener('input', layoutOnInput, true)
1812
1824
  document.removeEventListener('keydown', layoutOnKeydown, true)
@@ -1838,7 +1850,7 @@ window.__ModuleLoader__.load({
1838
1850
  // - plugins.row.config (#387): key = '@goodandready/dsh-russian-lang#' + FORM_NS
1839
1851
  // - settings-plugin-item (#389): устаревший слот упразднен в DSH 0.2.0-rc.1, удален
1840
1852
  const registerPluginsItem = () => {
1841
- ctx.slots.inject('plugins.item', () =>
1853
+ return ctx.slots.inject('plugins.item', () =>
1842
1854
  ctx.slots.register({
1843
1855
  name: 'plugins.item',
1844
1856
  id: FORM_NS,
@@ -1872,7 +1884,7 @@ window.__ModuleLoader__.load({
1872
1884
  id: 'dsh-russian-lang-quick-switch',
1873
1885
  order: 100,
1874
1886
  locale: SETTINGS_NS_NAME,
1875
- inject: () => ({ runtime, toggleRu }),
1887
+ inject: () => ({ scope, runtime, toggleRu }),
1876
1888
  }, QuickLangSwitch),
1877
1889
  )
1878
1890
  } catch (err) { /* ignore if slot not declared */ void err; }
@@ -1915,15 +1927,24 @@ window.__ModuleLoader__.load({
1915
1927
  // #158: Быстрый переключатель языка в шапке
1916
1928
  function QuickLangSwitch(props) {
1917
1929
  const inj = typeof props.inject === 'function' ? (props.inject() || {}) : (props.inject || {})
1930
+ const scope = props.scope || inj.scope
1918
1931
  const runtime = props.runtime || inj.runtime
1919
1932
  const toggleRu = props.toggleRu || inj.toggleRu
1933
+ const [snap, setSnap] = React.useState(() => (scope && typeof scope.getSnapshot === 'function' ? scope.getSnapshot() : { status: 'ready', value: {} }))
1920
1934
  const [locale, setLocaleState] = React.useState(runtime ? (runtime.getLocale().active || 'en') : 'ru')
1935
+ React.useEffect(() => {
1936
+ if (!scope || typeof scope.subscribe !== 'function') return
1937
+ const un = scope.subscribe(() => setSnap(scope.getSnapshot()))
1938
+ setSnap(scope.getSnapshot())
1939
+ return un
1940
+ }, [scope])
1921
1941
  React.useEffect(() => {
1922
1942
  if (!runtime) return
1923
1943
  return runtime.subscribe(() => {
1924
1944
  try { setLocaleState(runtime.getLocale().active || 'en') } catch (e) { /* ignore */ void e; }
1925
1945
  })
1926
1946
  }, [runtime])
1947
+ if (snap.status !== 'ready' || snap.value?.quickSwitch === false) return null
1927
1948
  const isRu = locale === 'ru'
1928
1949
  return React.createElement('button', {
1929
1950
  type: 'button',
@@ -2276,6 +2297,8 @@ window.__ModuleLoader__.load({
2276
2297
  const status = snap.status || 'loading'
2277
2298
  const value = snap.value || {}
2278
2299
  const typography = typo
2300
+ const smartUxActive = typography.enabled !== false || typography.liveInput !== false ||
2301
+ typography.yo === true || value.slashAliases !== false || value.layoutConversion !== false
2279
2302
  const overrides = value.overrides || {}
2280
2303
  const overridesCount = Object.keys(overrides).length
2281
2304
  const [newKey, setNewKey] = React.useState('')
@@ -2372,7 +2395,16 @@ window.__ModuleLoader__.load({
2372
2395
  ),
2373
2396
  React.createElement('div', { className: 'rl-item-desc' }, t('enabledDesc'))
2374
2397
  ),
2375
- React.createElement('div', { className: 'rl-hint-text' }, t('quickSwitchNote')),
2398
+ React.createElement('div', { className: 'rl-item-card' },
2399
+ React.createElement('div', { className: 'rl-item-head' },
2400
+ React.createElement('label', { className: 'rl-item-label' },
2401
+ checkbox(value.quickSwitch !== false,
2402
+ (ev) => { try { scope.set('quickSwitch', ev.target.checked) } catch (err) { console.warn('dsh-russian-lang: set quickSwitch failed', err) } }, disabled),
2403
+ t('quickSwitch')
2404
+ )
2405
+ ),
2406
+ React.createElement('div', { className: 'rl-item-desc' }, t('quickSwitchDesc'))
2407
+ ),
2376
2408
  overridesCount > 0 ? React.createElement('div', { className: 'rl-badge rl-badge-dim', style: { alignSelf: 'flex-start' } },
2377
2409
  t('overridesCount') + ': ' + overridesCount) : null
2378
2410
  ),
@@ -2381,10 +2413,12 @@ window.__ModuleLoader__.load({
2381
2413
  React.createElement('div', { className: 'rl-section-card' },
2382
2414
  React.createElement('div', { className: 'rl-section-title' },
2383
2415
  React.createElement('span', null, t('secTypography')),
2384
- React.createElement('span', { className: 'rl-badge rl-badge-ok' }, t('badgeSmartUx'))
2416
+ status === 'ready' && React.createElement('span', {
2417
+ className: 'rl-badge ' + (smartUxActive ? 'rl-badge-ok' : 'rl-badge-dim')
2418
+ }, t(smartUxActive ? 'badgeSmartUx' : 'badgeSmartUxOff'))
2385
2419
  ),
2386
2420
  React.createElement('div', { className: 'rl-section-desc' }, t('secTypographyDesc')),
2387
- React.createElement('div', { className: 'rl-grid-2' },
2421
+ React.createElement('div', { className: 'rl-grid-2', style: { gridAutoRows: '1fr' } },
2388
2422
  // 1. Типографика вывода
2389
2423
  React.createElement('div', { className: 'rl-item-card' },
2390
2424
  React.createElement('div', { className: 'rl-item-head' },
@@ -2430,11 +2464,18 @@ window.__ModuleLoader__.load({
2430
2464
  )
2431
2465
  ),
2432
2466
  React.createElement('div', { className: 'rl-item-desc' }, t('slashAliasesDesc'))
2467
+ ),
2468
+ // 5. Подсказки и конвертация раскладки
2469
+ React.createElement('div', { className: 'rl-item-card' },
2470
+ React.createElement('div', { className: 'rl-item-head' },
2471
+ React.createElement('label', { className: 'rl-item-label' },
2472
+ checkbox(value.layoutConversion !== false,
2473
+ (ev) => { try { scope.set('layoutConversion', ev.target.checked) } catch (err) { console.warn('dsh-russian-lang: set layoutConversion failed', err) } }, disabled),
2474
+ t('altLHintText')
2475
+ )
2476
+ ),
2477
+ React.createElement('div', { className: 'rl-item-desc' }, t('layoutConversionDesc'))
2433
2478
  )
2434
- ),
2435
- React.createElement('div', { className: 'rl-hotkey-box' },
2436
- React.createElement('span', { className: 'rl-hotkey-tag' }, '⌨️ Alt+L'),
2437
- React.createElement('span', null, t('altLHintText'))
2438
2479
  )
2439
2480
  ),
2440
2481
 
@@ -2740,7 +2781,7 @@ window.__ModuleLoader__.load({
2740
2781
  }
2741
2782
 
2742
2783
  const RL_CSS = [
2743
- '.rl-modal-mask{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--dsw-alias-bg-mask);display:flex;align-items:center;justify-content:center;z-index:99999;backdrop-filter:blur(2px)}.rl-modal-box{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:calc(100vw - 40px);max-width:500px;box-shadow:var(--dsw-alias-shadow-l3);display:flex;flex-direction:column;gap:12px;padding:18px}.rl-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;overflow:hidden;transition:border-color .15s ease}.rl-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 18px}.rl-head:hover{background:var(--dsw-alias-bg-layer-2)}.rl-head-main{flex:1;display:flex;flex-direction:column;gap:4px}.rl-title{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:600;line-height:1.4;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.rl-sub{color:var(--dsw-alias-label-secondary);font-size:13px}.rl-chev{margin-left:auto;flex:none;color:var(--dsw-alias-label-tertiary);display:inline-flex;transition:transform .16s}.rl-chev-open{transform:rotate(180deg)}.rl-body{border-top:1px solid var(--dsw-alias-border-l2);padding:18px}.rl-page{display:flex;flex-direction:column;gap:16px;max-width:960px}.rl-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:16px 18px;display:flex;flex-direction:column;gap:12px}.rl-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-section-desc{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:-4px;line-height:1.4}.rl-grid-2{display:grid;grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));gap:10px}.rl-grid-3{display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:10px}.rl-badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);display:inline-flex;align-items:center;gap:4px;font-weight:500}.rl-badge-ok{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent)}.rl-badge-warn{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary) 8%, transparent)}.rl-badge-dim{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3)}.rl-item-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}.rl-item-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-item-label{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;cursor:pointer}.rl-item-desc{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-stat-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:2px}.rl-stat-val{font-size:16px;font-weight:700;color:var(--dsw-alias-label-primary)}.rl-stat-label{font-size:11px;color:var(--dsw-alias-label-secondary);letter-spacing:0.3px}.rl-hotkey-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4;display:flex;align-items:flex-start;gap:10px}.rl-hotkey-tag{font-size:11px;font-weight:700;padding:2px 6px;border-radius:4px;background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);white-space:nowrap}.rl-preview-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 12px;font-size:12px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;transition:all .15s ease;text-decoration:none}.rl-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-1);border-color:var(--dsw-alias-label-secondary)}.rl-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border-color:transparent}.rl-btn-primary:hover:not(:disabled){opacity:0.9}.rl-select{height:32px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:6px;padding:0 8px;font-size:12px;outline:none;width:100%;max-width:380px}.rl-select:focus{border-color:var(--dsw-alias-state-brand-primary)}.rl-check{width:16px;height:16px;accent-color:var(--dsw-alias-label-primary);cursor:pointer;flex-shrink:0}.rl-hint-text{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-actions-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding-top:4px}.rl-lang-chip{appearance:none;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:700;padding:2px 7px;border-radius:6px;display:inline-flex;align-items:center;transition:all .15s;margin:0 4px}.rl-lang-chip:hover{border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}.rl-lang-chip-active{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rl-action-btn{appearance:none;background:0 0;border:1px solid transparent;border-radius:4px;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:11px;padding:2px 5px;display:inline-flex;align-items:center;transition:all .15s}.rl-action-btn:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3)}.rl-action-btn-active{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.rl-turn-translation{margin:8px 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;font-size:13px;line-height:1.5}.rl-trans-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:4px}.rl-trans-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:0.5px}.rl-trans-tools{display:flex;gap:4px}.rl-trans-btn{appearance:none;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;padding:2px 7px;border-radius:4px;font-size:11px}.rl-trans-btn:hover{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.rl-trans-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;user-select:text}.rl-export-md-btn{appearance:none;border:1px solid var(--dsw-alias-border-l2);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;background:transparent;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;font-weight:500;display:inline-flex;white-space:nowrap;margin-left:6px;transition:all .15s ease}.rl-export-md-btn:hover{background:var(--dsw-alias-interactive-bg-hover)}.rl-inspector-hover{position:absolute;pointer-events:none;border:2px solid var(--dsw-alias-state-brand-primary);border-radius:4px;background:color-mix(in srgb,var(--dsw-alias-state-brand-primary) 12%,transparent);box-shadow:0 0 10px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 30%,transparent);z-index:99998;transition:all .06s ease;display:none}.rl-inspector-badge{position:absolute;bottom:calc(100% + 4px);left:0;background:var(--dsw-alias-state-brand-primary);color:var(--dsw-alias-label-inverse);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;box-shadow:var(--dsw-alias-shadow-l2);pointer-events:none}.rl-inspector-pill{position:fixed;bottom:18px;right:18px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:20px;padding:6px 12px;box-shadow:var(--dsw-alias-shadow-l3);display:none;align-items:center;gap:8px;font-size:12px;z-index:99990;user-select:none}.rl-inspector-pill-active{border-color:var(--dsw-alias-state-brand-primary);box-shadow:0 0 12px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 35%,transparent)}'
2784
+ '.rl-modal-mask{position:fixed;top:0;left:0;width:100vw;height:100vh;background:var(--dsw-alias-bg-mask);display:flex;align-items:center;justify-content:center;z-index:99999;backdrop-filter:blur(2px)}.rl-modal-box{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:10px;width:calc(100vw - 40px);max-width:500px;box-shadow:var(--dsw-alias-shadow-l3);display:flex;flex-direction:column;gap:12px;padding:18px}.rl-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:12px;list-style:none;overflow:hidden;transition:border-color .15s ease}.rl-head{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;display:flex;align-items:center;gap:12px;padding:14px 18px}.rl-head:hover{background:var(--dsw-alias-bg-layer-2)}.rl-head-main{flex:1;display:flex;flex-direction:column;gap:4px}.rl-title{color:var(--dsw-alias-label-primary);font-size:16px;font-weight:600;line-height:1.4;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.rl-sub{color:var(--dsw-alias-label-secondary);font-size:13px}.rl-chev{margin-left:auto;flex:none;color:var(--dsw-alias-label-tertiary);display:inline-flex;transition:transform .16s}.rl-chev-open{transform:rotate(180deg)}.rl-body{border-top:1px solid var(--dsw-alias-border-l2);padding:18px}.rl-page{display:flex;flex-direction:column;gap:16px;max-width:960px}.rl-section-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;padding:16px 18px;display:flex;flex-direction:column;gap:12px}.rl-section-title{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-section-desc{font-size:12px;color:var(--dsw-alias-label-secondary);margin-top:-4px;line-height:1.4}.rl-grid-2{display:grid;grid-template-columns:repeat(auto-fit, minmax(280px, 1fr));gap:10px}.rl-grid-3{display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:10px}.rl-badge{font-size:11px;padding:2px 8px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);display:inline-flex;align-items:center;gap:4px;font-weight:500}.rl-badge-ok{border-color:var(--dsw-alias-state-success-primary);color:var(--dsw-alias-state-success-primary);background:color-mix(in srgb, var(--dsw-alias-state-success-primary) 8%, transparent)}.rl-badge-warn{border-color:var(--dsw-alias-state-warning-primary);color:var(--dsw-alias-state-warning-primary);background:color-mix(in srgb, var(--dsw-alias-state-warning-primary) 8%, transparent)}.rl-badge-dim{border-color:var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3)}.rl-item-card{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:4px}.rl-item-head{display:flex;align-items:center;justify-content:space-between;gap:8px}.rl-item-label{font-size:13px;font-weight:500;color:var(--dsw-alias-label-primary);display:flex;align-items:center;gap:8px;cursor:pointer}.rl-item-desc{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-stat-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;display:flex;flex-direction:column;gap:2px}.rl-stat-val{font-size:16px;font-weight:700;color:var(--dsw-alias-label-primary)}.rl-stat-label{font-size:11px;color:var(--dsw-alias-label-secondary);letter-spacing:0.3px}.rl-preview-box{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);border-radius:8px;padding:10px 12px;font-size:12px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-btn{appearance:none;font:inherit;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;padding:6px 12px;font-size:12px;background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;transition:all .15s ease;text-decoration:none}.rl-btn:hover:not(:disabled){background:var(--dsw-alias-bg-layer-1);border-color:var(--dsw-alias-label-secondary)}.rl-btn-primary{background:var(--dsw-alias-label-primary);color:var(--dsw-alias-bg-layer-3);border-color:transparent}.rl-btn-primary:hover:not(:disabled){opacity:0.9}.rl-select{height:32px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-primary);border-radius:6px;padding:0 8px;font-size:12px;outline:none;width:100%;max-width:380px}.rl-select:focus{border-color:var(--dsw-alias-state-brand-primary)}.rl-check{width:16px;height:16px;accent-color:var(--dsw-alias-label-primary);cursor:pointer;flex-shrink:0}.rl-hint-text{font-size:11px;color:var(--dsw-alias-label-secondary);line-height:1.4}.rl-actions-row{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding-top:4px}.rl-lang-chip{appearance:none;cursor:pointer;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3);color:var(--dsw-alias-label-secondary);font-size:11px;font-weight:700;padding:2px 7px;border-radius:6px;display:inline-flex;align-items:center;transition:all .15s;margin:0 4px}.rl-lang-chip:hover{border-color:var(--dsw-alias-label-primary);color:var(--dsw-alias-label-primary)}.rl-lang-chip-active{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2)}.rl-action-btn{appearance:none;background:0 0;border:1px solid transparent;border-radius:4px;color:var(--dsw-alias-label-secondary);cursor:pointer;font-size:11px;padding:2px 5px;display:inline-flex;align-items:center;transition:all .15s}.rl-action-btn:hover{color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-3)}.rl-action-btn-active{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-border-l2)}.rl-turn-translation{margin:8px 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:8px;font-size:13px;line-height:1.5}.rl-trans-head{display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;border-bottom:1px solid var(--dsw-alias-border-l2);padding-bottom:4px}.rl-trans-title{font-size:11px;font-weight:600;color:var(--dsw-alias-label-secondary);text-transform:uppercase;letter-spacing:0.5px}.rl-trans-tools{display:flex;gap:4px}.rl-trans-btn{appearance:none;background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);cursor:pointer;padding:2px 7px;border-radius:4px;font-size:11px}.rl-trans-btn:hover{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary)}.rl-trans-body{color:var(--dsw-alias-label-primary);white-space:pre-wrap;word-break:break-word;user-select:text}.rl-export-md-btn{appearance:none;border:1px solid var(--dsw-alias-border-l2);height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;background:transparent;border-radius:18px;justify-content:center;align-items:center;gap:4px;padding:6px 12px;font-size:13px;font-weight:500;display:inline-flex;white-space:nowrap;margin-left:6px;transition:all .15s ease}.rl-export-md-btn:hover{background:var(--dsw-alias-interactive-bg-hover)}.rl-inspector-hover{position:absolute;pointer-events:none;border:2px solid var(--dsw-alias-state-brand-primary);border-radius:4px;background:color-mix(in srgb,var(--dsw-alias-state-brand-primary) 12%,transparent);box-shadow:0 0 10px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 30%,transparent);z-index:99998;transition:all .06s ease;display:none}.rl-inspector-badge{position:absolute;bottom:calc(100% + 4px);left:0;background:var(--dsw-alias-state-brand-primary);color:var(--dsw-alias-label-inverse);font-size:10px;font-weight:600;padding:2px 6px;border-radius:4px;white-space:nowrap;box-shadow:var(--dsw-alias-shadow-l2);pointer-events:none}.rl-inspector-pill{position:fixed;bottom:18px;right:18px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary);border:1px solid var(--dsw-alias-border-l1);border-radius:20px;padding:6px 12px;box-shadow:var(--dsw-alias-shadow-l3);display:none;align-items:center;gap:8px;font-size:12px;z-index:99990;user-select:none}.rl-inspector-pill-active{border-color:var(--dsw-alias-state-brand-primary);box-shadow:0 0 12px color-mix(in srgb,var(--dsw-alias-state-brand-primary) 35%,transparent)}'
2744
2785
  ].join('')
2745
2786
  const STYLE_ID = 'dsh-russian-lang-styles'
2746
2787
  if (typeof document !== 'undefined' && (document.getElementById && !document.getElementById(STYLE_ID))) {
package/lib/index.js CHANGED
@@ -68,6 +68,7 @@ export const Config = z.object({
68
68
  agentPrompt: vol(z.boolean().required(false)),
69
69
  agentPromptPreset: vol(z.string().required(false)),
70
70
  slashAliases: vol(z.boolean().required(false)),
71
+ layoutConversion: vol(z.boolean().required(false)),
71
72
  quickSwitch: vol(z.boolean().required(false)),
72
73
  translateEngine: vol(z.string().required(false)),
73
74
  localApiUrl: vol(z.string().required(false))