import { defineFieldCopy } from '@/app/settings/field-copy' import { defineLocale } from './define-locale' // RU_PLURAL: (count, one, few, many) — русские формы сущ. падежа // RU_NOUN: (count, one, few, many) — формы род. множественного // count может быть number или string (часть подписей en.ts передаёт строки) const ruNum = (count: number | string) => (typeof count === 'string' ? Number(count) || 0 : count) const RU_PLURAL = (count: number | string, one: string, few: string, many: string) => { const c = ruNum(count) const n = Math.abs(c) % 10 const nn = Math.abs(c) % 100 return n === 1 && nn !== 11 ? one : n >= 2 && n <= 4 && (nn < 12 || nn > 14) ? few : many } const RU_NOUN = (count: number | string, one: string, few: string, many: string) => { const c = ruNum(count) const n = Math.abs(c) % 10 const nn = Math.abs(c) % 100 return n === 1 && nn !== 11 ? one : n >= 2 && n <= 4 && (nn < 12 || nn > 14) ? few : many } export const ru = defineLocale({ common: { apply: 'Применить', back: 'Назад', save: 'Сохранить', saving: 'Сохранение…', cancel: 'Отмена', change: 'Изменить', choose: 'Выбрать', clear: 'Очистить', close: 'Закрыть', collapse: 'Свернуть', confirm: 'Подтвердить', connect: 'Подключить', connecting: 'Подключение', continue: 'Продолжить', copied: 'Скопировано', copy: 'Копировать', copyFailed: 'Не удалось скопировать', delete: 'Удалить', docs: 'Документация', done: 'Готово', error: 'Ошибка', expand: 'Развернуть', failed: 'Ошибка', formatJson: 'Форматировать JSON', free: 'Бесплатно', loading: 'Загрузка…', notSet: 'Не задано', refresh: 'Обновить', remove: 'Убрать', replace: 'Заменить', retry: 'Повторить', run: 'Запустить', send: 'Отправить', set: 'Установить', skip: 'Пропустить', update: 'Обновить', tryHint: term => `Попробуйте «${term}»`, on: 'Вкл', off: 'Выкл' }, fileMenu: { revealFinder: 'Показать в Finder', revealExplorer: 'Показать в Проводнике', revealFileManager: 'Открыть содержащую папку', revealInSidebar: 'Показать в дереве файлов', copyPath: 'Копировать путь', copyRelativePath: 'Копировать относительный путь', download: 'Скачать', downloadSaved: 'Сохранено', downloadFailed: 'Не удалось скачать', rename: 'Переименовать…', delete: 'Удалить', renameTitle: 'Переименование', renameLabel: 'Новое имя', deleteTitle: name => `Удалить ${name}?`, deleteBody: 'Элемент будет перемещён в корзину — его можно восстановить оттуда.', pathCopied: 'Путь скопирован' }, boot: { ready: 'Hermes Desktop готов', desktopBootFailedWithMessage: message => `Не удалось запустить приложение: ${message}`, steps: { connectingGateway: 'Подключение к шлюзу', loadingSettings: 'Загрузка настроек Hermes', loadingSessions: 'Загрузка последних сеансов', retryingRemoteBackend: 'Переподключение к удалённому бэкенду Hermes…', startingDesktopConnection: 'Запуск подключения приложения', startingHermesDesktop: 'Запуск Hermes Desktop…' }, errors: { backgroundExited: 'Фоновый процесс Hermes завершён.', backgroundExitedDuringStartup: 'Фоновый процесс Hermes завершился при запуске.', backendStopped: 'Бэкенд остановлен', desktopBootFailed: 'Не удалось запустить приложение', gatewayConnectionLost: 'Соединение с шлюзом потеряно', gatewaySignInRequired: 'Требуется вход в шлюз', ipcBridgeUnavailable: 'IPC-мост приложения недоступен.' }, failure: { title: 'Hermes не удалось запустить', description: 'Фоновый шлюз не запустился. Попробуйте один из шагов восстановления ниже. Ничто из этого не удаляет ваши чаты и настройки.', remoteTitle: 'Требуется вход в удалённый шлюз', remoteDescription: 'Сессия удалённого шлюза истекла. Войдите снова, чтобы переподключиться. Ничто из этого не удаляет ваши чаты и настройки.', retry: 'Повторить', repairInstall: 'Восстановить установку', useLocalGateway: 'Использовать локальный шлюз', gatewaySettings: 'Настройки шлюза', back: 'Назад', openLogs: 'Открыть журналы', repairHint: 'Восстановление перезапускает установщик — на чистой машине это может занять несколько минут.', remoteSignInHint: signInLabel => `Выход из сохранённой сессии удалённого браузера, затем открытие ${signInLabel}. Чтобы перейти на встроенный бэкенд, используйте локальный шлюз.`, signOutAndSignIn: 'Выйти и войти', remoteFailureHint: 'Проверьте URL шлюза и вход в настройках шлюза или переключитесь на локальный шлюз.', hideRecentLogs: 'Скрыть недавние журналы', showRecentLogs: 'Показать недавние журналы', signedInTitle: 'Вы вошли в систему', signedInMessage: 'Переподключение к удалённому шлюзу…', signInIncompleteTitle: 'Вход не завершён', signInIncompleteMessage: 'Окно входа закрылось до завершения аутентификации.', signInFailed: 'Не удалось войти', signInToRemoteGateway: 'Войти в удалённый шлюз', signInWithProvider: provider => `Войти через ${provider}`, identityProvider: 'вашему провайдеру аутентификации' } }, notifications: { region: 'Уведомления', hide: 'Скрыть', show: 'Показать', more: count => `Ещё ${count} ${count % 10 === 1 && count % 100 !== 11 ? 'уведомление' : count % 10 >= 2 && count % 10 <= 4 && (count % 100 < 12 || count % 100 > 14) ? 'уведомления' : 'уведомлений'}`, clearAll: 'Очистить всё', dismiss: 'Закрыть уведомление', details: 'Подробности', copyDetail: 'Копировать подробность', copyDetailFailed: 'Не удалось скопировать подробность уведомления', backendOutOfDateTitle: 'Устаревший бэкенд', backendOutOfDateMessage: 'Ваш бэкенд Hermes старше этой сборки приложения и может работать некорректно. Обновите их, чтобы они совпали.', installMethodUnsupportedTitle: 'Неподдерживаемый способ установки', updateHermes: 'Обновить Hermes', updateReadyTitle: 'Обновление готово', updateReadyMessage: count => `Доступно ${count} ${count % 10 === 1 && count % 100 !== 11 ? 'новое изменение' : count % 10 >= 2 && count % 10 <= 4 && (count % 100 < 12 || count % 100 > 14) ? 'новых изменения' : 'новых изменений'}.`, updateReadyMessageUnknown: 'Доступно новое обновление.', seeWhatsNew: 'Смотреть, что нового', mcp: { needsAuthTitle: 'Серверу MCP требуется повторная аутентификация', needsAuthMessage: name => `Для MCP ${name} требуется повторная аутентификация.`, errorTitle: 'Сервер MCP недоступен', errorMessage: name => `MCP ${name} не прошёл проверку работоспособности.`, signIn: 'Войти', view: 'Просмотр' }, errors: { elevenLabsNeedsKey: 'Для STT ElevenLabs нужен ELEVENLABS_API_KEY.', elevenLabsRejectedKey: 'ElevenLabs отклонил API-ключ (401).', diskFull: 'Диск заполнен — освободите место и повторите.', gatewayAuthFailed: 'Аутентификация шлюза не удалась — проверьте API_SERVER_KEY.', methodNotAllowed: 'Бэкенд приложения отклонил запрос (405 Method Not Allowed). Попробуйте перезапустить Hermes Desktop.', microphonePermission: 'Доступ к микрофону запрещён.', openaiRejectedApiKey: 'OpenAI отклонил API-ключ.', openaiRejectedApiKeyWithStatus: status => `OpenAI отклонил API-ключ (${status} invalid_api_key).`, openaiTtsNeedsKey: 'Для TTS OpenAI нужен VOICE_TOOLS_OPENAI_KEY или OPENAI_API_KEY.' }, voice: { configureSpeechToText: 'Настройте распознавание речи, чтобы использовать голосовой режим.', couldNotStartSession: 'Не удалось начать голосовой сеанс', microphoneAccessDenied: 'Доступ к микрофону запрещён.', microphoneConstraintsUnsupported: 'Ограничения микрофона не поддерживаются этим устройством.', microphoneFailed: 'Ошибка микрофона', microphoneInUse: 'Микрофон уже используется другим приложением.', microphonePermissionDenied: 'Доступ к микрофону запрещён.', microphoneStartFailed: 'Не удалось начать запись с микрофона.', microphoneUnsupported: 'Это окружение не поддерживает запись с микрофона.', noMicrophone: 'Микрофон не найден.', noSpeechDetected: 'Речь не обнаружена', playbackFailed: 'Не удалось воспроизвести голос', recordingFailed: 'Не удалось записать голос', sayStopToEnd: phrase => `Скажите «${phrase}», чтобы закончить голосовой чат.`, transcriptionFailed: 'Не удалось расшифровать речь', transcriptionUnavailable: 'Расшифровка речи пока недоступна.', tryRecordingAgain: 'Попробуйте записать ещё раз.', unavailable: 'Голос недоступен' }, native: { approvalTitle: 'Требуется одобрение', approveAction: 'Одобрить', rejectAction: 'Отклонить', inputTitle: 'Требуется ввод', inputBody: 'Hermes ожидает ваш ответ.', turnDoneTitle: 'Hermes завершил', turnDoneBody: '', turnErrorTitle: 'Ход не удался', backgroundDoneTitle: 'Фоновая задача завершена', backgroundFailedTitle: 'Фоновая задача не удалась', creditsTitle: 'Кредиты' } }, remoteDisplayBanner: { message: reason => `Включён программный рендеринг — обнаружен удалённый дисплей (${reason}). GPU-ускорение отключено, чтобы избежать мерцания.` }, billingBlock: { titleNous: 'Кредиты Nous закончились', titleProvider: provider => `Кредиты закончились — ${provider}`, fallbackMessage: 'В вашем аккаунте закончились кредиты. Пополните баланс, чтобы продолжить.', openBilling: 'Открыть биллинг', addCredits: 'Пополнить кредиты', dismiss: 'Скрыть' }, titlebar: { hideSidebar: 'Скрыть боковую панель', showSidebar: 'Показать боковую панель', search: 'Поиск', searchTitle: 'Поиск сеансов, видов и действий', swapSidebarSides: 'Поменять панели местами', hideRightSidebar: 'Скрыть правую панель', showRightSidebar: 'Показать правую панель', unreadSessions: count => count === 1 ? '1 непрочитанный сеанс' : `${count} ${count % 10 === 1 && count % 100 !== 11 ? 'непрочитанный сеанс' : count % 10 >= 2 && count % 10 <= 4 && (count % 100 < 12 || count % 100 > 14) ? 'непрочитанных сеанса' : 'непрочитанных сеансов'}`, muteHaptics: 'Выключить вибрацию', unmuteHaptics: 'Включить вибрацию', openSettings: 'Открыть настройки', openStarmap: 'Открыть граф памяти', enterHud: 'Режим HUD', exitHud: 'Выйти из режима HUD', layoutEditor: 'Редактор раскладки', layoutEditorTitle: mod => `Редактор раскладки — ${mod}-клик сбрасывает раскладку` }, keybinds: { title: 'Горячие клавиши', subtitle: open => `Нажмите на сочетание, чтобы переназначить · ${open} снова открывает эту панель.`, search: 'Поиск горячих клавиш…', rebind: 'Переназначить', reset: 'Сбросить по умолчанию', resetAll: 'Сбросить всё', pressKey: 'Нажмите клавишу…', set: 'задано', conflictWith: label => `Также назначено на «${label}»`, categories: { composer: 'Композер', profiles: 'Профили', session: 'Сеанс', navigation: 'Навигация', view: 'Вид' }, actions: { 'keybinds.openPanel': 'Открыть горячие клавиши', 'nav.commandPalette': 'Открыть палитру команд', 'nav.commandCenter': 'Открыть центр команд', 'nav.settings': 'Открыть настройки', 'nav.profiles': 'Открыть профили', 'nav.skills': 'Открыть навыки', 'nav.messaging': 'Открыть мессенджеры', 'nav.artifacts': 'Открыть артефакты', 'nav.cron': 'Открыть запланированные задачи', 'nav.agents': 'Открыть агенты', 'session.new': 'Новый сеанс', 'session.newTab': 'Новая вкладка сеанса', 'session.newWindow': 'Новое окно', 'session.next': 'Следующий сеанс', 'session.prev': 'Предыдущий сеанс', 'session.slot.1': 'Переключить на недавний сеанс 1', 'session.slot.2': 'Переключить на недавний сеанс 2', 'session.slot.3': 'Переключить на недавний сеанс 3', 'session.slot.4': 'Переключить на недавний сеанс 4', 'session.slot.5': 'Переключить на недавний сеанс 5', 'session.slot.6': 'Переключить на недавний сеанс 6', 'session.slot.7': 'Переключить на недавний сеанс 7', 'session.slot.8': 'Переключить на недавний сеанс 8', 'session.slot.9': 'Переключить на недавний сеанс 9', 'session.focusSearch': 'Поиск по сеансам', 'session.togglePin': 'Закрепить / открепить текущий сеанс', 'session.archive': 'В архив текущий сеанс', 'workspace.newWorktree': 'Новый worktree', 'workspace.openFolder': 'Открыть папку как проект', 'composer.focus': 'Сфокусировать композер', 'composer.modelPicker': 'Открыть выбор модели', 'composer.voice': 'Начать / остановить голосовой диалог', 'view.toggleSidebar': 'Показать / скрыть панель сеансов', 'view.toggleRightSidebar': 'Показать / скрыть браузер файлов', 'view.toggleReview': 'Показать / скрыть панель ревью', 'view.toggleStatusbar': 'Показать / скрыть строку состояния', 'view.toggleTabStrip': 'Показать / скрыть вкладки', 'view.showFiles': 'Показать браузер файлов', 'view.showBrowser': 'Открыть браузер', 'view.toggleHud': 'Включить / выключить режим HUD', 'hud.snapToPointer': 'Переместить HUD под курсор (глобально, пока HUD открыт)', 'view.showTerminal': 'Показать / скрыть терминал', 'view.newTerminal': 'Новый терминал', 'view.nextTerminal': 'Следующий терминал', 'view.prevTerminal': 'Предыдущий терминал', 'view.closeTerminal': 'Закрыть терминал', 'view.terminalSelection': 'Отправить выделенное из терминала в композер', 'view.terminalCopy': 'Копировать выделенное из терминала', 'view.terminalPaste': 'Вставить в терминал', 'view.closeTab': 'Закрыть вкладку', 'view.reopenTab': 'Восстановить закрытую вкладку', 'view.flipPanes': 'Поменять панели местами', 'view.findInPage': 'Найти на странице', 'view.findNext': 'Следующее вхождение', 'view.findPrevious': 'Предыдущее вхождение', 'appearance.toggleMode': 'Сменить светлую / тёмную тему', 'profile.default': 'Переключить на профиль по умолчанию', 'profile.switch.1': 'Переключить на профиль 1', 'profile.switch.2': 'Переключить на профиль 2', 'profile.switch.3': 'Переключить на профиль 3', 'profile.switch.4': 'Переключить на профиль 4', 'profile.switch.5': 'Переключить на профиль 5', 'profile.switch.6': 'Переключить на профиль 6', 'profile.switch.7': 'Переключить на профиль 7', 'profile.switch.8': 'Переключить на профиль 8', 'profile.switch.9': 'Переключить на профиль 9', 'profile.switch.10': 'Переключить на профиль 10', 'profile.switch.11': 'Переключить на профиль 11', 'profile.switch.12': 'Переключить на профиль 12', 'profile.switch.13': 'Переключить на профиль 13', 'profile.switch.14': 'Переключить на профиль 14', 'profile.switch.15': 'Переключить на профиль 15', 'profile.switch.16': 'Переключить на профиль 16', 'profile.switch.17': 'Переключить на профиль 17', 'profile.switch.18': 'Переключить на профиль 18', 'profile.next': 'Следующий профиль', 'profile.prev': 'Предыдущий профиль', 'profile.toggleAll': 'Показать все профили', 'profile.create': 'Создать профиль', 'composer.send': 'Отправить сообщение', 'composer.newline': 'Вставить перенос строки', 'composer.steer': 'Направить текущий ход', 'composer.queue': 'Поставить сообщение в очередь', 'composer.sendQueued': 'Отправить следующий ход из очереди', 'composer.mention': 'Ссылка на файлы, папки, URL', 'composer.slash': 'Палитра slash-команд', 'composer.help': 'Быстрая справка', 'composer.history': 'Переключить поповер / историю', 'composer.cancel': 'Закрыть поповер · отменить запуск' } }, findInPage: { next: 'Следующее вхождение', previous: 'Предыдущее вхождение' }, language: { label: 'Язык', description: 'Выберите язык интерфейса приложения.', saving: 'Сохранение языка…', saveError: 'Не удалось обновить язык', switchTo: 'Сменить язык', searchPlaceholder: 'Поиск языка…', noResults: 'Языки не найдены' }, settings: { closeSettings: 'Закрыть настройки', exportConfig: 'Экспорт конфигурации', importConfig: 'Импорт конфигурации', resetToDefaults: 'Сбросить к значениям по умолчанию', resetConfirm: 'Сбросить все настройки к значениям Hermes по умолчанию?', exportFailed: 'Не удалось экспортировать', resetFailed: 'Не удалось сбросить', nav: { providers: 'Провайдеры', providerAccounts: 'Аккаунты', providerApiKeys: 'API-ключи', providerCustomEndpoints: 'Свои эндпоинты', gateway: 'Шлюзы', apiKeys: 'Инструменты и ключи', keybinds: 'Горячие клавиши', keysTools: 'Инструменты', keysSettings: 'Настройки', mcp: 'MCP', archivedChats: 'Архив чатов', about: 'О программе', billing: 'Оплата', notifications: 'Уведомления', plugins: 'Плагины' }, plugins: { title: 'Плагины приложения', blurb: 'Встроенные или добавленные в папку desktop-plugins. Отключите, чтобы выгрузить без перезапуска.', count: n => `Установлено: ${n}`, openFolder: 'Открыть папку плагинов', rescan: 'Пересканировать', reveal: 'Показать в файловом менеджере', enable: 'Включить', disable: 'Отключить', failed: 'ошибка', empty: 'Плагины приложения пока не установлены.', kinds: { bundled: 'встроенный', disk: 'на диске', runtime: 'runtime' }, agent: { title: 'Плагины агента', blurb: 'Плагины, установленные в бэкенд Hermes — инструменты, навыки, MCP-серверы, хуки и slash-команды. Переносимые — пакеты Agent Plugins (навыки + MCP-бандлы, работающие и в других агентах). Переключатели действуют для новых сеансов.', appliesTo: 'Применяется к:', empty: 'Плагины агента пока не установлены.', loadFailed: 'Не удалось загрузить плагины агента', portable: 'переносимый', search: 'Поиск плагинов…', noMatches: 'Плагины, подходящие под поиск, не найдены.', toggleFailed: name => `Не удалось переключить ${name}`, updateBackendToManage: 'Обновите бэкенд Hermes, чтобы управлять этим плагином из приложения.', sources: { bundled: 'встроенный', user: 'пользовательский', git: 'git', project: 'проектный', entrypoint: 'pip' } }, installModal: { title: 'Установка плагина', description: 'Перед установкой посмотрите, что содержит этот репозиторий.', repoLabel: 'Репозиторий', includesHeading: 'Состав пакета', agentLabel: 'Плагин агента', desktopLabel: 'UI приложения', agentTargetLocal: profile => `Устанавливается в локальный бэкенд ${profile} (~/.hermes/plugins/)`, agentTargetRemote: profile => `Устанавливается в подключённый бэкенд ${profile}`, desktopTarget: 'Устанавливается в локальную папку desktop-plugins этого приложения', desktopOnlyNote: 'Пакеты только для приложения не устанавливают плагин агента.', insecureWarning: 'Этот URL использует небезопасную или локальную схему. Для боевой установки предпочитайте https:// или git@.', securityHeading: 'Перед установкой', securityIntro: 'Устанавливайте только из проверенных источников — при желании просмотрите репозиторий ниже, чтобы увидеть, что будет добавлено.', sourceHeading: 'Исходный код', viewRepository: 'Посмотреть репозиторий', viewPluginFiles: 'Посмотреть файлы плагина', gitCloneLabel: 'URL для git clone', enableAgent: 'Включить плагин агента после установки', forceReinstall: 'Принудительная переустановка (заменить, если уже установлен)', install: 'Установить', installing: 'Установка…', probing: 'Осмотр репозитория…', probeUnavailable: 'Осмотр плагинов недоступен в этом окружении.', desktopUnavailable: 'Установка плагинов приложения недоступна в этом окружении.', selectComponent: 'Выберите хотя бы один компонент для установки.', agentSuccess: name => `Плагин агента ${name} установлен`, desktopSuccess: name => `Плагин приложения ${name} установлен`, agentFailed: 'Не удалось установить плагин агента', desktopFailed: 'Не удалось установить плагин приложения', missingEnv: vars => `Не хватает переменных окружения: ${vars}. Добавьте их в Настройки → Ключи.` } }, notifications: { title: 'Уведомления', intro: 'Системные уведомления (не всплывающие внутри приложения). Настраивается для каждого устройства.', enableAll: 'Включить уведомления', enableAllDesc: 'Если выключено — все уведомления ниже будут заглушены.', focusedHint: 'Оповещения о завершении срабатывают только пока Hermes в фоне.', kinds: { approval: { label: 'Нужно одобрение', description: 'Команда ожидает вашего одобрения или отклонения.' }, input: { label: 'Нужен ввод', description: 'Hermes задал вопрос или требует пароль/секрет.' }, turnDone: { label: 'Ответ готов', description: 'Ход завершился, пока Hermes был в фоне.' }, turnError: { label: 'Ход не удался', description: 'Ошибки фоновых ходов.' }, backgroundDone: { label: 'Фоновая задача завершена', description: 'Фоновая команда терминала выполнена.' }, credits: { label: 'Оповещения о кредитах', description: 'Доступ к кредитам приостановлен или восстановлен.' }, plugin: { label: 'Уведомления плагинов', description: 'Плагин приложения отправил уведомление, пока Hermes был в фоне.' } }, test: 'Отправить тестовое уведомление', testTitle: 'Hermes', testBody: 'Уведомления работают.', testSent: 'Тест отправлен. Если ничего не появилось, проверьте разрешения на уведомления в системе и режим «Не беспокоить».', testUnsupported: 'Эта система не поддерживает системные уведомления.', completionSoundTitle: 'Звук завершения', completionSoundDesc: 'Воспроизводится, когда ход агента завершён. Выберите пресет и прослушайте здесь.', completionSoundPreview: 'Прослушать' }, sections: { model: 'Модель', chat: 'Чат', appearance: 'Внешний вид', workspace: 'Рабочее пространство', safety: 'Безопасность', memory: 'Память и контекст', voice: 'Голос', advanced: 'Дополнительно' }, searchPlaceholder: { about: 'О Hermes Desktop', config: 'Поиск настроек…', gateway: 'Подключение шлюза…', keys: 'Поиск API-ключей…', mcp: 'Поиск MCP-серверов…', sessions: 'Поиск архивных сеансов…' }, modeOptions: { light: { label: 'Светлая', description: 'Яркие поверхности' }, dark: { label: 'Тёмная', description: 'Мягкое рабочее пространство' }, system: { label: 'Системная', description: 'Следовать настройкам ОС' } }, appearance: { title: 'Внешний вид', intro: 'Только для приложения. Режим — это яркость, тема — палитра и оформление чата.', colorMode: 'Цветовой режим', colorModeDesc: 'Выберите фиксированный режим или позвольте Hermes следовать настройкам системы.', toolViewTitle: 'Отображение вызовов инструментов', toolViewDesc: 'Режим «Продукт» скрывает сырые данные инструментов, «Технический» показывает полный вход/выход.', reasoningCollapsedTitle: 'Сворачивать «мышление» по умолчанию', reasoningCollapsedDesc: 'Стриминговое рассуждение остаётся доступным, но не разворачивается, пока вы его не откроете.', uiScaleTitle: 'Масштаб интерфейса', uiScaleDesc: percent => `Масштабирует текст и элементы управления во всём приложении. Также работает Cmd/Ctrl с +, − и 0. Сейчас: ${percent}%.`, sessionDensityTitle: 'Плотность списка сеансов', sessionDensityDesc: 'Выберите, сколько контекста показывать под заголовками сеансов в боковой панели.', sessionDensityCompact: 'Компактно', sessionDensityComfortable: 'Комфортно', sessionDensityDetailed: 'Подробно', tabStripTitle: 'Панель вкладок', tabStripDesc: 'Показывать вкладки над зоной. Автоматически скрываются, когда в зоне только одна панель.', tabStripAuto: 'Авто', tabStripAlways: 'Всегда', tabStripNever: 'Никогда', terminalFontTitle: 'Шрифт терминала', terminalFontDesc: 'Выберите установленный шрифт для терминалов приложения. Nerd Fonts отображают Powerlevel10k и иконки оболочки; оставьте пустым, чтобы использовать встроенный JetBrains Mono.', terminalFontPlaceholder: 'MesloLGS NF или CSS-стек шрифтов', terminalFontPreview: 'Предпросмотр глифов', terminalFontReset: 'Использовать по умолчанию', translucencyTitle: 'Полупрозрачность окна', translucencyDesc: 'Рабочий стол виден сквозь всё окно, включая текст. Отдельная настройка для светлой и тёмной тем.', translucencyGlassDesc: 'Матовое стекло: рабочий стол виден как плавное размытие, а текст остаётся чётким. Отдельная настройка для светлой и тёмной тем.', translucencyModeClear: 'Прозрачная', translucencyModeGlass: 'Стекло', translucencyTintTitle: 'Тон', translucencyFadeTitle: 'Затухание', translucencyFrostTitle: 'Матовость', translucencyFrost: { 'under-window': 'Глубина', popover: 'Мягкость', titlebar: 'Яркость', header: 'Отблеск' }, translucencyScopeTitle: 'Область', translucencyScope: { window: 'Всё окно', sidebar: 'Только боковая панель' }, backdropTitle: 'Фон чата', backdropDesc: 'Блёклый силуэт позади диалога.', introSplashTitle: 'Экран приветствия', introSplashDesc: 'Логотип и подсказка, показываемые на пустом чате.', reactionsTitle: 'Реакции на сообщения', reactionsDesc: 'Эмодзи-тапбеки в стиле iMessage — реагируйте на сообщения, и Hermes сможет реагировать на ваши.', composerPopoutTitle: 'Плавающий композер', composerPopoutDesc: 'Позволяет вытягивать композер из его док-зоны. Отключите, чтобы он был закреплён снизу.', embedsTitle: 'Встроенные превью', embedsDesc: 'Богатые превью загружаются со сторонних сайтов (YouTube, X, …). «Спрашивать» показывает заглушку, пока вы не разрешите каждый источник; «Всегда» загружает их автоматически; «Выкл» оставляет обычные ссылки.', embedsAsk: 'Спрашивать', embedsAlways: 'Всегда', embedsOff: 'Выкл', embedsReset: count => `Сбросить ${count} ${RU_NOUN(count, 'разрешённый сервис', 'разрешённых сервиса', 'разрешённых сервисов')}`, resumeLastSessionTitle: 'Открывать последний чат при запуске', resumeLastSessionDesc: 'Продолжайте с того места, где остановились. Выключите, чтобы всегда начинать с нового чата.', product: 'Продукт', productDesc: 'Дружелюбная активность инструментов с краткими сводками.', technical: 'Технический', technicalDesc: 'Показывать сырые аргументы/результаты инструментов и низкоуровневые детали.', themeTitle: 'Тема', themeDesc: 'Только палитры для приложения. Выбранный режим применяется поверх.', themeProfileNote: profile => `Сохранено для профиля ${profile} — у каждого профиля своя тема.`, installTitle: 'Установить из VS Code', installDesc: 'Вставьте id расширения с Marketplace (напр. dracula-theme.theme-dracula), чтобы преобразовать его цветовую тему в палитру приложения.', installPlaceholder: 'publisher.extension', installButton: 'Установить', installing: 'Установка…', installError: 'Не удалось установить эту тему.', installed: name => `Установлена «${name}».`, removeTheme: 'Удалить тему', importedBadge: 'Импортирована', pet: { title: 'Питомец', intro: 'Заберите анимированного питомца из petdex, который парит над приложением и реагирует на действия Hermes — «бегает», пока выполняются инструменты, радуется успеху и хмурится при ошибках.', restartHint: 'Питомцам нужен быстрый перезапуск — текущее приложение запустилось до появления этой функции. Выйдите из Hermes и откройте снова, затем вернитесь сюда.', on: 'Вкл', off: 'Выкл', scaleTitle: 'Размер', scaleDesc: 'Меняет размер парящего питомца. Применяется мгновенно везде.', roamTitle: 'Блуждание', roamDesc: 'Позволить питомцу самому бродить по окну, пока всё бездействие.', chooseTitle: 'Выбрать питомца', chooseDesc: 'Выбор установит его (при необходимости) и сделает активным.', searchPlaceholder: 'Поиск питомцев…', unreachable: 'Не удалось связаться с галереей petdex. Проверьте соединение и откройте страницу заново.', noMatch: query => `Нет питомцев, подходящих под «${query}».`, installedTag: 'установлен', generatedTag: 'Сгенерирован', countCapped: (cap, total) => `Показаны ${cap} из ${total} — начните вводить, чтобы сузить выбор.`, count: n => `${n} ${RU_PLURAL(n, 'питомец', 'питомца', 'питомцев')}.`, uninstall: name => `Удалить ${name}`, delete: name => `Удалить навсегда ${name}`, deleteTitle: name => `Удалить ${name}?`, deleteBody: 'Питомец будет удалён безвозвратно — переустановить его будет нельзя.', deleteConfirm: 'Удалить', rename: name => `Переименовать ${name}`, renameTitle: 'Переименовать питомца', renamePlaceholder: 'Имя вашего питомца', renameSave: 'Сохранить', exportPet: name => `Экспортировать ${name}`, adoptFailed: slug => `Не удалось забрать ${slug}`, uninstallFailed: slug => `Не удалось удалить ${slug}`, renameFailed: slug => `Не удалось переименовать ${slug}`, exportFailed: slug => `Не удалось экспортировать ${slug}`, noneAvailable: 'Сейчас нет доступных питомцев для включения.', turnOnFailed: 'Не удалось включить питомца.', turnOffFailed: 'Не удалось выключить питомца.' } }, fieldLabels: defineFieldCopy({ model: 'Модель по умолчанию', modelContextLength: 'Окно контекста', fallbackProviders: 'Резервные модели', toolsets: 'Включённые наборы инструментов', timezone: 'Часовой пояс', display: { personality: 'Личность', showReasoning: 'Блоки рассуждений' }, desktop: { repoScanEnabled: 'Автоматическое обнаружение репозиториев', repoScanRoots: 'Корни обнаружения репозиториев', repoScanExcludePaths: 'Исключаемые пути репозиториев' }, agent: { maxTurns: 'Макс. шагов агента', imageInputMode: 'Вложения изображений', apiMaxRetries: 'Повторы API', serviceTier: 'Уровень сервиса', toolUseEnforcement: 'Принудительное использование инструментов' }, terminal: { cwd: 'Рабочий каталог', backend: 'Бэкенд выполнения', timeout: 'Тайм-аут команд', persistentShell: 'Персистентная оболочка', envPassthrough: 'Пропуск переменных окружения', dockerImage: 'Образ Docker', singularityImage: 'Образ Singularity', modalImage: 'Образ Modal', daytonaImage: 'Образ Daytona' }, fileReadMaxChars: 'Лимит чтения файла', toolOutput: { maxBytes: 'Лимит вывода терминала', maxLines: 'Лимит страниц файла', maxLineLength: 'Лимит длины строки' }, codeExecution: { mode: 'Режим выполнения кода' }, approvals: { mode: 'Режим подтверждения', timeout: 'Тайм-аут подтверждения', mcpReloadConfirm: 'Подтверждать перезагрузку MCP' }, commandAllowlist: 'Список разрешённых команд', security: { redactSecrets: 'Скрывать секреты', allowPrivateUrls: 'Разрешать частные URL' }, browser: { allowPrivateUrls: 'Частные URL браузера', autoLocalForPrivateUrls: 'Локальный браузер для частных URL' }, checkpoints: { enabled: 'Чекпоинты файлов', maxSnapshots: 'Лимит чекпоинтов' }, voice: { recordKey: 'Горячая клавиша голосового ввода', maxRecordingSeconds: 'Макс. длительность записи', autoTts: 'Зачитывать ответы вслух' }, stt: { enabled: 'Распознавание речи', echoTranscripts: 'Повторять расшифровки', provider: 'Провайдер распознавания речи', local: { model: 'Локальная модель транскрипции', language: 'Язык транскрипции' }, openai: { model: 'Модель STT OpenAI' }, groq: { model: 'Модель STT Groq' }, mistral: { model: 'Модель STT Mistral' }, elevenlabs: { modelId: 'Модель STT ElevenLabs', languageCode: 'Язык ElevenLabs', tagAudioEvents: 'Метки звуковых событий', diarize: 'Разделение спикеров' } }, tts: { provider: 'Провайдер синтеза речи', edge: { voice: 'Голос Edge' }, openai: { model: 'Модель TTS OpenAI', voice: 'Голос OpenAI' }, elevenlabs: { voiceId: 'Голос ElevenLabs', modelId: 'Модель ElevenLabs' }, xai: { voiceId: 'Голос xAI (Grok)', language: 'Язык xAI', speed: 'Скорость воспроизведения xAI', autoSpeechTags: 'Автомаркеры речи xAI', optimizeStreamingLatency: 'Оптимизация задержки стриминга xAI', sampleRate: 'Частота дискретизации xAI', bitRate: 'Битрейт xAI' }, minimax: { model: 'Модель TTS MiniMax', voiceId: 'Голос MiniMax' }, mistral: { model: 'Модель TTS Mistral', voiceId: 'Голос Mistral' }, gemini: { model: 'Модель TTS Gemini', voice: 'Голос Gemini' }, neutts: { model: 'Модель NeuTTS', device: 'Устройство NeuTTS' }, kittentts: { model: 'Модель KittenTTS', voice: 'Голос KittenTTS' }, piper: { voice: 'Голос Piper' }, deepinfra: { model: 'Модель TTS DeepInfra', voice: 'Голос DeepInfra' } }, memory: { memoryEnabled: 'Персистентная память', userProfileEnabled: 'Профиль пользователя', memoryCharLimit: 'Бюджет памяти', userCharLimit: 'Бюджет профиля', provider: 'Провайдер памяти' }, context: { engine: 'Движок контекста' }, compression: { enabled: 'Авто-сжатие', threshold: 'Порог сжатия', targetRatio: 'Целевое сжатие', protectLastN: 'Защищённые недавние сообщения' }, delegation: { model: 'Модель субагента', provider: 'Провайдер субагента', maxIterations: 'Лимит ходов субагента', maxConcurrentChildren: 'Параллельные субагенты', childTimeoutSeconds: 'Тайм-аут субагента', reasoningEffort: 'Глубина рассуждений субагента' }, updates: { nonInteractiveLocalChanges: 'Локальные изменения при обновлении из приложения' } }), fieldDescriptions: defineFieldCopy({ model: 'Используется для новых чатов, если вы не выберете другую модель в композере.', modelContextLength: 'Оставьте 0, чтобы использовать обнаруженное окно контекста выбранной модели.', fallbackProviders: 'Резервные записи provider:model, которые будут пробоваться, если модель по умолчанию не сработает.', display: { personality: 'Стиль ассистента по умолчанию для новых сеансов.', showReasoning: 'Показывать блоки рассуждений, когда бэкенд их предоставляет.' }, desktop: { repoScanEnabled: 'Сканировать локальные папки на Git-репозитории, чтобы показывать их в Проектах.', repoScanRoots: 'Папки для сканирования. Оставьте пустым, чтобы сканировать домашний каталог.', repoScanExcludePaths: 'Папки и их вложенные, которые нужно пропускать при обнаружении репозиториев.' }, timezone: 'Идентификатор часового пояса IANA. Пустое значение — системный часовой пояс.', agent: { imageInputMode: 'Управляет тем, как вложения изображений отправляются модели.', maxTurns: 'Верхний предел ходов с вызовами инструментов, после которого Hermes останавливает запуск.' }, terminal: { cwd: 'Папка проекта по умолчанию для инструментов и терминала.', persistentShell: 'Сохранять состояние оболочки между командами, если бэкенд это поддерживает.', envPassthrough: 'Переменные окружения, которые передавать в выполнение инструментов.', dockerImage: 'Образ контейнера, используемый, когда бэкенд выполнения — Docker.', singularityImage: 'Образ, используемый, когда бэкенд выполнения — Singularity.', modalImage: 'Образ, используемый, когда бэкенд выполнения — Modal.', daytonaImage: 'Образ, используемый, когда бэкенд выполнения — Daytona.' }, codeExecution: { mode: 'Насколько строго выполнение кода ограничено текущим проектом.' }, fileReadMaxChars: 'Максимальное число символов, которые Hermes может прочитать из одного запроса к файлу.', approvals: { mode: 'Как Hermes обрабатывает команды, требующие явного подтверждения.', timeout: 'Как долго запросы подтверждения ждут перед тайм-аутом.' }, security: { redactSecrets: 'Скрывать обнаруженные секреты из видимого для модели содержимого, когда это возможно.' }, checkpoints: { enabled: 'Создавать снимки для отката перед правкой файлов.' }, memory: { memoryEnabled: 'Сохранять долговременные воспоминания, которые могут помочь будущим сеансам.', userProfileEnabled: 'Поддерживать компактный профиль предпочтений пользователя.' }, context: { engine: 'Стратегия управления длинными диалогами у предела контекста.' }, compression: { enabled: 'Сжимать более старый контекст, когда диалоги становятся большими.' }, voice: { autoTts: 'Автоматически зачитывать ответы ассистента.' }, tts: { xai: { voiceId: 'ID голоса xAI (например, eve) или ID пользовательского голоса.', language: 'Код языка речи (например, en, pt-BR) или «auto» для автоопределения.', speed: 'Скорость воспроизведения. 0.7 = медленнее, 1.0 = нормально, 1.5 = быстрее.', autoSpeechTags: 'Позволить LLM вставлять выразительные звуковые теги ([laughing], [sighs]) в сценарий перед синтезом.', optimizeStreamingLatency: 'Компромисс между задержкой и качеством. 0 = лучшее качество, 2 = минимальная задержка.', sampleRate: 'Частота дискретизации аудио в Гц. Выше = лучшее качество, большие файлы.', bitRate: 'Битрейт MP3 в бит/с. Действует только когда кодек — mp3.' }, neutts: { device: 'Локальное устройство инференса для NeuTTS.' } }, stt: { enabled: 'Включать локальное или провайдерное распознавание речи.', echoTranscripts: 'Возвращать в чат «сырую» 🎙️ расшифровку голосовых сообщений.', elevenlabs: { languageCode: 'Необязательный код языка ISO-639-3. Пустое значение — автоопределение ElevenLabs.' } }, updates: { nonInteractiveLocalChanges: 'Когда Hermes обновляет себя из приложения (без запроса в терминале), сохранять локальные правки исходников (stash) или выбрасывать (discard). Обновления из терминала всегда спрашивают.' } }), about: { heading: 'Hermes Desktop', version: value => `Версия ${value}`, versionUnavailable: 'Версия недоступна', bundleOutOfSync: 'Сборка приложения устарела', bundleOutOfSyncDesc: 'Рантайм Hermes обновлён, но само приложение — ещё старая сборка: новые функции интерфейса (например, Bot Mode) не появятся до обновления. Запустите обновление ниже, чтобы пересобрать приложение. Если предупреждение не исчезнет, переустановите с последнего установщика.', bundleOutOfSyncAction: 'Скачать установщик', updates: 'Обновления', checkNow: 'Проверить сейчас', checking: 'Проверка…', seeWhatsNew: 'Смотреть, что нового', updateNow: 'Обновить сейчас', releaseNotes: 'Заметки о выпуске', onLatest: 'У вас последняя версия.', installing: 'Сейчас устанавливается обновление.', cantUpdate: 'Эта сборка не может обновляться изнутри приложения.', cantReach: 'Не удалось связаться с сервером обновлений.', tapCheck: 'Нажмите «Проверить сейчас», чтобы найти обновления.', updateReady: count => `Готово новое обновление (включено ${count} ${RU_PLURAL(count, 'изменение', 'изменения', 'изменений')}).`, updateReadyUnknown: 'Готово новое обновление.', lastChecked: age => `Проверено ${age}`, justNowSuffix: ' · только что', automaticUpdates: 'Автоматические обновления', automaticUpdatesDesc: 'Hermes автоматически проверяет обновления в фоне и сообщает, когда они готовы.', branchCommit: (branch, commit) => `Ветка ${branch} · Коммит ${commit}`, never: 'никогда', justNow: 'только что', minAgo: count => `${count} ${RU_NOUN(count, 'минуту', 'минуты', 'минут')} назад`, hoursAgo: count => `${count} ${RU_NOUN(count, 'час', 'часа', 'часов')} назад`, daysAgo: count => `${count} ${RU_NOUN(count, 'день', 'дня', 'дней')} назад` }, config: { none: 'Нет', noneParen: '(нет)', builtinOnly: 'Только встроенные', notSet: 'Не задано', commaSeparated: 'значения через запятую', searchPlaceholder: 'Поиск…', noResults: 'Ничего не найдено', systemDefault: 'Системное по умолчанию', loading: 'Загрузка конфигурации Hermes…', emptyTitle: 'Настраивать нечего', emptyDesc: 'В этом разделе нет настраиваемых параметров.', failedLoad: 'Не удалось загрузить настройки', autosaveFailed: 'Не удалось сохранить автоматически', imported: 'Конфигурация импортирована', invalidJson: 'Неверный JSON конфигурации', toolsetsWipeConfirm: 'Удалить все включённые наборы инструментов? Это отключит память, терминал, веб-поиск, делегирование и большинство других инструментов, пока вы не включите их снова.', keepAwakeTitle: 'Не давать компьютеру засыпать', keepAwakeDesc: 'Не даёт этой машине засыпать, чтобы долгие или ночные прогоны продолжались. Экран при этом может гаснуть.', disableF12Title: 'Отключить F12 DevTools', disableF12Desc: 'Блокирует открытие Developer Tools по F12. Ctrl+Shift+I (на Mac — Cmd+Opt+I) продолжает работать.', attachmentSizeTitle: 'Макс. размер превью / загрузки изображений', attachmentSizeDesc: 'Насколько большой локальный файл приложение будет загружать для превью и вложений, в МБ. По умолчанию 16. Для удалённых неграфических вложений действует отдельный лимит 256 МБ. Слишком большое значение загружает весь файл в память и может подвесить или уронить приложение.', attachmentSizeUnit: 'МБ', attachmentSizeLabel: 'Макс. размер превью / загрузки изображений в мегабайтах' }, quickEntry: { enabledTitle: 'Быстрый ввод', enabledDesc: 'Глобальным горячим ключом вызывайте маленький композер откуда угодно и отправляйте запрос, не открывая Hermes.', shortcutTitle: 'Горячий ключ быстрого ввода', shortcutDesc: 'Нужен хотя бы один модификатор, например CommandOrControl+Shift+Space.', active: 'Горячий ключ активен.', takenBy: 'Это сочетание уже занято другим приложением — выберите другое.', invalidShortcut: 'Некорректное сочетание. Включите хотя бы одну модифицирующую клавишу.' }, credentials: { pasteKey: 'Вставить ключ', pasteLabelKey: label => `Вставить ключ ${label}`, optional: 'Необязательно', enterValueFirst: 'Сначала введите значение.', couldNotSave: 'Не удалось сохранить учётные данные.', remove: 'Удалить', getKey: 'Получить ключ', saving: 'Сохранение' }, envActions: { actions: 'Действия', manageInKeys: 'Управлять в API-ключах', docs: 'Документация', hideValue: 'Скрыть значение', revealValue: 'Показать значение', replace: 'Заменить', set: 'Установить', clear: 'Очистить' }, // v2 multi-connection registry: Settings → Gateways. connections: { title: 'Зарегистрированные шлюзы', intro: 'Управляйте этим устройством и всеми шлюзами Hermes, до которых можно дотянуться через удалённые, SSH или Cloud-соединения.', stagedNote: 'Переключайтесь между шлюзами из раздела «Сеансы». Профили, чаты, мессенджеры и cron-задачи остаются за своим шлюзом; работа на других шлюзах продолжается.', launchModeTitle: 'При запуске возвращаться к «Сеансам» на последнем шлюзе', launchModeDesc: 'Если выключено, «Сеансы» открываются на основном шлюзе.', searchPlaceholder: 'Поиск шлюзов…', noSearchResults: 'Шлюзы, подходящие под поиск, не найдены.', loadFailed: 'Не удалось загрузить соединения', currentPill: 'Текущий', primaryPill: 'Основной', managedPill: 'Управляется приложением', addConnection: 'Добавить соединение', editConnection: 'Изменить', removeConnection: 'Удалить', removeConfirmTitle: 'Удалить это соединение?', removeConfirmDesc: label => `«${label}» будет удалено из этого приложения. Сама инстанция не затрагивается — её можно добавить снова в любой момент.`, makePrimary: 'Сделать основным', testConnection: 'Проверить', testOk: 'Доступен', testFailed: 'Проверка соединения не удалась', saveFailed: 'Не удалось сохранить соединение', removeFailed: 'Не удалось удалить соединение', updateAll: 'Обновить все инстансы', updateAllRunning: 'Обновление всех инстансов…', updateAllDone: 'Обновления разосланы', updateAllFailed: 'Не удалось разослать обновления', updateSkippedCloud: 'Управляется Hermes Cloud', kindLocal: 'Локальный', kindRemote: 'Удалённый шлюз', kindCloud: 'Hermes Cloud', kindSsh: 'SSH', kindLocalDesc: 'Рантайм Hermes, которым управляет это приложение.', kindRemoteDesc: 'Шлюз Hermes, доступный по HTTP(S) — LAN, Tailscale или интернет.', kindCloudDesc: 'Хостинговая инстанция, обнаруженная через ваш аккаунт Hermes Cloud.', kindSshDesc: 'Установка Hermes, доступная по SSH.', labelTitle: 'Имя', labelDesc: 'Обязательно. Показывается везде, где фигурирует эта инстанция; должно быть уникальным (напр. «Домашняя лаборатория», «Рабочий ноутбук»).', labelPlaceholder: 'Домашняя лаборатория', urlTitle: 'URL шлюза', sshHostTitle: 'SSH-хост', headersTitle: 'Дополнительные заголовки шлюза', headersDesc: 'Отправляются с каждым HTTP- и WebSocket-запросом к этому шлюзу — например, для прокси доступа вроде Cloudflare Access (CF-Access-Client-Id / CF-Access-Client-Secret). Значения хранятся зашифрованными. Заголовки, которыми управляет Hermes (Authorization, Cookie, Host…), игнорируются.', headerValuePlaceholder: 'Значение', headerValueSaved: 'Сохранено — оставьте пустым, чтобы не менять', headerAdd: 'Добавить заголовок', headerRemove: 'Удалить', duplicateLocal: 'Это приложение уже управляет локальным соединением — их может быть только одно.', duplicateUrl: label => `Соединение с этим URL шлюза уже есть («${label}»).`, duplicateSsh: label => `Соединение с этим SSH-хостом уже есть («${label}»).`, sameBackendHint: label => `Тот же бэкенд, что и «${label}»`, localAddHint: 'Локальное недоступно: управляемое локальное соединение уже существует (их всегда только одно).', cloudAddHint: 'Подсказка: вход в Hermes Cloud выше автоматически обнаруживает ваших агентов — эту форму используйте только для ручной регистрации известного URL инстанса.', save: 'Сохранить соединение', saving: 'Сохранение…', cancel: 'Отмена', empty: 'Соединения пока не зарегистрированы.' }, gateway: { loading: 'Загрузка настроек шлюза…', unavailableTitle: 'Настройки шлюза недоступны', unavailableDesc: 'IPC-мост приложения не предоставляет настройки шлюза.', title: 'Подключение шлюза', envOverride: 'переопределение переменными окружения', intro: 'По умолчанию — локальный. Используйте удалённый, когда приложение должно управлять бэкендом Hermes в другом месте. Соединения шлюзов — на уровне машины; профили обнаруживаются из подключённых шлюзов.', envOverrideTitle: 'Переменные окружения управляют этой сессией приложения.', envOverrideDesc: 'Сбросьте HERMES_DESKTOP_REMOTE_URL и HERMES_DESKTOP_REMOTE_TOKEN, чтобы использовать сохранённую настройку ниже.', modeTitle: 'Режим подключения', localTitle: 'Локальный шлюз', localDesc: 'Запускает приватный бэкенд Hermes на localhost. Это значение по умолчанию, работает офлайн.', remoteTitle: 'Удалённый шлюз', remoteDesc: 'Подключает это приложение к удалённому бэкенду Hermes.', remoteAuthHint: 'Хостинговые шлюзы используют OAuth или логин/пароль; самохостинговые могут использовать токен сессии.', cloudTitle: 'Hermes Cloud', cloudDesc: 'Войдите в Hermes Cloud один раз и выбирайте агентов из своего аккаунта — без вставки URL.', cloudSignInTitle: 'Hermes Cloud', cloudSignIn: 'Войти в Hermes Cloud', cloudSignedIn: 'Вы вошли в Hermes Cloud', cloudNeedsSignIn: 'Войдите в Hermes Cloud, чтобы обнаружить агентов в вашем аккаунте.', cloudSignedInDesc: 'Вы вошли. Выберите агента ниже; сессия обновляется автоматически.', cloudAgentsTitle: 'Ваши агенты', cloudOrgPickerTitle: 'Выберите организацию', cloudOrgSelect: 'Выбрать', cloudOrgChange: 'Сменить организацию', cloudOrgRole: role => `Роль: ${role}`, cloudLoadingAgents: 'Загрузка ваших агентов…', cloudNoAgents: { before: 'Агенты на этом аккаунте не найдены. Создайте агента в', linkText: 'портале Nous', after: ', затем обновите страницу.' }, cloudRefresh: 'Обновить', cloudConnect: 'Подключиться', cloudConnecting: 'Подключение…', cloudDiscoverFailed: 'Не удалось загрузить агентов Hermes Cloud', cloudConnectFailed: 'Не удалось подключиться к этому агенту', cloudSignInFailed: 'Не удалось войти в Hermes Cloud', cloudSignedOutTitle: 'Выход из Hermes Cloud', cloudSignedOutMessage: 'Сессия Hermes Cloud сброшена.', cloudConnectedTitle: 'Подключено', cloudConnectedPill: 'Подключено', cloudConnectedTo: name => `Подключено к ${name}.`, cloudAgentProvisioning: 'Развёртывание…', cloudStatusLabel: status => `Статус: ${status}`, remoteUrlTitle: 'Удалённый URL', remoteUrlDesc: 'Базовый URL удалённого бэкенда дашборда. Поддерживаются префиксы пути, например /hermes.', probing: 'Проверяем, как аутентифицируется этот шлюз…', probeError: 'Пока не удалось связаться с этим шлюзом. Проверьте URL — способ аутентификации появится, когда он ответит.', signedIn: 'Вы вошли', signIn: 'Войти', signOut: 'Выйти', signInWith: provider => `Войти через ${provider}`, authTitle: 'Аутентификация', authSignedInPassword: 'Этот шлюз использует логин и пароль. Вы вошли; сессия обновляется автоматически.', authSignedInOauth: 'Этот шлюз использует OAuth. Вы вошли; сессия обновляется автоматически.', authNeedsPassword: 'Этот шлюз использует логин и пароль. Войдите, чтобы авторизовать это приложение.', authNeedsOauth: provider => `Этот шлюз использует OAuth. Войдите через ${provider}, чтобы авторизовать это приложение.`, tokenTitle: 'Токен сессии', tokenDesc: 'Токен сессии дашборда для доступа через REST и WebSocket. Оставьте пустым, чтобы сохранить текущий токен.', existingToken: value => `Текущий токен ${value}`, savedToken: 'сохранён', pasteSessionToken: 'Вставьте токен сессии', plainTextConfirmTitle: 'Хранить токен шлюза в открытом виде?', plainTextConfirmDesc: 'Служба системного хранилища ключей на этой машине не найдена, поэтому токен будет сохранён без шифрования в файле настроек соединения приложения, и его сможет прочитать любой процесс, работающий от вашего имени. Для шифрованного хранилища установите и включите GNOME Keyring или KWallet.', plainTextConfirmAction: 'Сохранить в открытом виде', plainTextStoredTitle: 'Токен сохранён в открытом виде', plainTextStoredDesc: 'Безопасное хранилище недоступно, поэтому сохранённый токен хранится без шифрования в файле настроек соединения приложения на этой машине. Установите и включите GNOME Keyring или KWallet для шифрования.', testRemote: 'Проверить удалённый', saveForRestart: 'Сохранить до следующего перезапуска', saveAndReconnect: 'Сохранить и переподключиться', diagnostics: 'Диагностика', diagnosticsDesc: 'Показать desktop.log в файловом менеджере — полезно, если шлюз не запускается.', openLogs: 'Открыть логи', incompleteTitle: 'Настройки удалённого шлюза неполные', incompleteSignIn: 'Введите удалённый URL и войдите, прежде чем переключаться на удалённый режим.', incompleteToken: 'Введите удалённый URL и токен сессии, прежде чем переключаться на удалённый режим.', incompleteSignInTest: 'Введите удалённый URL и войдите, прежде чем проверять.', incompleteTokenTest: 'Введите удалённый URL и токен сессии, прежде чем проверять.', enterUrlFirst: 'Сначала введите удалённый URL.', restartingTitle: 'Перезапуск соединения шлюза', savedTitle: 'Настройки шлюза сохранены', restartingMessage: 'Hermes Desktop переподключится с сохранёнными настройками — оболочка останется открытой.', savedMessage: 'Сохранено для следующего перезапуска.', connectedTo: (baseUrl, version) => `Подключено к ${baseUrl}${version ? ` · Hermes ${version}` : ''}`, reachableTitle: 'Удалённый шлюз доступен', signedOutTitle: 'Вы вышли', signedOutMessage: 'Сессия удалённого шлюза сброшена.', failedLoad: 'Не удалось загрузить настройки шлюза', signInFailed: 'Не удалось войти', signOutFailed: 'Не удалось выйти', testFailed: 'Проверка удалённого шлюза не удалась', applyFailed: 'Не удалось применить настройки шлюза', saveFailed: 'Не удалось сохранить настройки шлюза', sshTitle: 'Подключение по SSH', sshDesc: 'Hermes запускается на удалённой машине по SSH и туннелируется в это приложение — ничего не нужно запускать или открывать самим. Требуется рабочая SSH-аутентификация по ключу на хост.', sshTrustHint: 'Первый предъявленный ключ хоста доверяется и фиксируется; последующие изменения приведут к отказу.', sshHostTitle: 'Хост', sshHostDesc: 'user@host или псевдоним Host из ~/.ssh/config.', sshHostPick: 'Выбрать хост…', sshHostPickTitle: 'Хост', sshHostPickDesc: 'Псевдоним Host из ~/.ssh/config, либо «Свой», чтобы ввести вручную.', sshHostCustom: 'Свой (ввести вручную)…', sshUserTitle: 'Пользователь', sshUserDesc: 'Пусто = ~/.ssh/config или ваш текущий пользователь.', sshUserPlaceholder: 'из ~/.ssh/config', sshPortTitle: 'Порт', sshPortDesc: 'Пусто = 22 или порт из ~/.ssh/config.', sshKeyTitle: 'Файл ключа', sshKeyDesc: 'Путь к закрытому ключу. Пусто = ssh-agent или ~/.ssh/config.', sshHermesPathTitle: 'Путь к Hermes (необязательно)', sshHermesPathDesc: 'Полный путь к бинарнику hermes на удалённой машине. Пусто = автоопределение.', sshHermesPathPlaceholder: 'автоопределение', sshTestConnection: 'Проверить SSH', sshConnect: 'Подключиться', sshButtonsHint: '«Сохранить» применится при следующем запуске. «Подключиться» переподключится сейчас.', sshReachable: (host, platform) => `Доступен: ${host} (${platform}) — Hermes найден`, sshIncompleteHost: 'Введите SSH-хост перед подключением.', sshErrUnreachable: 'Не удалось достичь этого хоста по SSH. Проверьте хост, порт и сеть.', sshErrAuth: 'SSH-аутентификация не удалась. Загрузите ключ в ssh-agent (ssh-add) или задайте IdentityFile в ~/.ssh/config — Hermes запускает ssh в неинтерактивном режиме.', sshErrHostKey: 'Ключ хоста ИЗМЕНИЛСЯ с последнего подключения. Убедитесь, что это ожидаемо, затем выполните ssh-keygen -R и переподключитесь.', sshErrNotInstalled: 'Hermes не установлен на удалённой машине. Установите его там (curl -fsSL https://hermes-agent.nousresearch.com/install.sh | sh) или задайте путь к Hermes.', sshErrPlatform: 'Неподдерживаемая удалённая платформа. SSH-режим Hermes Desktop поддерживает удалённые хосты Linux, macOS и Windows.', sshErrTimeout: 'SSH-соединение истекло. Хост может быть недоступен или «спит».', sshErrUpdateRequired: 'Перед подключением через SSH обновите Hermes на удалённой машине.', sshErrUnknown: 'SSH-соединение не удалось.' }, keys: { loading: 'Загрузка API-ключей и учётных данных…', failedLoad: 'Не удалось загрузить API-ключи', empty: 'В этой категории пока ничего не настроено.' }, search: { placeholder: 'Поиск по всем настройкам…', pill: 'Поиск' }, profileScope: { appliesTo: 'Применяется к', editsProfile: profile => `Изменения на этой странице применяются к профилю «${profile}».` }, mcp: { loading: 'Загрузка MCP-серверов…', failedLoad: 'Не удалось загрузить конфигурацию MCP', nameRequiredTitle: 'Нужно имя', nameRequiredMessage: 'Задайте этому MCP-серверу ключ конфигурации.', objectRequired: 'Конфигурация сервера должна быть JSON-объектом', invalidJson: 'Неверный JSON MCP', saveFailed: 'Не удалось сохранить', removeFailed: 'Не удалось удалить', gatewayUnavailableTitle: 'Шлюз недоступен', gatewayUnavailableMessage: 'Переподключите шлюз, прежде чем перезагружать MCP.', reloadedTitle: 'Инструменты MCP перезагружены', reloadedMessage: 'Новые схемы инструментов применяются к новым ходам.', reloadFailed: 'Не удалось перезагрузить MCP', savedTitle: 'MCP-сервер сохранён', savedMessage: name => `${name} применится после перезагрузки MCP.`, newServer: 'Новый сервер', reload: 'Перезагрузить MCP', reloading: 'Перезагрузка…', emptyTitle: 'MCP-серверов нет', emptyDesc: 'Добавьте stdio- или HTTP-сервер, чтобы получить инструменты MCP.', disabled: 'отключён', editServer: 'Изменить сервер', name: 'Имя', serverJson: 'JSON сервера', remove: 'Удалить', saveServer: 'Сохранить сервер', test: 'Проверить соединение', testing: 'Проверка…', testOk: count => `Подключено — доступно ${count} ${RU_PLURAL(count, 'инструмент', 'инструмента', 'инструментов')}`, testFailed: 'Не удалось подключиться', enableServer: name => `Включить ${name}`, disableServer: name => `Отключить ${name}`, serverEnabled: name => `${name} включён — применится к новым сеансам.`, serverDisabled: name => `${name} отключён — применится к новым сеансам.`, toggleFailed: (name, enabled) => `Не удалось ${enabled ? 'включить' : 'отключить'} ${name}`, tabServers: 'Серверы', tabCatalog: 'Каталог', catalogLoading: 'Загрузка каталога MCP…', catalogLoadFailed: 'Не удалось загрузить каталог MCP', catalogEmpty: 'Записей каталога нет.', catalogInstalled: 'Установлен', catalogEnabled: 'Включён', catalogNeedsInstall: 'Нужна сборка', catalogInstall: 'Установить', catalogInstalling: 'Установка…', catalogInstallStarted: name => `Установка ${name}… применится к новым сеансам после завершения.`, catalogInstallFailed: name => `Не удалось установить ${name}`, catalogEnvPrompt: name => `${name} требует учётные данные`, catalogEnvRequired: 'Заполните обязательные значения перед установкой.', capabilitySummary: (tools, prompts, resources) => `${[`${tools} ${RU_NOUN(tools, 'инструмент', 'инструмента', 'инструментов')}`, ...(prompts ? [`${prompts} ${RU_NOUN(prompts, 'промпт', 'промпта', 'промптов')}`] : []), ...(resources ? [`${resources} ${RU_NOUN(resources, 'ресурс', 'ресурса', 'ресурсов')}`] : [])].join(', ')} включено`, costTokens: tokens => `~${tokens} ток/вызов`, usage30d: uses => `${uses} ${RU_NOUN(uses, 'использование', 'использования', 'использований')}/30д`, unusedPill: 'не используется', statusConnecting: 'Подключение…', statusNeedsAuth: 'Нужна аутентификация', statusError: 'Ошибка', statusOff: 'Выкл', allServers: 'Все серверы', authenticatedTitle: 'Аутентифицирован', authenticatedMessage: (server, count) => `${server}: ${count} ${RU_PLURAL(count, 'инструмент', 'инструмента', 'инструментов')}`, waitingForBrowser: 'Ожидание браузера…', authenticate: 'Аутентифицироваться', unsavedConnect: 'Не сохранено — сохраните mcp.json, чтобы подключиться.', enableTool: tool => `Включить ${tool}`, disableTool: tool => `Отключить ${tool}`, noOutput: 'Вывода пока нет.', deepLinkTitle: 'Добавить MCP-сервер?', deepLinkDescription: 'Ссылка запросила добавить этот MCP-сервер в Hermes. Проверьте конфигурацию ниже — она пришла из ссылки, а не из Hermes.', deepLinkStdioWarning: 'Этот сервер запускает локальный процесс на вашей машине командой, показанной ниже. Продолжайте только если доверяете источнику.', deepLinkConfirm: 'Добавить сервер', deepLinkNameInvalid: 'Имя: 1–64 символа — буквы, цифры, точки, дефисы или подчёркивания.', deepLinkNameConflict: name => `Сервер с именем ${name} уже существует — выберите другое имя или отмените.`, deepLinkErrorTitle: 'Ссылка установки MCP отклонена', deepLinkErrorName: 'Имя сервера в ссылке отсутствует или некорректно.', deepLinkErrorConfig: 'Конфигурация в ссылке не является корректным JSON в base64.', deepLinkErrorShape: 'Конфигурация должна быть JSON-объектом со строковым полем `url` или `command`.', deepLinkErrorUrl: 'Разрешены только URL серверов http:// и https://.', deepLinkErrorTooLarge: 'Пакет конфигурации превышает лимит 32 КБ.', importButton: 'Импортировать', importPlaceholder: 'Вставьте фрагмент mcp.json, команду npx/docker, строку claude mcp add, URL или ссылку Cursor…', importNoMatch: 'В вставленном тексте не распознана конфигурация сервера.', importConfirm: 'Добавить в mcp.json', importConfirmMany: count => `Добавить ${count} ${RU_PLURAL(count, 'сервер', 'сервера', 'серверов')} в mcp.json` }, model: { loading: 'Загрузка конфигурации модели…', appliesDesc: 'Применяется к новым сеансам. Для горячей смены модели в активном чате используйте выборщик модели в композере.', provider: 'Провайдер', model: 'Модель', applying: 'Применение…', defaultsLabel: 'По умолчанию', reasoning: 'Рассуждения', reasoningOff: 'Выкл', defaultsFailed: 'Не удалось сохранить модель по умолчанию', auxiliaryTitle: 'Вспомогательные модели', resetAllToMain: 'Сбросить всё на основную', auxiliaryDesc: 'Вспомогательные задачи по умолчанию выполняются основной моделью. Назначьте отдельную модель любой задаче, чтобы переопределить.', setToMain: 'На основную', change: 'Изменить', autoUseMain: 'авто · использовать основную модель', providerDefault: '(по умолчанию провайдера)', fallbackAdd: 'Добавить запасную', fallbackEmpty: 'Запасных моделей нет — используется модель по умолчанию, если она не падает.', notInCatalog: 'нет в списке моделей этого провайдера — вызовы могут уходить на запасную.', tasks: { vision: { label: 'Зрение', hint: 'Анализ изображений' }, web_extract: { label: 'Веб-извлечение', hint: 'Суммаризация страниц' }, compression: { label: 'Сжатие', hint: 'Компрессия контекста' }, skills_hub: { label: 'Хаб навыков', hint: 'Поиск навыков' }, approval: { label: 'Одобрение', hint: 'Умное авто-одобрение' }, mcp: { label: 'MCP', hint: 'Маршрутизация MCP-инструментов' }, title_generation: { label: 'Ген. заголовка', hint: 'Заголовки сеансов' }, curator: { label: 'Куратор', hint: 'Просмотр использования навыков' } } }, providers: { connectAccount: 'Подключить аккаунт', haveApiKey: 'Ввести API-ключ вместо этого?', intro: 'Войдите по подписке — копировать API-ключ не нужно. Hermes проведёт вход в браузере прямо здесь, в приложении.', connected: 'Подключено', collapse: 'Свернуть', connectAnother: 'Подключить другой провайдер', otherProviders: 'Другие провайдеры', disconnect: 'Отключить', disconnectInTerminal: 'Отключить (выполнит команду удаления в терминале)', removeConfirm: provider => `Удалить ${provider}?`, removeExternalGeneric: provider => `${provider} управляется собственным CLI — удалите его там.`, removeKeyManaged: provider => `${provider} настроен по API-ключу. Удалите его в разделе API-ключи.`, removeTerminalConfirm: (provider, command) => `Отключить ${provider}? В терминале будет выполнена команда "${command}" для сброса учётных данных.`, removeTerminalRunning: provider => `Выполняется отключение ${provider} в терминале…`, removedTitle: 'Аккаунт удалён', removedMessage: provider => `${provider} удалён.`, failedRemove: provider => `Не удалось удалить ${provider}`, noProviderKeys: 'API-ключи провайдеров недоступны.', searchKeys: 'Поиск провайдеров…', noKeysMatch: 'Провайдеры, подходящие под поиск, не найдены.', localEndpoint: { title: 'Локальный / свой эндпоинт', description: 'Направьте Hermes на любой OpenAI-совместимый эндпоинт (Zyphra, vLLM, llama.cpp, Ollama и т. д.).' }, loading: 'Загрузка провайдеров…' }, sessions: { loading: 'Загрузка архивных сеансов…', archivedTitle: 'Архивные сеансы', archivedIntro: 'Архивированные чаты скрыты из боковой панели, но сохраняют все сообщения. Чтобы архивировать чат из боковой панели — Ctrl/⌘-клик по нему.', emptyArchivedTitle: 'Архив пуст', emptyArchivedDesc: 'Архивируйте чат, чтобы скрыть его отсюда.', unarchive: 'Восстановить', deletePermanently: 'Удалить безвозвратно', messages: count => `${count} ${RU_PLURAL(count, 'сообщение', 'сообщения', 'сообщений')}`, restored: 'Восстановлено', deleteConfirm: title => `Безвозвратно удалить «${title}»? Это действие необратимо.`, autoArchiveTitle: 'Авто-архивация старых чатов', autoArchiveDesc: 'Автоматически архивировать чаты, к которым вы давно не возвращались. Закреплённые чаты никогда не архивируются, ничего не удаляется — архивные чаты просто переезжают сюда.', autoArchiveDaysLabel: 'Архивировать через', autoArchiveDaysUnit: 'дн. бездействия', autoArchiveFailed: 'Не удалось обновить авто-архивацию', defaultDirTitle: 'Папка проекта по умолчанию', defaultDirDesc: 'Новые сеансы начинаются в этой папке, если вы не выбрали другую. Оставьте пустым, чтобы использовать домашнюю директорию.', defaultDirUpdated: 'Папка проекта по умолчанию обновлена — начните новый чат (Ctrl/⌘+N), чтобы она вступила в силу', defaultsTo: label => `По умолчанию: ${label}.`, change: 'Изменить', choose: 'Выбрать', clear: 'Очистить', notSet: 'Не задано', failedLoad: 'Не удалось загрузить архивные сеансы', unarchiveFailed: 'Не удалось восстановить', deleteFailed: 'Не удалось удалить', updateDirFailed: 'Не удалось обновить папку по умолчанию', clearDirFailed: 'Не удалось очистить папку по умолчанию' }, toolsets: { loadingConfig: 'Загрузка конфигурации', savedTitle: 'Учётные данные сохранены', savedMessage: key => `${key} обновлён.`, removedTitle: 'Учётные данные удалены', removedMessage: key => `${key} удалён.`, failedSave: key => `Не удалось сохранить ${key}`, failedRemove: key => `Не удалось удалить ${key}`, failedReveal: key => `Не удалось показать ${key}`, removeConfirm: key => `Удалить ${key} из .env?`, set: 'Установить', notSet: 'Не задано', selectedTitle: 'Провайдер выбран', selectedMessage: provider => `Сейчас активен ${provider}.`, failedSelect: provider => `Не удалось выбрать ${provider}`, failedLoad: 'Не удалось загрузить конфигурацию инструментов', noProviderOptions: 'У этого набора инструментов нет вариантов провайдера — включите его, и он будет работать с вашей текущей конфигурацией.', noProviders: 'Для этого набора инструментов сейчас нет доступных провайдеров.', ready: 'Готово', needsSignIn: 'Нужен вход', needsSetup: 'Требуется настройка', activeBackend: 'Активен', activeBackendHint: 'Это ваш активный бэкенд', useBackend: 'Использовать этот бэкенд', nousIncluded: 'Входит в подписку Nous — войдите в Nous Portal, чтобы активировать.', nousAuthNeededTitle: 'Войдите в Nous Portal', nousAuthNeededMessage: provider => `${provider} сохранён, но не активируется, пока вы не войдёте в Nous Portal.`, nousAuthSignIn: 'Войти', nousAuthDoneTitle: 'Nous Portal подключён', nousAuthDoneMessage: 'Ваши бэкенды по подписке теперь активны.', nousAuthFailed: 'Вход в Nous Portal не завершён', noApiKeyRequired: 'API-ключ не требуется.', postSetupHint: step => `Этому бэкенду нужна однократная установка (${step}). Выполняется на этой машине — может занять несколько минут.`, postSetupInstalledHint: 'Установлено. Повторите настройку, только если что-то сломано.', postSetupRun: 'Запустить настройку', postSetupRerun: 'Повторить настройку', postSetupInstalled: 'Установлено', postSetupRunning: 'Установка…', postSetupStarting: 'Запуск…', postSetupCompleteTitle: 'Настройка завершена', postSetupCompleteMessage: step => `${step} установлен.`, postSetupErrorTitle: 'Настройка завершилась с ошибками', postSetupErrorMessage: step => `Посмотрите журнал ${step}.`, postSetupFailed: step => `Не удалось выполнить настройку ${step}`, webSearchActive: backend => `Поиск: ${backend}`, webExtractActive: backend => `Извлечение: ${backend}`, webCapabilityUnset: 'не задано', webUseForSearch: 'Использовать для поиска', webUseForExtract: 'Использовать для извлечения', webUsedForSearch: 'Бэкенд поиска', webUsedForExtract: 'Бэкенд извлечения', webCapabilitySelectedMessage: (provider, capability) => `${provider} теперь отвечает за веб-${capability}.`, failedSelectCapability: provider => `Не удалось настроить ${provider}`, loadingModels: 'Загрузка каталога моделей…', modelSectionTitle: 'Модель', modelCount: count => `${count} ${RU_PLURAL(count, 'модель', 'модели', 'моделей')}`, modelInUse: 'В использовании', modelDefault: 'по умолчанию', modelInactiveHint: 'Сначала выберите этот бэкенд, чтобы изменить его модель.', modelSelectedTitle: 'Модель выбрана', modelSelectedMessage: model => `${model} применится к новым сеансам.`, failedSelectModel: model => `Не удалось выбрать ${model}`, terminalBackend: { sectionTitle: 'Бэкенд выполнения', loading: 'Проверка бэкендов выполнения…', failedLoad: 'Не удалось загрузить бэкенды терминала', ready: 'Готово', needsSetup: 'Нужна настройка', unavailable: 'Недоступен', inUse: 'В использовании', selectedTitle: 'Бэкенд выбран', selectedMessage: backend => `Команды терминала теперь выполняются через ${backend}. Применится к новым сеансам.`, failedSelect: backend => `Не удалось выбрать ${backend}`, needsSetupHint: 'Этот бэкенд можно выбрать сейчас — команды будут падать, пока настройка не завершена.' } } }, skills: { tabSkills: 'Навыки', tabToolsets: 'Инструменты', configuringProfile: 'Настраивается:', tabMcp: 'MCP', all: 'Все', searchSkills: 'Поиск навыков...', searchToolsets: 'Поиск инструментов...', refresh: 'Обновить навыки', refreshing: 'Обновление навыков', loading: 'Загрузка возможностей...', noSkillsTitle: 'Навыки не найдены', noSkillsDesc: 'Попробуйте более широкий поиск или другую категорию.', noToolsetsTitle: 'Toolsets не найдены', noToolsetsDesc: 'Попробуйте более широкий запрос.', noDescription: 'Без описания.', configured: 'Настроено', needsKeys: 'Нужны ключи', visionModelHint: 'Зрение использует вашу конфигурацию вспомогательной модели — модель с поддержкой изображений выбирается там, а не здесь по провайдеру.', visionModelLink: 'Выбрать модель зрения в Настройки → Модели', toolsetsEnabled: (enabled, total) => `Включено наборов инструментов: ${enabled}/${total}`, configureToolset: label => `Настроить ${label}`, toggleToolset: (label, enabled) => `${enabled ? 'Включить' : 'Отключить'} набор инструментов ${label}`, skillsLoadFailed: 'Не удалось загрузить навыки', toolsetsRefreshFailed: 'Не удалось обновить наборы инструментов', skillEnabled: 'Навык включён', skillDisabled: 'Навык отключён', toolsetEnabled: 'Набор инструментов включён', toolsetDisabled: 'Набор инструментов отключён', appliesToNewSessions: name => `${name} применится к новым сеансам.`, failedToUpdate: name => `Не удалось обновить ${name}`, sortMostUsed: 'Самые используемые', sortAlpha: 'А–Я', sortMostUsedDesc: '↓ Самые используемые', sortLeastUsedAsc: '↑ Меньше всего используемые', enableAll: 'Включить все', disableAll: 'Отключить все', disableUnused: 'Отключить неиспользуемые', bulkUpdated: count => `Обновлено ${count} ${RU_NOUN(count, 'элемент', 'элемента', 'элементов')} для новых сеансов.`, bulkNoChange: 'Менять нечего.', usageCount: count => `использован ${count}×`, provenance: { agent: 'Научен', bundled: 'Встроенный', hub: 'Хаб' }, emptyNoneFound: noun => `Не найдено: ${noun}`, emptyNothingMatches: query => `Ничего не подходит под «${query}».`, emptyNoneAvailable: noun => `${noun} пока недоступны.`, changesApplyNewSessions: 'Изменения применяются к новым сеансам.', skillUpdated: 'Навык обновлён', edit: 'Изменить', archive: 'В архив', skillArchivedTitle: 'Навык в архиве', skillArchivedMessage: 'Восстановить через hermes curator restore.', hub: { searchPlaceholder: 'Поиск в хабе навыков', search: 'Поиск', searching: 'Поиск...', connectingHubs: 'Подключение к хабам навыков...', connectedHubs: 'Подключённые хабы:', featured: 'Избранные навыки', landingHint: 'Ищите в хабе, чтобы просматривать устанавливаемые навыки из официального индекса, GitHub и источников сообщества.', noResults: 'Совпадающие навыки в хабе не найдены.', resultCount: (count, ms) => `${count} ${RU_PLURAL(count, 'результат', 'результата', 'результатов')}${ms !== null ? ` за ${ms}мс` : ''}`, timedOut: sources => `Тайм-аут: ${sources}`, installed: 'Установлен', install: 'Установить', installing: 'Установка...', uninstall: 'Удалить', uninstalling: 'Удаление...', updateAll: 'Обновить установленные', updating: 'Обновление...', preview: 'Предпросмотр', scan: 'Сканировать', scanning: 'Сканирование...', close: 'Закрыть', files: 'Файлы', noReadme: 'Для этого навыка нет предпросмотра SKILL.md.', trust: { builtin: 'встроенный', trusted: 'доверенный', community: 'сообщество' }, verdictSafe: 'Безопасен', verdictCaution: 'Осторожно', verdictDangerous: 'Опасен', policyAllow: 'Установка разрешена', policyAsk: 'Проверьте перед установкой', policyBlock: 'Установка заблокирована политикой', findings: count => `${count} ${RU_NOUN(count, 'находка', 'находки', 'находок')}`, noFindings: 'Находок безопасности нет.', installStarted: name => `Установка ${name}...`, uninstallStarted: name => `Удаление ${name}...`, updateStarted: 'Обновление установленных навыков...', actionFailed: 'Действие с навыком не удалось', actionLog: 'Журнал действий', alreadyInstalled: name => `«${name}» уже установлен`, pickerTitle: 'Хаб навыков', pickerBrowse: 'Открыть весь хаб', pickerHide: 'Скрыть браузер хаба', pickerHint: 'Нажмите «+ Добавить к этому агенту» на любом навыке — он установится и появится в списке выше.', loadFailed: 'Не удалось загрузить хаб навыков', previewFailed: 'Не удалось получить предпросмотр навыка', scanFailed: 'Не удалось выполнить проверку безопасности', searchFailed: 'Поиск в хабе не удался' } }, starmap: { title: 'Граф памяти', subtitle: (nodes, clusters) => `${nodes} ${RU_NOUN(nodes, 'навык', 'навыка', 'навыков')} в ${clusters} ${RU_NOUN(clusters, 'категория', 'категории', 'категорий')}`, close: 'Закрыть граф памяти', refresh: 'Обновить', memory: 'Память', filterAll: 'Все', filterUsed: 'Использованные', filterLearned: 'Наученные', viewGraph: 'Граф', loadFailed: 'Не удалось загрузить граф памяти', loading: 'Загрузка…', emptyTitle: 'Пока ничего не изучено', emptyDesc: 'По мере того как Hermes создаёт навыки и память для вашей работы, они появятся здесь.', share: 'Поделиться картой', shareHint: 'Скопируйте код, чтобы поделиться этой картой, или вставьте код для загрузки. Включает только раскладку, а не вашу память или текст навыков.', shareTitle: 'Импорт / экспорт карты', sharePlaceholder: 'Вставьте код карты…', copy: 'Скопировать код карты', copied: 'Скопировано!', importMap: 'Импортировать карту', importBtn: 'Загрузить', importEmpty: 'Вставьте код карты для загрузки.', importSuccess: nodes => `Загружена карта с ${nodes} ${RU_NOUN(nodes, 'узлом', 'узла', 'узлов')}.`, importedBadge: 'импортированная карта', resetToMine: 'Вернуться к моей карте' }, agents: { close: 'Закрыть агентов', title: 'Дерево запусков', subtitle: 'Активные субагенты текущего хода в реальном времени.', emptyTitle: 'Нет активных субагентов', emptyDesc: 'Когда ход делегирует работу, дочерние агенты стримят свой прогресс сюда.', running: 'Выполняется', failed: 'Ошибка', done: 'Готово', streaming: 'Стримится', files: 'Файлы', moreFiles: count => `+ещё ${count} ${RU_NOUN(count, 'файл', 'файла', 'файлов')}`, delegation: index => `Делегирование ${index}`, workers: count => `${count} ${RU_NOUN(count, 'воркер', 'воркера', 'воркеров')}`, workersActive: count => `${count} ${RU_NOUN(count, 'активен', 'активно', 'активных')}`, agentsCount: count => `${count} ${RU_PLURAL(count, 'агент', 'агента', 'агентов')}`, activeCount: count => `${count} ${RU_NOUN(count, 'активен', 'активно', 'активных')}`, failedCount: count => `${count} ${RU_NOUN(count, 'с ошибкой', 'с ошибками', 'с ошибками')}`, toolsCount: count => `${count} ${RU_NOUN(count, 'инструмент', 'инструмента', 'инструментов')}`, filesCount: count => `${count} ${RU_NOUN(count, 'файл', 'файла', 'файлов')}`, updatedAgo: age => `обновлено ${age}`, ageNow: 'только что', ageSeconds: seconds => `${seconds}с назад`, ageMinutes: minutes => `${minutes}м назад`, ageHours: hours => `${hours}ч назад`, ageDays: days => `${days}д назад`, durationSeconds: seconds => `${seconds}с`, durationMinutes: (minutes, seconds) => `${minutes}м ${seconds}с`, tokens: value => `${value} ток` }, commandCenter: { close: 'Закрыть командный центр', paletteTitle: 'Палитра команд', back: 'Назад', searchPlaceholder: 'Поиск сеансов, представлений и действий', goTo: 'Перейти', goToSession: 'Перейти к сеансу', branches: 'Ветви', projects: 'Проекты', openFolder: 'Открыть папку как проект…', openFolderAt: path => `Открыть папку как проект — ${path}`, newSessionInProject: project => `Новый сеанс в ${project}`, commands: 'Команды', startInBranch: branch => `Новый диалог в ${branch}`, commandCenter: 'Командный центр', appearance: 'Внешний вид', settings: 'Настройки', changeTheme: 'Сменить тему', changeColorMode: 'Сменить цветовой режим…', pets: { title: 'Питомцы', placeholder: 'Поиск питомцев…', loading: 'Загрузка галереи petdex…', error: 'Не удалось подключиться к галерее petdex.', staleBackend: 'Перезапустите Hermes, чтобы использовать питомцев — бэкенд старше этой функции.', empty: 'Совпадающих питомцев нет.', turnOff: 'Отключить', turnOn: 'Включить', installed: 'Установлен', generatedTag: 'Сгенерирован', adoptFailed: 'Не удалось усыновить этого питомца.', toggleFailed: enabled => `Не удалось ${enabled ? 'включить' : 'отключить'} питомца.`, noneAvailable: 'Питомцев пока нет — выберите ниже для установки.' }, generatePet: { title: 'Сгенерировать питомца', placeholder: 'Опишите питомца для генерации…', promptHint: 'Введите описание и нажмите Enter, чтобы получить четыре варианта облика.', readyHint: 'Нажмите Enter, чтобы получить четыре варианта облика по вашему описанию.', generate: 'Сгенерировать', generating: 'Генерация…', retry: 'Повторить', hatch: 'Вылупить', spawning: 'Создаём…', hatching: 'Вылупливаем вашего питомца…', hatchingSub: 'Оживляем его…', hatched: 'Он вылупился!', hatchRow: (_state, done, total) => `Рисуем кадр ${done} из ${total}…`, hatchComposing: 'Собираем по частям…', hatchSaving: 'Почти готово…', namePlaceholder: 'Имя для вашего питомца', staleBackend: 'Обновите Hermes, чтобы генерировать питомцев.', backgroundHint: 'Можно закрыть — Hermes уведомит, когда будет готово.', slowProviderHint: 'Это может занять несколько минут', remix: 'Ремикс', remixConfirmTitle: 'Сделать ремикс из этого облика?', remixConfirmBody: 'Будет сгенерирован новый набор вариантов с этим как отправной точкой. Это может занять несколько минут.', genericError: 'Генерация не удалась — попробуйте снова или выберите подсказку.', referenceImageTooLarge: 'Изображение-референс слишком большое. Используйте меньше 16 МБ.', referenceImageInvalid: 'Не удалось прочитать это изображение-референс. Попробуйте PNG, JPG, WebP или GIF.', adopt: 'Усыновить', startOver: 'Начать заново' }, installTheme: { title: 'Установить тему…', pageTitle: 'Установка темы', placeholder: 'Поиск в VS Code Marketplace...', loading: 'Поиск в Marketplace...', error: 'Не удалось подключиться к Marketplace.', empty: 'Совпадающих тем нет.', install: 'Установить', installing: 'Установка...', installed: 'Установлена', installs: count => `${count} ${RU_NOUN(count, 'установка', 'установки', 'установок')}` }, settingsFields: 'Поля настроек', mcpServers: 'MCP-серверы', archivedChats: 'Архивные чаты', sections: { maintenance: 'Обслуживание', sessions: 'Сеансы', system: 'Система', usage: 'Использование' }, sectionDescriptions: { maintenance: 'Диагностика, резервные копии, курир и данные памяти', sessions: 'Поиск и управление сеансами', system: 'Статус, журналы и системные действия', usage: 'Токены, стоимость и активность навыков со временем' }, nav: { newChat: { title: 'Новый сеанс', detail: 'Начать новый сеанс' }, settings: { title: 'Настройки', detail: 'Настройка Hermes desktop' }, skills: { title: 'Возможности', detail: 'Навыки, инструменты и MCP-серверы' }, messaging: { title: 'Сообщения', detail: 'Настройка Telegram, Slack, Discord и других' }, artifacts: { title: 'Артефакты', detail: 'Просмотр сгенерированных результатов' } }, sectionEntries: { sessions: { title: 'Панель сеансов', detail: 'Поиск, закрепление и управление сеансами' }, system: { title: 'Системная панель', detail: 'Статус шлюза, журналы, перезапуск/обновление' }, usage: { title: 'Панель использования', detail: 'Токены, стоимость и активность навыков' } }, providerNavigate: 'Перейти', providerSessions: 'Сеансы', refresh: 'Обновить', refreshing: 'Обновление...', noResults: 'Совпадающие результаты не найдены.', pinSession: 'Закрепить сеанс', unpinSession: 'Открепить сеанс', exportSession: 'Экспортировать сеанс', deleteSession: 'Удалить сеанс', noSessions: 'Сеансов пока нет.', gatewayRunning: 'Шлюз сообщений работает', gatewayStopped: 'Шлюз сообщений остановлен', hermesActiveSessions: (version, count) => `Hermes ${version} · Активные сеансы: ${count}`, restartGateway: 'Перезапустить шлюз', openBrowser: 'Открыть браузер', gatewayRestartFailed: 'Не удалось перезапустить шлюз.', updateHermes: 'Обновить Hermes', reloadWindow: 'Перезагрузить окно', actionRunning: 'выполняется', actionDone: 'готово', actionFailed: 'ошибка', actionStartedWaiting: 'Действие запущено, ожидание статуса...', loadingStatus: 'Загрузка статуса...', recentLogs: 'Последние записи журнала', noLogs: 'Журналы ещё не загружены.', days: count => `${count}д`, statSessions: 'Сеансы', statApiCalls: 'Вызовы API', statTokens: 'Токены вход/выход', statCost: 'Оценка стоимости', actualCost: cost => `фактически ${cost}`, loadingUsage: 'Загрузка использования...', noUsage: period => `Нет использования за последние ${period} ${RU_NOUN(period, 'день', 'дня', 'дней')}.`, retry: 'Повторить', dailyTokens: 'Токены за день', input: 'вход', output: 'выход', noDailyActivity: 'Ежедневной активности нет.', topModels: 'Топ моделей', noModelUsage: 'Использование моделей пока отсутствует.', topSkills: 'Топ навыков', noSkillActivity: 'Активности навыков пока нет.', actions: count => `${count} ${RU_NOUN(count, 'действие', 'действия', 'действий')}`, logFile: 'Файл журнала', logLevel: 'Уровень', logSearchPlaceholder: 'Фильтр строк журнала...', maintenance: { runOps: 'Диагностика', doctor: 'Запустить doctor', doctorDesc: 'Проверка здоровья установки, конфигурации и провайдеров', securityAudit: 'Аудит безопасности', securityAuditDesc: 'Сканирование конфигурации и навыков на предмет рискованных настроек', backup: 'Создать резервную копию', backupDesc: 'Сжатие конфигурации, памяти, навыков и сеансов в zip', debugShare: 'Поделиться отладкой', debugShareDesc: 'Загрузка анонимизированного отчёта + журналов, получение ссылок (автоудаление через 6 ч)', debugShareRunning: 'Загрузка отладочного отчёта...', debugShareLinks: 'Ссылки для шаринга', debugShareFailed: 'Ошибка шаринга отладки', copyLink: 'Скопировать ссылку', linkCopied: 'Ссылка скопирована', curator: 'Курир навыков', curatorDesc: 'Фоновый обзор, архивирующий устаревшие навыки, созданные агентом', curatorPaused: 'Приостановлен', curatorActive: 'Активен', curatorDisabled: 'Отключён', curatorLastRun: when => `Последний запуск ${when}`, curatorNeverRan: 'Никогда не запускался', pause: 'Приостановить', resume: 'Продолжить', runNow: 'Запустить сейчас', memoryData: 'Данные памяти', memoryDataDesc: 'Встроенные файлы памяти, внедряемые в каждый сеанс', memoryProvider: name => `Активный провайдер: ${name}`, builtinMemory: 'встроенный', memoryFile: 'Память агента (MEMORY.md)', userFile: 'Профиль пользователя (USER.md)', bytes: size => size, empty: 'пусто', resetMemory: 'Сбросить память', resetUser: 'Сбросить профиль', resetAll: 'Сбросить оба', resetConfirm: target => `Удалить ${target}? Это действие необратимо.`, resetDone: files => `Удалено: ${files}.`, resetFailed: 'Не удалось сбросить память', actionStarted: name => `${name} запущен — следим за журналом...`, actionFailed: name => `Не удалось запустить ${name}`, running: 'Выполняется...', viewLog: 'Журнал действия' } }, messaging: { search: 'Поиск в сообщениях...', loading: 'Загрузка платформ сообщений...', loadFailed: 'Не удалось загрузить платформы сообщений', states: { connected: 'Подключено', connecting: 'Подключение', disabled: 'Отключено', fatal: 'Ошибка', gateway_stopped: 'Шлюз сообщений остановлен', not_configured: 'Нужна настройка', pending_restart: 'Нужен перезапуск', retrying: 'Повторная попытка', startup_failed: 'Не удалось запустить' }, unknown: 'Неизвестно', hintPendingRestart: 'Перезапустите шлюз из строки состояния, чтобы применить это изменение.', hintGatewayStopped: 'Запустите шлюз из строки состояния для подключения.', credentialsSet: 'Учётные данные заданы', needsSetup: 'Нужна настройка', gatewayStopped: 'Шлюз сообщений остановлен', getCredentials: 'Получить учётные данные', openSetupGuide: 'Открыть руководство по настройке', required: 'Обязательно', recommended: 'Рекомендуется', advanced: count => `Расширенные (${count})`, noTokenNeeded: 'Этой платформе здесь не нужен токен. Используйте руководство выше, затем включите её ниже.', enabled: 'Включено', disabled: 'Отключено', unsavedChanges: 'Несохранённые изменения', saving: 'Сохранение...', saveChanges: 'Сохранить изменения', saved: 'Сохранено', replaceValue: 'Заменить текущее значение', openDocs: 'Открыть документацию', clearField: key => `Очистить ${key}`, enableAria: name => `Включить ${name}`, disableAria: name => `Отключить ${name}`, platformEnabled: name => `${name} включено`, platformDisabled: name => `${name} отключено`, restartToApply: 'Это изменение вступит в силу после перезапуска шлюза.', setupSaved: name => `Настройка ${name} сохранена`, restartToReconnect: 'Новые учётные данные вступят в силу после перезапуска шлюза.', keyCleared: key => `${key} очищено`, setupUpdated: name => `Настройка ${name} обновлена.`, failedUpdate: name => `Не удалось обновить ${name}`, failedSave: name => `Не удалось сохранить ${name}`, failedClear: key => `Не удалось очистить ${key}`, pendingRequests: count => `Ожидающие запросы (${count})`, pendingAria: count => `${count} ${RU_NOUN(count, 'ожидающий запрос на сопряжение', 'ожидающих запроса на сопряжение', 'ожидающих запросов на сопряжение')}`, approvedUsers: count => `Одобрённые пользователи (${count})`, approve: 'Одобрить', approving: 'Одобрение...', revoke: 'Отозвать', revoking: 'Отзыв...', revokeAria: name => `Отозвать ${name}`, revokeTitle: 'Отозвать доступ', revokeDesc: name => `${name} потеряет доступ и перестанет распознаваться начиная со следующего сообщения.`, approvedUser: name => `${name} одобрен`, approvedHint: 'Они распознаются автоматически начиная с их следующего сообщения.', revokedUser: name => `${name} отозван`, failedApprove: name => `Не удалось одобрить ${name}`, failedRevoke: name => `Не удалось отозвать ${name}`, pairingLockedOut: 'Слишком много неудачных одобрений — эта платформа заблокирована. Попробуйте позже.', waitingSince: minutes => (minutes < 1 ? 'только что' : `${minutes}м назад`), fieldCopy: { TELEGRAM_BOT_TOKEN: { label: 'Токен бота', help: 'Создайте бота через @BotFather и вставьте выданный им токен.', placeholder: 'Вставьте токен бота Telegram' }, TELEGRAM_ALLOWED_USERS: { label: 'Разрешённые ID пользователей Telegram', help: 'Рекомендуется. Числовые ID через @userinfobot через запятую. Без этого писать вашему боту может кто угодно.' }, TELEGRAM_PROXY: { label: 'URL прокси', help: 'Нужен только в сетях, где Telegram заблокирован.' }, DISCORD_BOT_TOKEN: { label: 'Токен бота', help: 'Создайте приложение в Discord Developer Portal, добавьте бота и вставьте его токен.' }, DISCORD_ALLOWED_USERS: { label: 'Разрешённые ID пользователей Discord', help: 'Рекомендуется. ID пользователей Discord через запятую.' }, DISCORD_REPLY_TO_MODE: { label: 'Стиль ответов', help: 'first, all или off.' }, DISCORD_ALLOW_ALL_USERS: { label: 'Разрешить всех пользователей Discord', help: 'Только для разработки. Если true, писать боту в ЛС может кто угодно без allowlist.' }, DISCORD_HOME_CHANNEL: { label: 'ID домашнего канала', help: 'Канал, куда бот шлёт проактивные сообщения (результаты cron, напоминания).' }, DISCORD_HOME_CHANNEL_NAME: { label: 'Название домашнего канала', help: 'Отображаемое имя домашнего канала в журналах и выводе статуса.' }, BLUEBUBBLES_ALLOW_ALL_USERS: { label: 'Разрешить всех пользователей iMessage', help: 'Если true, allowlist BlueBubbles пропускается.' }, MATTERMOST_ALLOW_ALL_USERS: { label: 'Разрешить всех пользователей Mattermost' }, MATTERMOST_HOME_CHANNEL: { label: 'Домашний канал' }, QQ_ALLOW_ALL_USERS: { label: 'Разрешить всех пользователей QQ' }, QQBOT_HOME_CHANNEL: { label: 'Домашний канал QQ', help: 'Канал или группа по умолчанию для доставки cron.' }, QQBOT_HOME_CHANNEL_NAME: { label: 'Название домашнего канала QQ' }, SLACK_BOT_TOKEN: { label: 'Токен бота Slack', help: 'Используйте токен бота из OAuth & Permissions после установки вашего приложения Slack.', placeholder: 'Вставьте токен бота Slack' }, SLACK_APP_TOKEN: { label: 'Токен приложения Slack', help: 'Используйте токен уровня приложения, необходимый для Socket Mode.', placeholder: 'Вставьте токен приложения Slack' }, SLACK_ALLOWED_USERS: { label: 'Разрешённые ID пользователей Slack', help: 'Рекомендуется. ID пользователей Slack через запятую.' }, MATTERMOST_URL: { label: 'URL сервера', placeholder: 'https://mattermost.example.com' }, MATTERMOST_TOKEN: { label: 'Токен бота' }, MATTERMOST_ALLOWED_USERS: { label: 'Разрешённые ID пользователей', help: 'Рекомендуется. ID пользователей Mattermost через запятую.' }, MATRIX_HOMESERVER: { label: 'URL homeserver', placeholder: 'https://matrix.org' }, MATRIX_ACCESS_TOKEN: { label: 'Токен доступа' }, MATRIX_USER_ID: { label: 'ID пользователя бота', placeholder: '@hermes:example.org' }, MATRIX_ALLOWED_USERS: { label: 'Разрешённые ID пользователей Matrix', help: 'Рекомендуется. ID пользователей через запятую в формате @user:server.' }, SIGNAL_HTTP_URL: { label: 'URL моста Signal', placeholder: 'http://127.0.0.1:8080', help: 'URL работающего REST-моста signal-cli.' }, SIGNAL_ACCOUNT: { label: 'Номер телефона', help: 'Номер, зарегистрированный в вашем мосте signal-cli.' }, SIGNAL_ALLOWED_USERS: { label: 'Разрешённые пользователи Signal', help: 'Рекомендуется. Идентификаторы Signal через запятую.' }, WHATSAPP_ENABLED: { label: 'Включить мост WhatsApp', help: 'Устанавливается автоматически переключателем ниже. Не меняйте, если точно не нужно.' }, WHATSAPP_MODE: { label: 'Режим моста' }, WHATSAPP_ALLOWED_USERS: { label: 'Разрешённые пользователи WhatsApp', help: 'Рекомендуется. Номера телефонов или ID WhatsApp через запятую.' } }, platformIntro: {} }, webhooks: { search: 'Поиск вебхуков...', loading: 'Загрузка вебхуков...', loadFailed: 'Не удалось загрузить вебхуки', subscriptions: count => `Подписки (${count})`, hint: 'Изменения подписок применяются на лету, когда приёмник запущен. Отключённые подписки отклоняют входящие события.', empty: 'Подписок вебхуков пока нет.', disabledTitle: 'Приёмник вебхуков отключён', disabledBody: 'Вебхуки — это отдельная платформа шлюза. Включите их здесь, чтобы принимать входящие HTTP-события; чат-каналы нужны только когда подписка доставляет в Telegram, Discord, Slack или другой канал.', enable: 'Включить вебхуки', enabling: 'Включение...', enabled: name => `Включено: «${name}»`, disabled: name => `Отключено: «${name}»`, enableRow: 'Включить', disableRow: 'Отключить', delete: 'Удалить', deleting: 'Удаление...', deleted: 'Вебхук удалён', deleteTitle: 'Удалить вебхук', deleteDescPrefix: 'Это навсегда удалит ', deleteDescSuffix: '. Это действие необратимо.', deleteFailed: name => `Не удалось удалить «${name}»`, toggleFailed: (name, enabled) => `Не удалось ${enabled ? 'включить' : 'отключить'} «${name}»`, newSubscription: 'Новая подписка', restarting: 'Перезапуск шлюза...', restartNeeded: 'Вебхуки включены, но шлюз всё ещё нужно перезапустить, чтобы приёмник заработал.', restartGateway: 'Перезапустить шлюз', restartingGateway: 'Перезапуск...', restartFailed: detail => `Не удалось перезапустить шлюз${detail}`, enabledRestarting: 'Вебхуки включены; шлюз перезапускается...', all: '(все)', deliverOnly: 'только доставка', createdTitle: 'Подписка создана', createdSecretHint: 'Скопируйте секрет сейчас — он показывается только один раз.', webhookUrl: 'URL вебхука', secretOnce: 'Секрет (показывается один раз)', done: 'Готово', fieldName: 'Имя', fieldNamePlaceholder: 'например, github-push', fieldDescription: 'Описание', fieldDescriptionPlaceholder: 'Что делает этот вебхук (необязательно)', fieldEvents: 'События', fieldEventsPlaceholder: 'через запятую, пусто — все', fieldSkills: 'Навыки', fieldSkillsPlaceholder: 'имена навыков через запятую (необязательно)', fieldDeliver: 'Доставить в', fieldDeliverOnly: 'Доставлять только payload', fieldPrompt: 'Промпт', fieldPromptPlaceholder: 'Инструкции для агента при срабатывании этого вебхука (необязательно)', nameRequired: 'Имя обязательно', create: 'Создать', creating: 'Создание...', created: 'Создано', createFailed: detail => `Не удалось создать: ${detail}`, copy: 'Копировать', deliverOptions: { log: 'Журнал', telegram: 'Telegram', discord: 'Discord', slack: 'Slack', email: 'Email', github_comment: 'Комментарий GitHub' } }, profiles: { close: 'Закрыть профили', nameHint: 'Строчные буквы, цифры, дефисы и подчёркивания. Должно начинаться с буквы или цифры.', title: 'Профили', count: count => `${count} ${RU_PLURAL(count, 'профиль', 'профиля', 'профилей')}`, search: 'Поиск профилей...', loading: 'Загрузка профилей...', newProfile: 'Новый профиль', importProfile: 'Импортировать профиль…', exportProfile: 'Экспортировать профиль…', imported: 'Профиль импортирован', exported: 'Профиль экспортирован', failedImport: 'Не удалось импортировать профиль', failedExport: 'Не удалось экспортировать профиль', allProfiles: 'Все профили', showAllProfiles: 'Показать все профили', switchToProfile: name => `Переключиться на ${name}`, switchToConnection: name => `Переключиться на ${name}`, switchConnectionFailed: name => `Не удалось подключиться к ${name}`, manageProfiles: 'Управлять профилями…', connectGateway: 'Управлять шлюзами…', actions: 'Действия', color: 'Цвет…', colorFor: 'Цвет', setColor: color => `Установить цвет ${color}`, autoColor: 'Авто', noProfiles: 'Профилей пока нет.', selectPrompt: 'Выберите профиль, чтобы посмотреть его детали.', refresh: 'Обновить профили', refreshing: 'Обновление профилей', default: 'по умолчанию', skills: count => `${count} ${RU_PLURAL(count, 'навык', 'навыка', 'навыков')}`, env: 'env', defaultBadge: 'По умолчанию', rename: 'Переименовать', renameMenu: 'Переименовать…', editSoul: 'Изменить SOUL.md…', copySetup: 'Скопировать команду установки', copying: 'Копирование...', modelLabel: 'Модель', skillsLabel: 'Навыки', notSet: 'Не задано', soulDesc: 'Системный промпт и инструкции по персоне, встроенные в этот профиль.', soulOptional: 'необязательно', soulPlaceholder: mode => `Системный промпт / персона этого профиля.\nОставьте пустым, чтобы сохранить ${mode} по умолчанию.`, soulPlaceholderCloned: 'склонированный', soulPlaceholderEmpty: 'пустой', unsavedChanges: 'Несохранённые изменения', loadingSoul: 'Загрузка SOUL.md...', emptySoul: 'Пустой SOUL.md — начните писать персону...', saving: 'Сохранение...', saveSoul: 'Сохранить SOUL.md', deleteTitle: 'Удалить профиль?', deleteDescPrefix: 'Это удалит ', deleteDescMid: ' и сотрёт его ', deleteDescSuffix: ' каталог. Это действие необратимо.', deleting: 'Удаление...', createDesc: 'Профили — это независимые среды Hermes: отдельные настройки, навыки и SOUL.md.', nameLabel: 'Имя', cloneFrom: 'Клонировать из', cloneFromNone: 'Нет (пустой)', cloneFromDesc: 'Копирует настройки, навыки и SOUL.md из выбранного исходного профиля.', cloneFromDefault: 'Клонировать из профиля по умолчанию', cloneFromDefaultDesc: 'Скопируйте настройки, навыки и SOUL.md из вашего профиля по умолчанию.', invalidName: hint => `Некорректное имя. ${hint}`, nameRequired: 'Имя обязательно.', creating: 'Создание...', createAction: 'Создать профиль', renameTitle: 'Переименовать профиль', renameDescPrefix: 'Переименование обновляет каталог профиля и все wrapper-скрипты в ', renameDescSuffix: '.', displayNameTitle: 'Название этого агента', displayNameDesc: 'Устанавливает отображаемое имя, показываемое во всём приложении. Внутренний ID профиля остаётся «default».', displayNameLabel: 'Отображаемое имя', newNameLabel: 'Новое имя', renaming: 'Переименование...', created: 'Профиль создан', renamed: 'Профиль переименован', deleted: 'Профиль удалён', setupCopied: 'Команда установки скопирована', soulSaved: 'SOUL.md сохранён', failedLoad: 'Не удалось загрузить профили', failedDelete: 'Не удалось удалить профиль', failedCopy: 'Не удалось скопировать команду установки', failedLoadSoul: 'Не удалось загрузить SOUL.md', failedSaveSoul: 'Не удалось сохранить SOUL.md', failedCreate: 'Не удалось создать профиль', failedRename: 'Не удалось переименовать профиль' }, cron: { close: 'Закрыть cron', title: 'Запланированные задачи', count: count => `${count} ${RU_PLURAL(count, 'задача', 'задачи', 'задач')}`, modelImpact: { title: 'Запланированные задачи требуют проверки', message: count => `Будет пропущено ${count} ${RU_NOUN(count, 'задача', 'задачи', 'задач')} до тех пор, пока вы не проверите их настройки модели.`, detailMore: (names, remaining) => `${names} и ещё ${remaining}`, review: 'Проверить запланированные задачи', saveFailed: 'Hermes не сохранил это изменение модели.' }, search: 'Поиск cron-задач...', loading: 'Загрузка cron-задач...', states: { enabled: 'включено', scheduled: 'запланировано', running: 'выполняется', paused: 'приостановлено', disabled: 'отключено', error: 'ошибка', completed: 'завершено' }, deliveryLabels: { local: 'Это приложение', telegram: 'Telegram', discord: 'Discord', slack: 'Slack', email: 'Email' }, scheduleLabels: { daily: 'Ежедневно', weekdays: 'Будни', weekly: 'Еженедельно', monthly: 'Ежемесячно', hourly: 'Каждый час', 'every-15-minutes': 'Каждые 15 минут', custom: 'Свой' }, scheduleHints: { daily: 'Каждый день в 9:00', weekdays: 'С понедельника по пятницу в 9:00', weekly: 'Каждый понедельник в 9:00', monthly: 'В первый день каждого месяца в 9:00', hourly: 'В начале каждого часа', 'every-15-minutes': 'Каждые 15 минут', custom: 'Синтаксис cron или естественный язык' }, days: { '0': 'Воскресенье', '1': 'Понедельник', '2': 'Вторник', '3': 'Среда', '4': 'Четверг', '5': 'Пятница', '6': 'Суббота', '7': 'Воскресенье' }, dayFallback: value => `день ${value}`, everyDayAt: time => `Каждый день в ${time}`, weekdaysAt: time => `Будни в ${time}`, everyDayOfWeekAt: (day, time) => `Каждый ${day} в ${time}`, monthlyOnDayAt: (dayOfMonth, time) => `Ежемесячно ${dayOfMonth}-го числа в ${time}`, topOfHour: 'В начале каждого часа', everyHourAt: minute => `Каждый час на :${minute}`, newCron: 'Новый cron', emptyDescNew: 'Запланируйте промпт, который будет выполняться по cron-выражению. Hermes выполнит его и доставит результаты в выбранное вами место.', emptyDescSearch: 'Попробуйте более широкий запрос.', emptyTitleNew: 'Запланированных задач пока нет', emptyTitleSearch: 'Нет совпадений', last: 'Последний:', next: 'Следующий:', noRuns: 'Запусков пока не было', manage: 'Управлять', showRuns: 'Показать запуски', hideRuns: 'Скрыть запуски', runHistory: 'История запусков', actionsTitle: 'Действия с cron-задачей', resume: 'Продолжить cron', pause: 'Приостановить cron', resumeTitle: 'Продолжить', pauseTitle: 'Приостановить', triggerNow: 'Запустить сейчас', edit: 'Изменить cron', deleteTitle: 'Удалить cron-задачу?', deleteDescPrefix: 'Это навсегда удалит ', deleteDescSuffix: '. Она перестанет срабатывать сразу.', deleting: 'Удаление...', resumed: 'Cron продолжен', paused: 'Cron приостановлен', triggered: 'Cron запущен', deleted: 'Cron удалён', created: 'Cron создан', updated: 'Cron обновлён', failedLoad: 'Не удалось загрузить cron-задачи', failedUpdate: 'Не удалось обновить cron-задачу', failedTrigger: 'Не удалось запустить cron-задачу', failedDelete: 'Не удалось удалить cron-задачу', failedSave: 'Не удалось сохранить cron-задачу', editTitle: 'Изменить cron-задачу', createTitle: 'Новая cron-задача', editDesc: 'Обновите расписание, промпт или место доставки. Изменения вступят в силу при следующем запуске.', createDesc: 'Запланируйте промпт для автоматического выполнения. Используйте синтаксис cron или фразу вроде «каждые 15 минут».', nameLabel: 'Имя', namePlaceholder: 'Утренний брифинг', promptLabel: 'Промпт', promptPlaceholder: 'Суммируй мои непрочитанные треды Slack и пришли топ-5 на почту...', frequencyLabel: 'Частота', deliverLabel: 'Доставить в', deliverNeedsHomeChannel: 'сначала задайте домашний канал', modelLabel: 'Модель', modelDefault: 'По умолчанию (глобальная модель)', customScheduleLabel: 'Своё расписание', customPlaceholder: '0 9 * * * или будни в 9:00', customHint: 'Cron-выражение или фразы вроде «каждый час» или «будни в 9:00».', optional: 'Необязательно', promptRequired: 'Промпт обязателен.', promptScheduleRequired: 'Промпт и расписание обязательны.', scheduleRequired: 'Расписание обязательно.', scriptOnlyEditHint: 'Задача только со скриптом (без AI-промпта). ID задачи:', saveChanges: 'Сохранить изменения', createAction: 'Создать cron', tabs: { jobs: 'Задачи', blueprints: 'Шаблоны' }, blueprints: { tab: 'Шаблоны', startFrom: 'Начать с', custom: 'Свой', subtitle: 'Готовые автоматизации', dialogDesc: 'Заполните детали и запланируйте.', scheduleIt: 'Запланировать', scheduling: 'Планирование...', scheduled: 'Шаблон запланирован', loading: 'Загрузка шаблонов...', failedLoad: 'Не удалось загрузить шаблоны', emptyTitle: 'Шаблоны недоступны', emptyDesc: 'На этом бэкенде нет шаблонов автоматизации.' } }, artifacts: { search: 'Поиск артефактов...', refresh: 'Обновить артефакты', refreshing: 'Обновление артефактов', indexing: 'Индексация недавних артефактов сеансов', tabAll: 'Все', tabImages: 'Изображения', tabFiles: 'Файлы', tabLinks: 'Ссылки', noArtifactsTitle: 'Артефакты не найдены', noArtifactsDesc: 'Сгенерированные изображения и файловые результаты появятся здесь по мере их создания в сеансах.', failedLoad: 'Не удалось загрузить артефакты', openFailed: 'Не удалось открыть', itemsImage: 'изображения', itemsLink: 'ссылки', itemsFile: 'файлы', itemsGeneric: 'элементы', zero: '0', rangeOf: (start, end, total) => `${start}–${end} из ${total}`, goToPage: (itemLabel, page) => `Перейти на страницу ${page} ${itemLabel}`, colTitleLink: 'Название ссылки', colTitleFile: 'Имя', colTitleDefault: 'Название / имя', colLocationLink: 'URL', colLocationFile: 'Путь', colLocationDefault: 'Место', colSession: 'Сеанс', kindImage: 'изображение', kindFile: 'файл', kindLink: 'ссылка', chat: 'Чат', copyUrl: 'Копировать URL', copyPath: 'Копировать путь' }, artifactCard: { kind: { code: 'Код', html: 'Интерактивная страница', svg: 'Графика' }, generating: lines => `Генерация… ${lines} ${RU_NOUN(lines, 'строка', 'строки', 'строк')}`, versionBadge: count => `${count} ${RU_NOUN(count, 'версия', 'версии', 'версий')}`, open: 'Открыть' }, artifactPreview: { versionOf: (current, total) => `v${current} из ${total}`, olderVersion: 'Более старая версия', newerVersion: 'Более новая версия', latest: 'Последняя', copyContent: 'Копировать содержимое', download: 'Скачать', openInBrowser: 'Открыть в браузере', openInBrowserFailed: 'Не удалось открыть в браузере', missingTitle: 'Артефакт недоступен', missingBody: 'Этот артефакт больше нет в локальном реестре.' }, sidebar: { nav: { 'new-session': 'Новый сеанс', skills: 'Возможности', messaging: 'Сообщения', artifacts: 'Артефакты', cron: 'Запланированные задачи' }, searchAria: 'Поиск сеансов', searchPlaceholder: 'Поиск сеансов…', clearSearch: 'Очистить поиск', noMatch: query => `Нет сеансов по запросу «${query}».`, results: 'Результаты', pinned: 'Закреплённые', sessions: 'Сеансы', cronJobs: 'Cron-задачи', groupAriaGrouped: 'Показать сеансы одним списком', groupAriaUngrouped: 'Сгруппировать сеансы по рабочим пространствам', showProjects: 'Показать проекты', showSessions: 'Показать сеансы', groupTitleGrouped: 'Не группировать сеансы', groupTitleUngrouped: 'Группировать по рабочему пространству', allPinned: 'Здесь всё закреплено. Открепите чат, чтобы он появился в недавних.', shiftClickHint: 'Shift-клик по чату, чтобы закрепить', noWorkspace: 'Без рабочего пространства', projectEmpty: 'Сеансов пока нет', noSessions: 'Сеансов пока нет', noFilterMatches: 'Нет сеансов по этим фильтрам', projects: { sectionLabel: 'Проекты', home: 'Главная', newButton: 'Новый проект', createTitle: 'Новый проект', createDesc: 'Назовите рабочее пространство и добавьте одну или несколько папок.', renameTitle: 'Переименовать проект', addFolderTitle: 'Добавить папку', namePlaceholder: 'например, Skunkworks', foldersLabel: 'Папки', ideaLabel: 'Идея', ideaPlaceholder: 'О чём этот проект? (сохраняется в IDEA.md)', ideaGenerate: 'Сгенерировать идею', ideaGenerating: 'Генерация…', ideaShuffle: 'Перемешать шаблоны', noFolders: 'Папки ещё не добавлены.', addFolder: 'Добавить папку', primaryBadge: 'основная', removeFolder: 'Удалить', create: 'Создать', menu: 'Действия', menuRename: 'Переименовать', menuAppearance: 'Внешний вид', noColor: 'Без цвета', menuAddFolder: 'Добавить папку', menuSetActive: 'Сделать активным', menuDelete: 'Удалить', moveToProject: 'Переместить в проект', movedTo: name => `Перемещено в ${name}`, moveFailed: 'Не удалось переместить сеанс', moveNoFolder: 'У этого проекта нет папки для перемещения', moveNoProjects: 'Нет других проектов', reveal: 'Показать в папке', copyPath: 'Копировать путь', removeFromSidebar: 'Скрыть из боковой панели', createFailed: 'Не удалось создать проект', staleBackend: 'Обновите бэкенд Hermes, чтобы создавать проекты — ваш бэкенд старше этого desktop-приложения (Настройки → Обновления → Бэкенд).', deleteConfirm: 'Это удалит сохранённый проект из Hermes. Файлы, git-репозитории и worktrees не пострадают.', startWork: 'Новый worktree', newWorktreeTitle: 'Новый worktree', newWorktreeDesc: 'Назовите ветку для этого worktree.', branchPlaceholder: 'например, my-feature', branchOff: () => ({ after: '', before: 'от ветки ' }), baseBranchPlaceholder: 'Поиск веток…', baseBranchNone: 'Ветки не найдены', startWorkFailed: 'Не удалось создать worktree', worktreeStaleBackend: 'Обновите бэкенд Hermes, чтобы создавать worktrees по этому удалённому соединению — он старше git worktree API.', worktreeProjectLabel: 'Проект', worktreeProjectPlaceholder: 'Поиск проектов…', worktreeProjectNone: 'Нет проектов с папкой', convertBranch: 'Преобразовать ветку…', convertBranchTitle: 'Преобразовать ветку', convertBranchDesc: 'Откройте закоммиченные ветки или создайте worktree для свободной ветки.', convertBranchPlaceholder: 'Поиск веток…', convertBranchInstead: 'Преобразовать существующую ветку', branchOpenExisting: 'открыть', branchSwitchHome: 'сменить home', branchCreateWorktree: 'новый worktree', branchTrackRemote: 'отслеживать удалённую', branchesLoading: 'Загрузка веток…', noBranches: 'Ветки не найдены', removeWorktree: 'Удалить worktree', removeWorktreeFailed: 'Не удалось удалить worktree (есть незакоммиченные изменения?)', removeWorktreeConfirm: 'Удалить из git (сотрёт каталог worktree; ветка останется) или просто скрыть лану из боковой панели, оставив worktree на диске.', removeWorktreeDirty: 'В этом worktree есть незакоммиченные изменения. Удалить принудительно (сбросит эти изменения) или просто скрыть лану и оставить на диске.', forceRemove: 'Удалить принудительно', enter: label => `Открыть ${label}`, reorder: label => `Изменить порядок ${label}`, toggle: (label, open) => `${open ? 'Показать' : 'Скрыть'} сеансы ${label}`, back: 'Все проекты' }, newSessionIn: label => `Новый сеанс в ${label}`, showMoreIn: (count, label) => `Показать ещё ${count} в ${label}`, loading: 'Загрузка…', loadMore: 'Загрузить ещё', loadCount: step => `Загрузить ещё ${step}`, messageCount: count => `${count} ${RU_PLURAL(count, 'сообщение', 'сообщения', 'сообщений')}`, toolCallCount: count => `${count} ${RU_PLURAL(count, 'вызов инструмента', 'вызова инструмента', 'вызовов инструмента')}`, row: { pin: 'Закрепить', unpin: 'Открепить', markUnread: 'Отметить как непрочитанное', markRead: 'Отметить как прочитанное', unreadFailed: 'Не удалось обновить состояние непрочитанных', copyId: 'Копировать ID', export: 'Экспорт', branchFrom: 'Ветка', rename: 'Переименовать', archive: 'В архив', newWindow: 'Новое окно', openInTerminal: 'Открыть в терминале', hideTabBar: 'Скрыть панель вкладок', openInNewTab: 'Открыть в новой вкладке', openInSplit: 'Открыть в сплит-виде', copyIdFailed: 'Не удалось скопировать ID сеанса', sessionActions: 'Действия с сеансом', sessionRunning: 'Сеанс выполняется', needsInput: 'Нужен ваш ввод', waitingForAnswer: 'Ждёт вашего ответа', finishedUnread: 'Завершён — не прочитан', backgroundRunning: 'Фоновая задача выполняется', draftSession: 'Черновик — ещё ничего не отправлено', handoffOrigin: platform => `Передано из ${platform}`, ownedByProfile: profile => `Профиль: ${profile}`, renamed: 'Переименовано', renameFailed: 'Переименование не удалось', renameTitle: 'Переименовать сеанс', renameDesc: 'Оставьте пустым, чтобы очистить.', untitledPlaceholder: 'Сеанс без названия', deleteTitle: 'Удалить сеанс?', deleteDesc: title => `Это навсегда удалит «${title}». Это действие необратимо.`, deleting: 'Удаление…', deleted: 'Сеанс удалён', untitledChat: id => `Чат ${id}`, messageCount: count => `${count} ${RU_PLURAL(count, 'сообщение', 'сообщения', 'сообщений')}`, todoProgress: 'Задачи выполнены', ageNow: 'сейчас', ageDay: 'д', ageHour: 'ч', ageMin: 'м' }, dateDivider: { today: 'Ранее сегодня', yesterday: 'Вчера', thisWeek: 'Ранее на этой неделе', lastWeek: 'На прошлой неделе', thisMonth: 'Ранее в этом месяце' }, statusDivider: { working: 'Работает', done: 'Готово' }, markAllRead: 'Отметить все как прочитанные' }, composer: { message: 'Сообщение', wakingProfile: profile => `Пробуждаем ${profile}…`, placeholderStarting: 'Запуск Hermes...', placeholderReconnecting: 'Переподключение к Hermes…', placeholderFollowUp: 'Отправить продолжение', newSessionPlaceholders: [ 'Что будем делать?', 'Дайте Hermes задачу', 'О чём вы думаете?', 'Опишите, что нужно', 'Что обсудим?', 'Спросите о чём угодно', 'Начните с цели' ], followUpPlaceholders: [ 'Отправьте продолжение', 'Добавьте контекст', 'Уточните запрос', 'Что дальше?', 'Продолжаем', 'Запустите дальше', 'Скорректируйте или продолжите' ], startVoice: 'Начать голосовой разговор', openDirective: 'Открыть', queueMessage: 'Вставить сообщение в очередь', steer: 'Направить текущий запуск', stop: 'Стоп', send: 'Отправить', speaking: 'Говорит', transcribing: 'Расшифровка', thinking: 'Думает', muted: 'Приглушено', listening: 'Слушает', muteMic: 'Выключить микрофон', unmuteMic: 'Включить микрофон', stopListening: 'Перестать слушать и отправить', stopShort: 'Стоп', endConversation: 'Завершить голосовой разговор', endShort: 'Завершить', stopDictation: 'Остановить диктовку', transcribingDictation: 'Расшифровка диктовки', voiceControls: 'Голос', voiceDictation: 'Голосовая диктовка', speakReplies: 'Зачитывать ответы вслух', stopSpeakingReplies: 'Перестать зачитывать ответы вслух', wakeWordListening: phrase => `Слово-пробуждение: «${phrase}» — слушает`, wakeWordOff: phrase => `Слово-пробуждение: «${phrase}» — выключено`, wakeWordPausedVoice: phrase => `Слово-пробуждение: «${phrase}» — приостановлено во время голосового чата`, lookupLoading: 'Ищем…', lookupNoMatches: 'Нет совпадений.', lookupTry: 'Попробуйте', lookupOr: 'или', commonCommands: 'Частые команды', hotkeys: 'Горячие клавиши', helpFooter: 'открывает полную панель · backspace закрывает', commandDescs: { '/help': 'полный список команд + горячих клавиш', '/clear': 'начать новый сеанс', '/resume': 'возобновить прошлый сеанс', '/details': 'уровень детализации транскрипта', '/copy': 'скопировать выделенное или последнее сообщение ассистента', '/quit': 'выйти из hermes' }, hotkeyDescs: { 'composer.mention': 'ссылки на файлы, папки, URL, git', 'composer.slash': 'палитра слэш-команд', 'composer.help': 'эта быстрая справка (удалите, чтобы закрыть)', 'composer.sendNewline': 'отправить · Shift+Enter — новая строка', 'composer.sendQueued': 'отправить следующий ход в очереди', 'keybinds.openPanel': 'все горячие клавиши', 'composer.cancel': 'закрыть поповер · отменить запуск', 'composer.history': 'переключать поповер / историю' }, attachUrlTitle: 'Прикрепить URL', attachUrlDesc: 'Hermes загрузит страницу и добавит её как контекст для этого хода.', urlPlaceholder: 'https://example.com/post', urlHintPre: 'Укажите полный URL, например ', attach: 'Прикрепить', queued: count => `${count} в очереди`, queuedPaused: count => `${count} в очереди — пауза`, attachmentOnly: 'Ход только с вложениями', emptyTurn: 'Пустой ход', attachments: count => `${count} ${RU_NOUN(count, 'вложение', 'вложения', 'вложений')}`, editingInComposer: 'Редактирование в композере', editingQueuedInComposer: 'Редактирование хода в очереди в композере', queueEdit: 'Изменить', queueSendNext: 'Дальше', queueSteer: 'Направить — изменить текущий ход сейчас', queueSend: 'Отправить', queueDelete: 'Удалить', queueResume: 'Продолжить', queueResumeTip: 'Приостановлено стопом — продолжить отправку ходов из очереди', queueStuckTitle: 'Сообщение из очереди не отправлено', queueStuckBody: 'Ход из очереди несколько раз не удалось отправить. Он всё ещё в очереди — попробуйте отправить снова.', previewUnavailable: 'Предпросмотр недоступен', previewLabel: label => `Предпросмотр ${label}`, couldNotPreview: label => `Не удалось предпросмотреть ${label}`, removeAttachment: label => `Удалить ${label}`, dictating: 'Диктовка', preparingAudio: 'Подготовка аудио', speakingResponse: 'Зачитывает ответ', readingAloud: 'Читает вслух', themeSuggestions: 'Предложения тем desktop', noMatchingThemes: 'Нет совпадающих тем.', themeTryPre: 'Попробуйте ', themeTryPost: '.', attachLabel: 'Прикрепить', files: 'Файлы…', folder: 'Папка…', images: 'Изображения…', pasteImage: 'Вставить изображение', url: 'URL…', promptSnippets: 'Фрагменты промптов…', tipPre: 'Подсказка: введите ', tipPost: ' чтобы ссылаться на файлы inline.', snippetsTitle: 'Фрагменты промптов', snippetsDesc: 'Выберите стартовый промпт, чтобы вставить в композер.', dropFiles: 'Перетащите файлы, чтобы прикрепить', dropSession: 'Перетащите, чтобы связать этот чат', mcpSuggestions: { label: server => `Добавить ${server}`, tip: keyword => `Предложено, потому что вы упомянули «${keyword}» — нажмите, чтобы подключить`, connecting: server => `Подключаем ${server}…`, cancelTip: 'Нажмите, чтобы отменить', added: server => `Добавлен ${server}`, addedTip: 'Подключено — его инструменты готовы в этом чате', connectFailed: server => `Не удалось подключить ${server}` }, skillSuggestions: { label: skill => `Использовать навык: ${skill}`, tip: skill => `Вы упомянули «${skill}» — нажмите, чтобы начать с этого навыка`, done: skill => `Добавлено /${skill}`, doneTip: 'Навык загрузится при отправке' }, githubSuggestions: { label: 'Настроить GitHub', tip: 'GitHub работает через навыки gh CLI здесь — нажмите, чтобы подключить аккаунт', done: 'Добавлено /github-auth', doneTip: 'Отправьте сообщение, и агент проведёт вас через вход в GitHub' }, repairSuggestions: { label: server => `Переподключить ${server}`, tip: server => `Недавний вызов ${server} завершился ошибкой соединения`, working: server => `Переподключаем ${server}…`, workingTip: 'Нажмите, чтобы отменить', done: server => `Переподключено ${server}`, doneTip: 'Свежие учётные данные активны в этом чате', failed: server => `Не удалось переподключить ${server}` }, cronSuggestions: { label: 'Запланировать это', tip: phrase => `«${phrase}» звучит как повторяющееся — запланируйте выполнение по расписанию`, prefix: 'Настроить это как запланированную задачу:', done: 'Отмечено для планирования', doneTip: 'Отправьте, и агент создаст задачу' }, snippets: { codeReview: { label: 'Рецензия кода', description: 'Аудит текущих изменений на предмет регрессий, упущенных граничных случаев и недостающих тестов.', text: 'Пожалуйста, проверьте это на баги, регрессии и недостающие тесты.' }, implementationPlan: { label: 'План реализации', description: 'Опишите подход перед правкой кода, чтобы diff остался сфокусированным.', text: 'Пожалуйста, составьте краткий план реализации перед изменением кода.' }, explainThis: { label: 'Объяснить это', description: 'Разберите, как работает выделенный код, и дайте ссылки на ключевые файлы.', text: 'Пожалуйста, объясните, как это работает, и укажите ключевые файлы.' } } }, statusStack: { agents: 'Агенты', background: count => `${count} ${RU_NOUN(count, 'фоновая задача', 'фоновые задачи', 'фоновых задач')}`, goalActive: 'Цель активна', goalDone: 'Цель выполнена', goalPaused: 'Цель на паузе', goalWaiting: 'Цель ожидает', subagents: count => `${count} ${RU_PLURAL(count, 'субагент', 'субагента', 'субагентов')}`, todos: (done, total) => `Задачи ${done}/${total}`, running: 'Выполняется', stop: 'Стоп', dismiss: 'Скрыть', exit: code => `exit ${code}`, coding: { title: 'Рабочее дерево', noBranch: 'Без ветки', detached: 'отсоединена', clean: 'Чисто', changed: count => `${count} изменено`, ahead: count => `${count} впереди`, behind: count => `${count} позади`, review: 'Проверить', close: 'Закрыть', openChanges: 'Открыть изменения', openFile: 'Открыть файл', stage: 'Добавить в индекс', unstage: 'Убрать из индекса', stageAll: 'Добавить всё в индекс', viewAsTree: 'Вид деревом', viewAsList: 'Вид списком', revert: 'Отменить', revertAll: 'Отменить всё', revertConfirm: 'Сбросить изменения в этом файле и вернуть его в закоммиченное состояние? Это действие необратимо.', revertAllConfirm: 'Сбросить все изменения и вернуть файлы в закоммиченное состояние? Это действие необратимо.', staged: 'В индексе', noChanges: 'Изменений нет', notRepo: 'Не git-репозиторий', noDiff: 'Нет diff для показа', scopeUncommitted: 'Незакоммиченные', scopeBranch: 'Ветка', scopeLastTurn: 'Последний ход', commit: 'Коммит', commitAndPush: 'Коммит и Push', commitPlaceholder: shortcut => `Сообщение (${shortcut} — коммит)`, generateCommitMessage: 'Сгенерировать сообщение коммита', stopGenerating: 'Остановить генерацию', createPr: 'Создать PR', openPr: 'Открыть PR', ghMissing: 'Установите GitHub CLI (gh) и войдите, чтобы открывать PR', agentShip: 'Попросить Hermes открыть PR', agentShipUnavailable: 'Чат, которому принадлежат эти изменения, не на экране.', agentShipPrompt: 'Проверьте текущие изменения, закоммитьте их с ясным conventional-commit сообщением, запушьте ветку и создайте pull request.', newBranch: 'Новая ветка', branchOffFrom: base => `Новая ветка от ${base}`, switchTo: branch => `Переключиться на ${branch}`, switchFailed: branch => `Не удалось переключиться на ${branch}`, worktrees: 'Worktrees' } }, updates: { stages: { idle: 'Готовимся…', prepare: 'Готовимся…', fetch: 'Скачиваем…', pull: 'Почти готово…', pydeps: 'Завершаем…', update: 'Обновляем Hermes…', rebuild: 'Пересобираем desktop-приложение…', restart: 'Перезапускаем Hermes…', done: 'Обновление завершено', manual: 'Обновление из терминала', guiSkew: 'Обновите desktop-приложение', error: 'Обновление приостановлено' }, checking: 'Ищем обновления…', checkFailedTitle: 'Не удалось проверить обновления', tryAgain: 'Попробовать снова', notAvailableTitle: 'Обновление недоступно', unsupportedMessage: 'Эта версия Hermes не может обновлять себя из приложения.', connectionRetry: 'Проверьте соединение и попробуйте снова.', latestBody: 'У вас последняя версия.', latestBodyBackend: 'Бэкенд работает на последней версии.', allSetTitle: 'Всё готово', availableTitle: 'Доступно новое обновление', availableBody: 'Новая версия Hermes готова к установке.', availableTitleBackend: 'Доступно обновление бэкенда', availableBodyBackend: 'Новая версия подключённого бэкенда Hermes готова к установке.', availableBodyNoChangelog: 'Новая версия готова. Заметки о выпуске недоступны для этого типа установки.', updateNow: 'Обновить сейчас', maybeLater: 'Возможно позже', moreChanges: count => `+ ещё ${count} ${RU_NOUN(count, 'изменение', 'изменения', 'изменений')} включено.`, manualTitle: 'Обновление из терминала', manualBody: 'Hermes установлен из командной строки, поэтому обновления тоже выполняются там. Вставьте это в терминал:', manualPickedUp: 'Hermes подхватит новую версию при следующем запуске.', guiSkewTitle: 'Обновите desktop-приложение', guiSkewBody: 'Бэкенд обновлён, но пакет этого desktop-приложения не изменился. Обновите или переустановите desktop-приложение Hermes (ваш AppImage / .deb / .rpm), чтобы версии совпали.', copy: 'Копировать', copied: 'Скопировано', done: 'Готово', applyingBody: 'Обновлятор Hermes возьмёт процесс на себя в своём окне и автоматически перезапустит Hermes, когда закончит. Пожалуйста, не открывайте Hermes вручную во время обновления.', applyingBodyBackend: 'Удалённый бэкенд применяет обновление и перезапустится. Hermes переподключится автоматически, когда он снова заработает.', applyingClose: 'Это окно закроется во время обновления, затем Hermes откроется сам.', errorTitle: 'Обновление не завершилось', errorBody: 'Не переживайте — ничего не потеряно. Можно попробовать снова прямо сейчас.', blockerTitle: 'Закрыть локальные предпросмотры, чтобы обновить Hermes?', blockerBody: 'Hermes нужно остановить эти локальные предпросмотры перед обновлением. Ваши файлы не будут изменены или удалены.', foreignBlockerTitle: 'Закрыть другие процессы, чтобы обновить Hermes', foreignBlockerBody: 'Hermes не может безопасно закрыть эти процессы автоматически. Закройте приложение, терминал или службу, которой принадлежит каждый из них, и повторите обновление.', mixedBlockerBody: 'Hermes может закрыть локальные предпросмотры, перечисленные ниже. Остальные процессы нужно закрыть вручную, прежде чем обновление сможет продолжиться.', closePreviewsAndUpdate: 'Закрыть предпросмотры и обновить', closePreviewsAndCheckAgain: 'Закрыть предпросмотры и проверить снова', localPreview: 'Локальный предпросмотр', portLabel: port => `Порт ${port}`, pidLabel: pid => `PID ${pid}`, technicalDetails: 'Технические детали', notNow: 'Не сейчас', clientAlsoBehindTitle: 'Desktop-приложение отстает', clientAlsoBehindMessage: 'Бэкенд в актуальном состоянии, но это desktop-приложение ещё на старой версии. Обновите его, чтобы получить последние исправления.', clientAlsoBehindAction: 'Обновить desktop-приложение', everythingDispatched: 'Обновление запущено', everythingSkipped: 'Пропущено', everythingRowFailed: 'Обновление не удалось', everythingFanoutFailedTitle: 'Не удалось обновить другие инстанции', applyStatus: { preparing: 'Обновляем бэкенд…', pulling: 'Бэкенд обновляется…', restarting: 'Бэкенд перезапускается для загрузки обновления…', notAvailable: 'Обновление недоступно для этого бэкенда.', failed: 'Не удалось обновить бэкенд.', noReturn: 'Бэкенд не вернулся в сеть. Обновление могло не завершиться — проверьте хост бэкенда.' } }, install: { stageStates: { pending: 'Ожидает', running: 'Установка', succeeded: 'Готово', skipped: 'Пропущено', failed: 'Ошибка' }, oneTimeTitle: 'Hermes требует одноразовой установки', unsupportedDesc: platform => `Автоматическая установка при первом запуске пока недоступна на ${platform}. Откройте Терминал и выполните команду ниже, затем перезапустите это приложение. При следующих запусках этот шаг будет пропущен.`, installCommand: 'Команда установки', copyCommand: 'Копировать команду', viewDocs: 'Открыть документацию по установке', installTo: 'Будет установлено в', retryAfterRun: 'Я выполнил — попробовать снова', setupChoiceTitle: 'Настройка Hermes Desktop', setupChoiceDesc: 'Подключите это приложение к уже работающему шлюзу Hermes или установите Hermes локально на этот компьютер.', connectExistingTitle: 'Подключиться к существующему Hermes', connectExistingShort: 'Подключить существующий', connectExistingDesc: 'Используйте удалённый бэкенд с сессионным токеном или входом через браузер. Локальная установка не начнётся.', installLocalTitle: 'Установить Hermes локально', installLocalDesc: 'Скачайте Hermes, создайте его Python-окружение и запустите бэкенд на этом компьютере.', localStartUnavailable: 'Не удалось начать локальную установку. Перезапустите Hermes Desktop и попробуйте снова.', remoteSetupTitle: 'Подключиться к существующему Hermes', remoteSetupDesc: 'Введите URL вашего шлюза. Hermes Desktop определит, нужен токен или вход через браузер.', remoteUrlTitle: 'URL шлюза', remoteUrlDesc: 'Используйте базовый URL шлюза Hermes, включая https:// для удалённых.', remoteUrlPlaceholder: 'https://gateway.example.com/hermes', probing: 'Определяем аутентификацию шлюза...', probeError: 'Не удалось подключиться к этому шлюзу Hermes.', identityProvider: 'ваш провайдер аутентификации', authTitle: 'Аутентификация', authNeedsOauth: provider => `Сначала войдите через ${provider}, чтобы проверить этот шлюз.`, authSignedIn: 'Вход через браузер завершён.', connected: 'Подключено', signIn: 'Войти', signInWith: provider => `Войти через ${provider}`, enterUrlFirst: 'Сначала введите URL шлюза.', signInIncomplete: 'Окно входа закрылось до завершения аутентификации.', tokenTitle: 'Сессионный токен', tokenDesc: 'Вставьте сессионный токен из файла .env удалённого шлюза.', pasteSessionToken: 'Вставьте сессионный токен', incompleteSignInTest: 'Войдите, чтобы проверить этот шлюз с OAuth-защитой.', incompleteTokenTest: 'Введите сессионный токен, чтобы проверить этот шлюз.', testConnection: 'Проверить соединение', testSucceeded: (baseUrl, version) => `Подключено к ${baseUrl}${version ? ` (${version})` : ''}.`, applyRemote: 'Применить и переподключиться', backToSetup: 'Назад', failedTitle: 'Установка не удалась', settingUpTitle: 'Настройка Hermes Agent', finishingTitle: 'Завершаем', failedDesc: 'Один из шагов установки завершился ошибкой. На Windows это может произойти, если запущена другая инстанция Hermes CLI или desktop. Остановите все работающие инстанции Hermes и повторите. Подробности — ниже или в журнале desktop.', activeDesc: 'Это одноразовая настройка. Установщик Hermes скачивает зависимости и настраивает вашу машину. При следующих запусках этот шаг будет пропущен.', progress: (completed, total) => `Выполнено ${completed} из ${total} шагов`, currentStage: stage => ` — сейчас: ${stage}`, fetchingManifest: 'Загружаем манифест установщика...', error: 'Ошибка', hideOutput: 'Скрыть вывод установщика', showOutput: 'Показать вывод установщика', lines: count => `${count} ${RU_PLURAL(count, 'строка', 'строки', 'строк')}`, noOutput: 'Вывода пока нет.', cancelling: 'Отмена...', cancelInstall: 'Отменить установку', transcriptSaved: 'Полный транскрипт сохранён в', copiedOutput: 'Скопировано!', copyOutput: 'Копировать вывод', reloadRetry: 'Перезагрузить и повторить' }, onboarding: { headerTitle: 'Настроим для вас Hermes Agent', headerDesc: 'Подключите провайдера модели, чтобы начать общение. Большинство вариантов — в один клик.', preparingInstall: 'Hermes завершает установку. Обычно это занимает меньше минуты при первом запуске.', starting: 'Запускаем Hermes…', lookingUpProviders: 'Ищем провайдеров...', collapse: 'Свернуть', otherProviders: 'Другие провайдеры', haveApiKey: 'У меня есть API-ключ', chooseLater: 'Выберу провайдера позже', recommended: 'Рекомендуется', connected: 'Подключено', featuredPitch: 'Одна подписка, 300+ передовых моделей — рекомендуемый способ запускать Hermes', fireworksPitch: 'Прямой API моделей — передовые модели на хостинге Fireworks', openRouterPitch: 'Один ключ, сотни моделей — надёжный вариант по умолчанию', apiKeyOptions: { fireworks: { short: 'прямой API моделей', description: 'Прямой доступ к моделям на хостинге Fireworks AI.' }, openrouter: { short: 'один ключ, много моделей', description: 'Сотни моделей за одним ключом. Хороший вариант по умолчанию для новых установок.' }, openai: { short: 'модели класса GPT', description: 'Прямой доступ к моделям OpenAI.' }, gemini: { short: 'модели Gemini', description: 'Прямой доступ к моделям Google Gemini.' }, xai: { short: 'модели Grok', description: 'Прямой доступ к моделям xAI Grok.' }, local: { short: 'self-hosted', description: 'Укажите Hermes локальный или self-hosted OpenAI-совместимый endpoint (vLLM, llama.cpp, Ollama и т.д.).' } }, backToSignIn: 'Назад ко входу', getKey: 'Получить ключ', replaceCurrent: 'Заменить текущее значение', pasteApiKey: 'Вставьте API-ключ', localApiKeyPlaceholder: 'API-ключ (необязательно — только если ваш endpoint его требует)', couldNotSave: 'Не удалось сохранить учётные данные.', connecting: 'Подключение', update: 'Обновить', flowSubtitles: { pkce: 'Откроет браузер для входа, затем продолжит здесь', device_code: 'Откроет страницу подтверждения в браузере — Hermes подключится автоматически', external: 'Войдите один раз в терминале, затем вернитесь в чат' }, startingSignIn: provider => `Начинаем вход для ${provider}...`, verifyingCode: provider => `Проверяем ваш код через ${provider}...`, connectedProvider: provider => `${provider} подключён`, connectedPicking: provider => `${provider} подключён. Выбираем модель по умолчанию...`, signInFailed: 'Вход не удался. Попробуйте снова.', pickDifferentProvider: 'Выбрать другого провайдера', signInWith: provider => `Войти через ${provider}`, openedBrowser: provider => `Мы открыли ${provider} в вашем браузере.`, authorizeThere: 'Авторизуйте Hermes там.', copyAuthCode: 'Скопируйте код авторизации и вставьте его ниже.', pasteAuthCode: 'Вставьте код авторизации', reopenAuthPage: 'Открыть страницу авторизации снова', autoBrowser: provider => `Мы открыли ${provider} в вашем браузере. Авторизуйте Hermes там, и подключение произойдёт автоматически — ничего копировать и вставлять не нужно.`, reopenSignInPage: 'Открыть страницу входа снова', waitingAuthorize: 'Ждём вашей авторизации...', externalPending: provider => `${provider} входит через собственный CLI. Выполните эту команду в терминале, затем вернитесь и выберите «Я вошёл»:`, signedIn: 'Я вошёл', deviceCodeOpened: provider => `Мы открыли ${provider} в вашем браузере. Введите там этот код:`, reopenVerification: 'Открыть страницу подтверждения снова', copy: 'Копировать', defaultModel: 'Модель по умолчанию', freeTier: 'Бесплатный тариф', pro: 'Pro', free: 'Free', price: (input, output) => `${input} вход / ${output} выход за Mtok`, change: 'Изменить', startChatting: 'Начать', docs: provider => `Документация ${provider}` }, modelPicker: { title: 'Сменить модель', current: 'текущая:', unknown: '(неизвестно)', search: 'Фильтр провайдеров и моделей...', noModels: 'Модели не найдены.', addProvider: 'Добавить провайдера', loadFailed: 'Не удалось загрузить модели', noAuthenticatedProviders: 'Нет провайдеров с аутентификацией.', pro: 'Pro', proNeedsSubscription: 'Модели Pro требуют платной подписки Nous.', free: 'Free', freeTier: 'Бесплатный тариф', priceTitle: 'Цена вход / выход за миллион токенов', wasPrice: 'было' }, modelVisibility: { title: 'Модели', search: 'Поиск моделей', noAuthenticatedProviders: 'Нет провайдеров с аутентификацией.', addProvider: 'Добавить провайдера…' }, shell: { windowControls: 'Управление окном', paneControls: 'Управление панелями', appControls: 'Управление приложением', modelMenu: { search: 'Поиск моделей', noModels: 'Модели не найдены', editModels: 'Изменить модели…', refreshModels: 'Обновить модели', fast: 'Быстрая' }, modelOptions: { comboDetails: 'Сведения о модели / комбинации', noOptions: 'Для этой модели нет опций', options: 'Опции', thinking: 'Размышление', fast: 'Быстрая', effort: 'Усилия', minimal: 'Минимально', low: 'Низкое', medium: 'Среднее', high: 'Высокое', xhigh: 'Очень высокое', max: 'Максимум', ultra: 'Ультра', updateFailed: 'Не удалось обновить опцию модели', fastFailed: 'Не удалось обновить быстрый режим' }, gatewayMenu: { gateway: 'Шлюз', connected: 'Подключён', connecting: 'Подключение', offline: 'Недоступен', inferenceReady: 'Инференс готов', inferenceNotReady: 'Инференс не готов', checkingInference: 'Проверка инференса', disconnected: 'Отключён', reconnectGateway: 'Переподключить шлюз', openSystem: 'Открыть системную панель', connection: label => `Соединение: ${label}`, recentActivity: 'Недавняя активность', viewAllLogs: 'Все журналы →', messagingPlatforms: 'Платформы сообщений' }, approvalMode: { title: 'Режим подтверждения', ariaLabel: mode => `Режим подтверждения: ${mode}`, manual: 'Ручной', manualDescription: 'Спрашивать перед действиями, требующими подтверждения', smart: 'Умный', smartDescription: 'Автоматически оценивать действия и спрашивать при необходимости', off: 'Выкл', offDescription: 'Выполнять без запросов подтверждения' }, statusbar: { unknown: 'неизвестно', restart: 'перезапуск', update: 'обновление', updateInProgress: 'Обновление выполняется', commitsBehind: (count, branch) => `${count} ${RU_NOUN(count, 'коммит', 'коммита', 'коммитов')} позади ${branch}`, desktopVersion: version => `Hermes Desktop v${version}`, backendVersion: version => `Бэкенд v${version}`, clientLabel: version => `клиент v${version}`, connectionSsh: host => `SSH: ${host}`, connectionRemote: host => `Удалённый: ${host}`, connectionCloud: host => `Облако: ${host}`, connectionCloudTooltip: host => `Hermes Cloud · ${host}`, connectionSshTooltip: host => `SSH · ${host}`, connectionRemoteTooltip: host => `Удалённый · ${host}`, backendLabel: version => `бэкенд v${version}`, commit: sha => `коммит ${sha}`, branch: branch => `ветка ${branch}`, closeCommandCenter: 'Закрыть командный центр', openCommandCenter: 'Открыть командный центр', showTerminal: 'Показать терминал', hideTerminal: 'Скрыть терминал', gateway: 'Шлюз', gatewayReady: 'готов', gatewayNeedsSetup: 'нужна настройка', gatewayChecking: 'проверка', gatewayConnecting: 'подключение', gatewayOffline: 'недоступен', gatewayRestarting: 'перезапуск…', gatewayTitle: 'Шлюз', customizeTitle: 'Показывать в статус-баре', hideStatusbar: 'Скрыть статус-бар', resetStatusbar: 'Сбросить к значениям по умолчанию', toggleApprovalMode: 'Подтверждения', toggleBackendVersion: 'Версия бэкенда', toggleCacheHitRate: 'Попадания в кэш', toggleCommandCenter: 'Командный центр', toggleContextUsage: 'Шкала контекста', toggleRunningTimer: 'Таймер хода', toggleSessionTimer: 'Таймер сеанса', toggleTerminal: 'Терминал', toggleTokensPerSecond: 'Токенов в секунду', toggleVersion: 'Версия и обновления', toggleWorkspace: 'Рабочее пространство', cacheHitRateTitle: 'Доля попаданий в кэш промпта за сеанс — кэшированные токены дешевле, чем выше, тем дешевле', tokensPerSecondTitle: 'Выходных токенов в секунду, среднее за последние 10 вызовов модели', agents: 'Агенты', closeAgents: 'Закрыть агентов', openAgents: 'Открыть агентов', subagents: count => `${count} ${RU_PLURAL(count, 'субагент', 'субагента', 'субагентов')}`, failed: count => `${count} ${RU_NOUN(count, 'сбой', 'сбоя', 'сбоев')}`, running: count => `${count} ${RU_NOUN(count, 'выполняется', 'выполняются', 'выполняется')}`, cron: 'Cron', openCron: 'Открыть cron-задачи', webhooks: 'Вебхуки', openWebhooks: 'Открыть вебхуки', starmap: 'Граф памяти', openStarmap: 'Открыть граф памяти', turnRunning: 'Выполняется', contextUsage: 'Использование контекста', contextUsagePanel: { categories: { conversation: 'Диалог', mcp: 'MCP', memory: 'Память', rules: 'Правила', skills: 'Навыки', subagent_definitions: 'Определения субагентов', system_prompt: 'Системный промпт', tool_definitions: 'Определения инструментов' }, empty: 'Данных контекста пока нет', loading: 'Загрузка разбивки…', percentFull: percent => `${percent}% занято`, title: 'Использование контекста', tokenSummary: (used, max) => `${used} / ${max} токенов` }, session: 'Сеанс', yoloOn: 'YOLO включён — автоматическое подтверждение опасных команд. Shift-клик переключает глобально.', yoloOff: 'YOLO выключен. Shift-клик переключает глобально.', modelNone: 'нет', noModel: 'модель не выбрана', switchModel: 'Сменить модель', openModelPicker: 'Открыть выбор модели', modelPinned: 'закреплено вами; новые чаты используют её вместо модели по умолчанию из настроек', modelTitle: (provider, model) => `Модель · ${provider}: ${model}`, providerModelTitle: (provider, model) => `${provider} · ${model}` } }, rightSidebar: { aria: 'Правая боковая панель', panelsAria: 'Панели правой боковой панели', files: 'Файловая система', terminal: 'Терминал', noFolderSelected: 'Папка не выбрана', changeCwdTitle: 'Изменить рабочий каталог', remotePickerTitle: 'Выбрать удалённую папку', remotePickerDescription: 'Просмотрите папки на подключённом бэкенде.', remotePickerSelect: 'Выбрать папку', folderTip: cwd => cwd, openFolder: 'Открыть папку', refreshTree: 'Обновить дерево', collapseAll: 'Свернуть все папки', previewUnavailable: 'Предпросмотр недоступен', couldNotPreview: path => `Не удалось предпросмотреть ${path}`, noProjectTitle: 'Проект не открыт', noProjectBody: 'Откройте проект, чтобы просматривать его файлы и проверять изменения.', noProjectOpen: 'Проект не открыт', noDiffs: 'Нет изменений', unreadableTitle: 'Недоступно', unreadableBody: error => `Не удалось прочитать эту папку (${error}).`, emptyTitle: 'Пусто', emptyBody: 'Эта папка пуста.', treeErrorTitle: 'Ошибка дерева', treeErrorBody: 'Дерево файлов столкнулось с ошибкой при отображении этой папки.', tryAgain: 'Попробовать снова', loadingTree: 'Загрузка дерева файлов', loadingFiles: 'Загрузка файлов', terminalHide: 'Скрыть терминал', terminalsAria: 'Терминалы', terminalNew: 'Новый терминал', terminalCloseOthers: 'Закрыть другие', terminalCloseAll: 'Закрыть все', addToChat: 'Добавить в чат' }, preview: { tab: 'Предпросмотр', closePane: 'Закрыть панель предпросмотра', loading: 'Загрузка предпросмотра', unavailable: 'Предпросмотр недоступен', opening: 'Открываем...', hide: 'Скрыть', openPreview: 'Открыть предпросмотр', openInBrowser: 'Открыть в браузере', linkHint: '⌘/Ctrl-клик — панель предпросмотра', sourceLineTitle: 'Клик — выбрать · Shift-клик — расширить · перетащите в композер', source: 'ИСТОЧНИК', renderedPreview: 'ПРЕДПРОСМОТР', diff: 'DIFF', unknownSize: 'размер неизвестен', binaryTitle: 'Похоже на бинарный файл', binaryBody: label => `Предпросмотр ${label} может показать нечитаемый текст.`, largeTitle: 'Этот файл большой', largeBody: (label, size) => `${label} — ${size}. Hermes покажет только первые 512 КБ.`, previewAnyway: 'Предпросмотр всё равно', truncated: 'Показаны первые 512 КБ.', noInlineTitle: 'Нет inline-предпросмотра', noInlineBody: mimeType => `${mimeType || 'Этот тип файла'} всё равно можно прикрепить как контекст.`, edit: 'Изменить', editing: 'Изменение', unsavedChanges: 'Несохранённые изменения', saveFailed: message => `Не удалось сохранить: ${message}`, diskChangedTitle: 'Файл изменился на диске', diskChangedBody: 'Этот файл изменился с момента открытия. Перезаписать его вашей версией или сбросить правки и перезагрузить?', overwrite: 'Перезаписать', discardReload: 'Сбросить и перезагрузить', console: { deselect: 'Снять выделение записи', select: 'Выбрать запись', copyFailed: 'Не удалось скопировать вывод консоли', copyEntry: 'Скопировать эту запись', sendEntry: 'Отправить эту запись в чат', messages: count => `${count} ${RU_PLURAL(count, 'сообщение консоли', 'сообщения консоли', 'сообщений консоли')}`, resize: 'Изменить размер консоли предпросмотра', title: 'Консоль предпросмотра', selected: count => `${count} ${count === 1 ? 'выделено' : 'выделено'}`, sendToChat: 'Отправить в чат', copySelected: 'Скопировать выбранное в буфер', copyAll: 'Скопировать всё в буфер', copy: 'Копировать', clear: 'Очистить', empty: 'Сообщений консоли пока нет.', promptHeader: 'Консоль предпросмотра:', sentTitle: 'Отправлено в чат', sentMessage: count => `${count} ${RU_NOUN(count, 'запись лога', 'записи лога', 'записей лога')} добавлено в композер` }, web: { appFailedToBoot: 'Приложение предпросмотра не запустилось', serverNotFound: 'Сервер не найден', remoteLoopback: 'Этот адрес указывает на машину, на которой работает ваш агент, а не на эту. Панель браузера загружает страницы локально, поэтому для удалённого dev-сервера нужен порт-форвардинг или доступный hostname.', failedToLoad: 'Не удалось загрузить предпросмотр', tryAgain: 'Попробовать снова', restarting: 'Hermes перезапускается...', askRestart: 'Попросить Hermes перезапустить сервер', lookingRestart: taskId => `Hermes ищет сервер предпросмотра для перезапуска (${taskId})`, restartingTitle: 'Перезапуск сервера предпросмотра', restartingMessage: 'Hermes работает в фоне. Следите за прогрессом в консоли предпросмотра.', startRestartFailed: message => `Не удалось запустить перезапуск сервера: ${message}`, restartFailed: 'Перезапуск сервера не удался', hideConsole: 'Скрыть консоль предпросмотра', showConsole: 'Показать консоль предпросмотра', hideDevTools: 'Скрыть DevTools предпросмотра', openDevTools: 'Открыть DevTools предпросмотра', goBack: 'Назад', goForward: 'Вперёд', reload: 'Перезагрузить страницу', address: 'Адрес', addressPlaceholder: 'Введите адрес', blankPageBody: 'Введите адрес выше, чтобы просматривать, или попросите Hermes открыть страницу.', finishedRestarting: message => `Hermes завершил перезапуск сервера предпросмотра${message ? `: ${message}` : ''}`, failedRestarting: message => `Перезапуск сервера не удался: ${message}`, unknownError: 'неизвестная ошибка', restartedTitle: 'Сервер предпросмотра перезапущен', reloadingNow: 'Перезагружаем предпросмотр.', restartFailedTitle: 'Перезапуск предпросмотра не удался', restartFailedMessage: 'Hermes не смог перезапустить сервер.', stillWorking: 'Hermes всё ещё работает, но результата перезапуска пока нет. Команда сервера может выполняться в foreground.', workspaceReloading: 'Рабочее пространство изменилось, перезагружаем предпросмотр', fileChanged: url => `Файл изменился, перезагружаем предпросмотр: ${url}`, filesChanged: (count, url) => `${count} ${RU_NOUN(count, 'изменение файла', 'изменения файла', 'изменений файла')}, перезагружаем предпросмотр: ${url}`, watchFailed: message => `Не удалось отслеживать файл предпросмотра: ${message}`, moduleMimeDescription: 'Модульные скрипты раздаются с неверным MIME-типом. Обычно это значит, что статический файл-сервер раздаёт Vite/React-приложение вместо dev-сервера проекта.', loadFailedConsole: (code, message) => `Не удалось загрузить${code ? ` (${code})` : ''}: ${message}`, unreachableDescription: 'Страница предпросмотра недоступна.', openTarget: url => `Открыть ${url}`, fallbackTitle: 'Предпросмотр' } }, zones: { showTabStrip: 'Показать вкладки', hideTabStrip: 'Скрыть вкладки', showStripTab: title => `Показать ${title}`, hideStripTab: title => `Скрыть ${title}`, lastTabKeptTitle: 'Последняя вкладка остаётся', lastTabKeptBody: 'В этой зоне нужна хотя бы одна видимая вкладка. Сначала покажите другую вкладку или сверните всю боковую панель.', toggleStripTab: title => `Переключить вкладку ${title}`, minimize: 'Свернуть', restore: 'Восстановить', closeRunningTitle: 'Закрыть работающую вкладку?', closeRunningBody: 'Этот чат ещё работает (или ждёт вашего ввода). Закрытие вкладки скроет его — сеанс сохранит прогресс и можно будет открыть снова из боковой панели.', closeRunningConfirm: 'Закрыть вкладку', reload: 'Перезагрузить', closeOthers: 'Закрыть другие', closeToRight: 'Закрыть справа', closeAll: 'Закрыть все', newSessionTab: 'Вкладка нового сеанса', pluginDisabled: pluginId => `Плагин «${pluginId}» отключён`, pluginDisabledBody: 'Включите его снова в Настройки → Плагины, чтобы вернуть панель.', missingPane: paneId => `нет панели: ${paneId}`, editTitle: 'Раскладки', editHint: 'Выберите раскладку или перетащите панели между зонами.', reset: 'Сбросить', templates: 'Шаблоны', custom: 'Свои', newGridLayout: 'Новая сеточная раскладка', saveCurrentAs: 'Сохранить текущую расстановку как шаблон', nameLayoutPlaceholder: 'Название этой раскладки…', deletePreset: name => `Удалить ${name}`, zoneEditorTitle: 'Редактор зон', editorHintPre: 'клик — разделить · ', editorHintPost: ' переворачивает линию · перетаскивание между зонами — слить · перетаскивание общих граней — изменить размер', templateColumns: 'Колонки', templateRows: 'Строки', templateGrid: 'Сетка', templatePriority: 'Приоритет', zoneTag: index => `зона ${index}`, mergeZones: count => `Слить ${count} ${RU_NOUN(count, 'зона', 'зоны', 'зон')}`, customZoneName: count => `Своя ${count}-зонная`, layoutNamePlaceholder: fallback => `Название раскладки (${fallback})`, saveApply: 'Сохранить и применить', notExpressible: 'эта расстановка зацеплена (pinwheel) — пока не выразима как вложенные разделения', zoneCount: count => `${count} ${RU_NOUN(count, 'зона', 'зоны', 'зон')}`, tabCount: count => `${count} ${RU_NOUN(count, 'вкладка', 'вкладки', 'вкладок')}` }, contextMenu: { link: { openInApp: 'Открыть во встроенном браузере', openExternal: 'Открыть во внешнем браузере', copyUrl: 'Копировать URL', copyResolvedUrl: 'Копировать разрешённый URL' }, image: { copyImage: 'Копировать изображение', copyImageAddress: 'Копировать адрес изображения', saveImageAs: 'Сохранить изображение как…' }, edit: { cut: 'Вырезать', paste: 'Вставить', selectAll: 'Выделить всё', addToDictionary: 'Добавить в словарь' }, page: { copyPageUrl: 'Копировать URL страницы', inspectElement: 'Исследовать элемент' } }, assistant: { thread: { loadingSession: 'Загрузка сеанса', showEarlier: 'Показать ранние сообщения', loadingResponse: 'Hermes загружает ответ', resumeWhenBackgroundDone: count => count === 1 ? 'Продолжится, когда фоновая задача завершится' : `Продолжится, когда ${count} ${RU_NOUN(count, 'фоновая задача', 'фоновые задачи', 'фоновых задач')} завершатся`, thinking: 'Думает', thought: 'Помыслил', thoughtBriefly: 'Кратко подумал', thoughtFor: duration => `Думал ${duration}`, turnDuration: duration => `Этот ход занял ${duration}`, today: time => `Сегодня, ${time}`, yesterday: time => `Вчера, ${time}`, copy: 'Копировать', refresh: 'Обновить', moreActions: 'Ещё действия', branchNewChat: 'Ветка в новый чат', react: 'Реакция', dismissError: 'Скрыть ошибку', filesChanged: count => `${count} ${RU_PLURAL(count, 'файл изменён', 'файла изменено', 'файлов изменено')}`, reviewChanges: 'Проверить', readAloudFailed: 'Не удалось зачитать вслух', preparingAudio: 'Подготовка аудио...', stopReading: 'Остановить чтение', readAloud: 'Зачитать вслух', editMessage: 'Изменить сообщение', expandMessage: 'Развернуть сообщение', scrollToBottom: 'Прокрутить вниз', stop: 'Стоп', restorePrevious: 'Восстановить предыдущий чекпоинт', restoreCheckpoint: 'Восстановить чекпоинт', restoreFromHere: 'Восстановить чекпоинт — запустить снова с этого промпта', restoreTitle: 'Восстановить до этого чекпоинта?', restoreBody: 'Всё, что было после этого промпта, будет удалено из разговора, и промпт запустится снова отсюда.', restoreConfirm: 'Восстановить и запустить', restoreNext: 'Восстановить следующий чекпоинт', goForward: 'Двигаться вперёд', sendEdited: 'Отправить изменённое сообщение', attachingFile: 'Прикрепление…' }, approval: { gatewayDisconnected: 'Шлюз Hermes не подключён', sendFailed: 'Не удалось отправить ответ на подтверждение', run: 'Выполнить', command: 'Команда', moreOptions: 'Больше опций подтверждения', allowSession: 'Разрешить в этом сеансе', alwaysAllowMenu: 'Всегда разрешать…', jumpToApproval: 'Нужно подтверждение', reject: 'Отклонить', alwaysTitle: 'Всегда разрешать эту команду?', alwaysDescription: pattern => `Это добавит паттерн «${pattern}» в ваш постоянный список разрешений (~/.hermes/config.yaml). Hermes больше не будет спрашивать о подобных командах — ни в этом сеансе, ни в будущем.`, alwaysAllow: 'Всегда разрешать' }, clarify: { notReady: 'Запрос уточнения ещё не готов', gatewayDisconnected: 'Шлюз Hermes не подключён', sendFailed: 'Не удалось отправить ответ на уточнение', loadingQuestion: 'Загрузка вопроса…', other: 'Другое (введите ответ)', placeholder: 'Введите ваш ответ…', skip: 'Пропустить', skipped: 'Пропущено', continueLabel: 'Продолжить', confirmAndContinueLabel: 'Подтвердить и продолжить', answeredBadge: 'Ответ дан', questionProgress: (answered, total) => `Ответ дан на ${answered} из ${total}`, lateAnswer: (question, choice) => `Re: «${question}» — мой ответ: ${choice}`, lateAnswerTip: 'Составить этот ответ как продолжение', lateAnswerHint: 'Этот промпт больше не ждёт. Выберите вариант, чтобы составить его как сообщение-продолжение.' }, mcpSetup: { installTitle: server => `Добавить MCP-сервер ${server}?`, enableTitle: server => `Включить MCP-сервер ${server}?`, authorizeTitle: server => `Авторизовать MCP-сервер ${server}?`, installAction: 'Установить', enableAction: 'Включить', authorizeAction: 'Авторизовать', decline: 'Не сейчас', declined: 'Отклонено', installed: server => `${server} установлен`, enabled: server => `${server} включён`, authorized: server => `${server} авторизован`, failed: server => `Настройка не удалась для ${server}`, unanswered: 'Нет ответа', toolCount: count => `${count} ${RU_NOUN(count, 'инструмент', 'инструмента', 'инструментов')}`, notInCatalog: server => `«${server}» нет в MCP-каталоге`, catalogSource: 'Из каталога, одобренного Nous', envRequired: 'Сначала заполните обязательные учётные данные', sendFailed: 'Не удалось отправить ответ на настройку MCP', reloadFailed: 'Сервер сохранён, но перезагрузка MCP-инструментов не удалась — они загрузятся в следующем сеансе', gatewayDisconnected: 'Шлюз Hermes не подключён' }, tool: { copyCode: 'Копировать код', renderingImage: 'Рендеринг изображения', copyOutput: 'Копировать вывод', copyCommand: 'Копировать команду', copyContent: 'Копировать содержимое', copyUrl: 'Копировать URL', copyResults: 'Копировать результаты', copyQuery: 'Копировать запрос', copyFile: 'Копировать файл', copyPath: 'Копировать путь', outputAlt: 'Вывод инструмента', rawResponse: 'Сырой ответ', copyActivity: 'Копировать активность', recoveredOne: 'Восстановлено после 1 неудачного шага', recoveredMany: count => `Восстановлено после ${count} ${RU_NOUN(count, 'неудачного шага', 'неудачных шагов', 'неудачных шагов')}`, failedOne: '1 шаг не удался', failedMany: count => `${count} ${RU_NOUN(count, 'шаг не удался', 'шага не удалось', 'шагов не удалось')}`, statusRunning: 'Выполняется', statusError: 'Ошибка', statusRecovered: 'Восстановлено', statusDone: 'Готово', memoryWriteNoted: 'Запись в память отмечена', actions: { read: 'Чтение', reading: 'Читает', opened: 'Открыто', opening: 'Открывает', failedToOpen: 'Не удалось открыть', searched: 'Поиск выполнен', searching: 'Ищет', ran: 'Выполнено', running: 'Выполняется', ranCode: 'Код выполнен', runningCode: 'Скриптинг' }, prefixes: { browser: 'Браузер', web: 'Web' }, titleTemplates: { actionCommand: (action, command) => `${action} ${command}`, actionQuoted: (action, value) => `${action} «${value}»`, actionTarget: (action, target) => `${action} ${target}`, prefixedDone: (prefix, action) => `${prefix} ${action}`, runningPrefixedTool: (prefix, action) => `Выполняется: ${prefix.toLowerCase()} ${action.toLowerCase()}`, runningTool: action => `Выполняется: ${action.toLowerCase()}` }, titles: { browser_click: { done: 'Нажат элемент страницы', pending: 'Нажимаю элемент страницы', pendingAction: 'Нажимаю' }, browser_fill: { done: 'Заполнено поле формы', pending: 'Заполняю поле формы', pendingAction: 'Заполняю' }, browser_navigate: { done: 'Открыта страница', pending: 'Открываю страницу', pendingAction: 'Открываю' }, browser_snapshot: { done: 'Снят снимок страницы', pending: 'Снимаю страницу', pendingAction: 'Снимаю' }, browser_take_screenshot: { done: 'Снят скриншот', pending: 'Снимаю скриншот', pendingAction: 'Снимаю' }, browser_type: { done: 'Введено на странице', pending: 'Ввожу на странице', pendingAction: 'Ввожу' }, clarify: { done: 'Задан вопрос', pending: 'Задаю вопрос', pendingAction: 'Задаю' }, cronjob: { done: 'Cron-задача', pending: 'Планирую cron-задачу', pendingAction: 'Планирую' }, edit_file: { done: 'Файл изменён', pending: 'Изменяю файл', pendingAction: 'Изменяю' }, execute_code: { done: 'Код выполнен', pending: 'Скриптинг', pendingAction: 'Скриптинг' }, image_generate: { done: 'Изображение сгенерировано', pending: 'Генерирую изображение', pendingAction: 'Генерирую' }, list_files: { done: 'Файлы перечислены', pending: 'Перечисляю файлы', pendingAction: 'Перечисляю' }, memory: { done: 'Сохранено в память', pending: 'Сохраняю в память', pendingAction: 'Сохраняю' }, patch: { done: 'Файл патчен', pending: 'Патчу файл', pendingAction: 'Патчу' }, read_file: { done: 'Файл прочитан', pending: 'Читаю файл', pendingAction: 'Читаю' }, search_files: { done: 'Файлы найдены', pending: 'Ищу файлы', pendingAction: 'Ищу' }, session_search_recall: { done: 'История сеансов найдена', pending: 'Ищу в истории сеансов', pendingAction: 'Ищу' }, terminal: { done: 'Команда выполнена', pending: 'Выполняю команду', pendingAction: 'Выполняю' }, todo: { done: 'Todo обновлены', pending: 'Обновляю todo', pendingAction: 'Обновляю' }, vision_analyze: { done: 'Изображение проанализировано', pending: 'Анализирую изображение', pendingAction: 'Анализирую' }, web_extract: { done: 'Веб-страница прочитана', pending: 'Читаю веб-страницу', pendingAction: 'Читаю' }, web_search: { done: 'Поиск в вебе выполнен', pending: 'Ищу в вебе', pendingAction: 'Ищу' }, write_file: { done: 'Файл изменён', pending: 'Изменяю файл', pendingAction: 'Изменяю' } } } }, prompts: { gatewayDisconnected: 'Шлюз Hermes не подключён', sudoSendFailed: 'Не удалось отправить пароль sudo', secretSendFailed: 'Не удалось отправить секрет', sudoTitle: 'Пароль администратора', sudoDesc: 'Hermes нужен ваш пароль sudo, чтобы выполнить команду с повышенными правами. Он отправляется только вашему локальному агенту.', sudoPlaceholder: 'пароль sudo', secretTitle: 'Требуется секрет', secretDesc: 'Hermes нужны учётные данные, чтобы продолжить.', secretPlaceholder: 'значение секрета' }, desktop: { audioReadFailed: 'Не удалось прочитать записанное аудио', sessionUnavailable: 'Сеанс недоступен', createSessionFailed: 'Не удалось создать новый сеанс', promptFailed: 'Промпт не удался', providerCredentialRequired: 'Добавьте учётные данные провайдера перед отправкой первого сообщения.', emptySlashCommand: 'пустая слэш-команда', desktopCommands: 'Команды desktop', skillCommandsAvailable: count => `${count} ${RU_NOUN(count, 'команда навыка', 'команды навыка', 'команд навыка')} доступно.`, warningLine: message => `предупреждение: ${message}`, yoloArmed: 'YOLO включён для этого чата', yoloOff: 'YOLO выключен', yoloSystem: active => `YOLO ${active ? 'включён' : 'выключен'} для этого сеанса`, yoloTitle: 'YOLO', yoloToggleFailed: 'Не удалось переключить YOLO', profileStatus: current => `Профиль: ${current}. Используйте /profile или выборку «Новый сеанс», чтобы начать чат в другом профиле.`, unknownProfile: 'Неизвестный профиль', noProfileNamed: (target, available) => `Нет профиля «${target}». Доступны: ${available}`, newChatsProfile: name => `Новые чаты будут использовать профиль ${name}.`, setProfileFailed: 'Не удалось установить профиль', sttDisabled: 'Распознавание речи отключено в настройках.', stopFailed: 'Остановка не удалась', regenerateFailed: 'Повторная генерация не удалась', editFailed: 'Изменение не удалось', editTurnUnavailable: 'Этого хода больше нет в истории сервера (возможно, он был сжат).', resumeFailed: 'Возобновление не удалось', resumeStrandedTitle: 'Не удалось загрузить этот сеанс', resumeStrandedBody: 'Соединение с этим сеансом оборвалось, и автоматические повторные попытки исчерпаны. Проверьте, что шлюз работает, и попробуйте снова.', resumeRetry: 'Повторить', nothingToBranch: 'Нечего ветвить', branchNeedsChat: 'Начните или возобновите чат перед ветвлением.', sessionBusy: 'Сеанс занят', branchStopCurrent: 'Остановите текущий ход перед ветвлением этого чата.', branchNoText: 'В этом сообщении нет текста, от которого можно ответвить.', branchTitle: n => `Черновик: Ветка #${n}`, branchFailed: 'Ветвление не удалось', deleteFailed: 'Удаление не удалось', archived: 'В архиве', archiveFailed: 'Архивирование не удалось', cwdChangeFailed: 'Изменение рабочего каталога не удалось', cwdStagedTitle: 'Рабочий каталог поставлен в очередь', cwdStagedMessage: 'Перезапустите бэкенд desktop, чтобы применить изменения cwd к этому активному сеансу.', modelSwitchFailed: 'Смена модели не удалась', sessionExported: 'Сеанс экспортирован', sessionExportFailed: 'Не удалось экспортировать сеанс', imageSaved: 'Изображение сохранено', downloadStarted: 'Загрузка началась', restartToUseSaveImage: 'Перезапустите Hermes Desktop, чтобы использовать «Сохранить изображение».', restartToSaveImages: 'Перезапустите Hermes Desktop, чтобы сохранять изображения', imageDownloadFailed: 'Загрузка изображения не удалась', openImage: 'Открыть изображение', downloadImage: 'Скачать изображение', savingImage: 'Сохранение изображения', imagePreviewFailed: 'Предпросмотр изображения не удался', imageAttach: 'Прикрепление изображения', imageWriteFailed: 'Не удалось записать изображение на диск.', imageAttachFailed: 'Прикрепление изображения не удалось', attachImages: 'Прикрепить изображения', clipboard: 'Буфер обмена', noClipboardImage: 'Изображение в буфере обмена не найдено', clipboardPasteFailed: 'Вставка из буфера обмена не удалась', dropFiles: 'Перетащите файлы', handoff: { pickPlatform: 'Выберите назначение', success: platform => `Передаём в ${platform}. Возобновите здесь в любой момент.`, systemNote: platform => `↻ Передано в ${platform} — возобновите здесь в любой момент.`, failed: error => `Передача не удалась: ${error}`, timedOut: 'Превышено время ожидания шлюза. Выполняется ли `hermes gateway`?' } }, errors: { genericFailure: 'Что-то пошло не так', boundaryTitle: 'Что-то сломалось в интерфейсе', boundaryDesc: 'Вид столкнулся с неожиданной ошибкой. Ваши чаты и настройки в безопасности.', reloadWindow: 'Перезагрузить окно', openLogs: 'Открыть журналы' }, ui: { search: { clear: 'Очистить поиск' }, pagination: { label: 'пагинация', previous: 'Назад', previousAria: 'Перейти на предыдущую страницу', next: 'Дальше', nextAria: 'Перейти на следующую страницу' }, sidebar: { title: 'Боковая панель', description: 'Показывает мобильную боковую панель.', toggle: open => `${open ? 'Показать' : 'Скрыть'} боковую панель` } } })