@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 +6 -6
- package/lib/client.js +33 -16
- package/lib/client.template.js +53 -12
- package/lib/index.js +1 -0
- package/lib/locales/core.json +1 -1
- package/lib/locales/plugins/03-dshmarket.json +1 -1
- package/lib/locales/plugins/15-commandcode.json +1 -1
- package/lib/locales/plugins/17-dsh-context.json +1 -1
- package/lib/locales/plugins/26-config-manager.json +1 -1
- package/lib/locales/plugins/37-time-machine.json +1 -1
- package/lib/locales/plugins/38-context-lens.json +1 -1
- package/lib/locales/plugins/83-smart-restart.json +1 -1
- package/package.json +5 -4
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.
|
|
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.
|
|
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-
|
|
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 [Слой перевода и адаптации —
|
|
56
|
-
Loader --> CoreDict[
|
|
57
|
-
Loader --> PluginDict[
|
|
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":"
|
|
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: '
|
|
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) => {
|
|
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) => {
|
|
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.
|
|
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(() => {
|
|
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 () => {
|
|
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.
|
|
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-
|
|
1507
|
-
),React.createElement('div', { className: 'rl-section-card' },React.createElement('div', { className: 'rl-section-title' },React.createElement('span', null, t('secTypography')),
|
|
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.
|
|
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.
|
|
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-
|
|
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')
|
package/lib/client.template.js
CHANGED
|
@@ -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: '
|
|
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-
|
|
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', {
|
|
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-
|
|
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))
|