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: 'Блёклый силуэт позади диалога.',
      userBubbleTitle: 'Пузырь сообщения',
      userBubbleDesc: 'Насколько прозрачны ваши сообщения. 0 — сплошная заливка, 100 — остаётся только контур.',
      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 <host> и переподключитесь.',
      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: {
      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 <name> или выборку «Новый сеанс», чтобы начать чат в другом профиле.`,
    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 ? 'Показать' : 'Скрыть'} боковую панель`
    }
  }
})
