Files
hermes-agent/web/src/i18n/ru.ts
T
Austin PickettandCursor 6d14a24b79 feat(dashboard): nous-blue theme, bulk sessions, schedule picker (#37383)
* feat(dashboard): nous-blue theme, bulk sessions, schedule picker

Batch of related dashboard improvements gathered on
austin/fix/dashboard-changes:

* Nous Blue theme — faithful port of the LENS_5I overlay system onto
  the existing DashboardTheme. Lifts the foreground inversion layer to
  z-index 200 to fix the long-standing hover / loading visual artifact,
  adds an explicit swatchColors slot so the theme picker shows the
  post-inversion preview, and migrates the legacy "lens-5i" theme key
  from localStorage / API to "nous-blue" on first read.
* Theme-aware series colors: new --series-input-token /
  --series-output-token CSS vars consumed by Analytics + Models
  charts; ToolCall + ModelInfoCard switched to semantic
  --color-success for diff lines and the Tools capability badge.
* Analytics + Models headers: consolidate period selector + refresh
  next to the page title and drop the redundant period badge.
* Bulk session management — "Delete empty (N)" button + per-row
  checkboxes with shift-click range select and a bulk-delete action
  bar. Backed by SessionDB.delete_sessions() /
  delete_empty_sessions() plus POST /api/sessions/bulk-delete and
  DELETE /api/sessions/empty (registered before the templated
  /api/sessions/{session_id} family so they don't get shadowed).
  Hard cap of 500 IDs per bulk request. Full pytest coverage.
* Cron page — human-readable schedule picker (every-interval / daily
  / weekly / monthly / once / custom) replaces the raw cron
  expression input; the job list now renders "Weekly on Mon, Wed,
  Fri at 14:30" instead of "30 14 * * 1,3,5". English-only ordinals
  for monthly schedules so non-English locales don't get incorrect
  suffixes.
* example-dashboard plugin moved from plugins/ to tests/fixtures/ so
  stock installs no longer ship the demo. Tests install it
  dynamically via a pytest fixture that also reorders the FastAPI
  routes.
* i18n: 40+ new keys for the bulk-select UI and schedule
  picker/describer translated across all 16 locales.

Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor(dashboard): dedupe memory provider picker

The memory provider <Select> lived on both /system and /plugins,
writing the same config.yaml field through two different endpoints
with no cross-page refresh. Remove the picker from /system in favor
of a read-only status row + link to /plugins, where it pairs with
the context-engine picker under "Plugin providers".

/system retains the destructive admin controls (file sizes, Reset
MEMORY.md / USER.md / all). The api.setMemoryProvider client and
PUT /api/memory/provider backend endpoint are left in place for
CLI / script callers.

Co-authored-by: Cursor <cursoragent@cursor.com>

* docs(dashboard): address Copilot review on PR #37383

- Backdrop layer-stack comment claimed LENS_5I-style themes override
  --component-backdrop-bg-blend-mode to multiply, but our only
  LENS_5I-style theme (nous-blue) keeps the default difference.
  Reword to describe what the code actually does and present the
  var as a forward-looking extension hook.
- /api/sessions/bulk-delete docstring promised the response would
  echo back the list of deleted IDs, but the implementation only
  returns {ok, deleted}. Tighten the docstring to match the wire
  format; the client already knows what it asked to delete, so the
  IDs aren't needed.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dashboard): address copilot review on cron describe + bulk-select checkbox

- schedule.ts: restrict `describeCronExpression` to strictly 5-field cron
  expressions. The backend `parse_schedule` also accepts the 6-field
  `min hour dom month dow year` form, and humanising those by
  destructuring only the first five fields would silently drop the year
  (e.g. ``0 9 * * * 2099`` rendered as "Daily at 09:00"). 6+ field
  expressions now fall through to the raw-string fallback so the user
  sees what's actually scheduled.

- SessionsPage.tsx (SessionRow): wire the bulk-select Checkbox's
  ``onClick`` directly instead of attaching it to a parent ``<span>``
  with a no-op ``onCheckedChange``. Radix forwards onClick to the
  underlying ``<button role=checkbox>``, so the same handler now drives
  both mouse clicks (preserving shift-key state for range select) and
  keyboard activation (Space on the focused checkbox, which the browser
  synthesises as a click on the <button>). Improves a11y / keyboard UX
  without changing the controlled-selection model.

- SessionsPage.tsx: also extend ``SessionRowProps`` with the new
  ``onRename`` / ``onExport`` props introduced on main so the row's
  destructured prop types resolve after the merge.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 12:37:40 -04:00

754 lines
40 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { Translations } from "./types";
export const ru: Translations = {
common: {
save: "Сохранить",
saving: "Сохранение...",
cancel: "Отмена",
close: "Закрыть",
confirm: "Подтвердить",
delete: "Удалить",
refresh: "Обновить",
retry: "Повторить",
search: "Поиск...",
loading: "Загрузка...",
create: "Создать",
creating: "Создание...",
set: "Задать",
replace: "Заменить",
clear: "Очистить",
live: "В сети",
off: "Отключено",
enabled: "включено",
disabled: "отключено",
active: "активно",
inactive: "неактивно",
unknown: "неизвестно",
untitled: "Без названия",
none: "Нет",
form: "Форма",
noResults: "Нет результатов",
of: "из",
page: "Страница",
msgs: "сообщ.",
tools: "инструменты",
match: "совпадение",
other: "Прочее",
configured: "настроено",
removed: "удалено",
failedToToggle: "Не удалось переключить",
failedToRemove: "Не удалось удалить",
failedToReveal: "Не удалось показать",
collapse: "Свернуть",
expand: "Развернуть",
general: "Общие",
messaging: "Мессенджеры",
pluginLoadFailed:
"Не удалось загрузить скрипт этого плагина. Проверьте вкладку «Сеть» (dashboard-plugins/…) и путь к плагинам на сервере.",
pluginNotRegistered:
"Скрипт плагина не вызвал register() или завершился с ошибкой. Откройте консоль браузера для подробностей.",
},
app: {
brand: "Hermes Agent",
brandShort: "HA",
closeNavigation: "Закрыть навигацию",
closeModelTools: "Закрыть модель и инструменты",
footer: {
org: "Nous Research",
},
activeSessionsLabel: "Активные сессии:",
gatewayStatusLabel: "Статус шлюза:",
gatewayStrip: {
failed: "Ошибка запуска",
off: "Отключён",
running: "Работает",
starting: "Запуск",
stopped: "Остановлен",
},
nav: {
analytics: "Аналитика",
chat: "Чат",
config: "Конфигурация",
cron: "Cron",
documentation: "Документация",
keys: "Ключи",
logs: "Журналы",
models: "Модели",
profiles: "профили: мульти-агенты",
plugins: "Плагины",
sessions: "Сессии",
skills: "Навыки",
},
modelToolsSheetSubtitle: "и инструменты",
modelToolsSheetTitle: "Модель",
navigation: "Навигация",
openDocumentation: "Открыть документацию в новой вкладке",
openNavigation: "Открыть навигацию",
pluginNavSection: "Плагины",
sessionsActiveCount: "{count} активн.",
statusOverview: "Обзор статуса",
system: "Система",
webUi: "Web UI",
},
status: {
actionFailed: "Ошибка действия",
actionFinished: "Завершено",
actions: "Действия",
agent: "Агент",
activeSessions: "Активные сессии",
connected: "Подключено",
connectedPlatforms: "Подключённые платформы",
disconnected: "Отключено",
error: "Ошибка",
failed: "Сбой",
gateway: "Шлюз",
gatewayFailedToStart: "Шлюзу не удалось запуститься",
lastUpdate: "Последнее обновление",
noneRunning: "Нет",
notRunning: "Не запущено",
pid: "PID",
platformDisconnected: "отключено",
platformError: "ошибка",
recentSessions: "Недавние сессии",
restartGateway: "Перезапустить шлюз",
restartingGateway: "Перезапуск шлюза…",
running: "Работает",
runningRemote: "Работает (удалённо)",
startFailed: "Ошибка запуска",
starting: "Запуск",
startedInBackground: "Запущено в фоне — следите за журналами",
stopped: "Остановлено",
updateHermes: "Обновить Hermes",
updatingHermes: "Обновление Hermes…",
waitingForOutput: "Ожидание вывода…",
},
sessions: {
title: "Сессии",
history: "История",
overview: "Обзор",
searchPlaceholder: "Поиск по содержимому сообщений...",
noSessions: "Сессий пока нет",
noMatch: "Нет сессий, соответствующих запросу",
startConversation: "Начните разговор, чтобы увидеть его здесь",
noMessages: "Нет сообщений",
untitledSession: "Сессия без названия",
deleteSession: "Удалить сессию",
confirmDeleteTitle: "Удалить сессию?",
confirmDeleteMessage:
"Это безвозвратно удалит разговор и все его сообщения. Действие нельзя отменить.",
sessionDeleted: "Сессия удалена",
failedToDelete: "Не удалось удалить сессию",
deleteEmpty: "Удалить пустые",
deleteEmptyConfirmTitle: "Удалить пустые сессии?",
deleteEmptyConfirmMessage:
"Это безвозвратно удалит {count} сессий без сообщений. Активные и архивные сессии будут пропущены. Это действие нельзя отменить.",
emptySessionsDeleted: "Удалено пустых сессий: {count}",
failedToDeleteEmpty: "Не удалось удалить пустые сессии",
selectSession: "Выбрать сессию",
selectAllOnPage: "Выбрать все на этой странице",
clearSelection: "Снять выделение",
selectedCount: "Выбрано: {count}",
deleteSelected: "Удалить {count}",
deleteSelectedConfirmTitle: "Удалить {count} сессий?",
deleteSelectedConfirmMessage:
"Это безвозвратно удалит {count} выбранных сессий и все их сообщения. Это действие нельзя отменить.",
selectedSessionsDeleted: "Удалено сессий: {count}",
failedToDeleteSelected: "Не удалось удалить выбранные сессии",
resumeInChat: "Продолжить в чате",
previousPage: "Предыдущая страница",
nextPage: "Следующая страница",
roles: {
user: "Пользователь",
assistant: "Ассистент",
system: "Система",
tool: "Инструмент",
},
},
analytics: {
period: "Период:",
totalTokens: "Всего токенов",
totalSessions: "Всего сессий",
apiCalls: "Вызовы API",
dailyTokenUsage: "Расход токенов по дням",
dailyBreakdown: "Разбивка по дням",
perModelBreakdown: "Разбивка по моделям",
topSkills: "Популярные навыки",
skill: "Навык",
loads: "Загружено агентом",
edits: "Управляется агентом",
lastUsed: "Последнее использование",
input: "Ввод",
output: "Вывод",
total: "Итого",
noUsageData: "Нет данных об использовании за этот период",
startSession: "Начните сессию, чтобы увидеть аналитику",
date: "Дата",
model: "Модель",
tokens: "Токены",
perDayAvg: "/день в среднем",
acrossModels: "по {count} моделям",
inOut: "{input} вход / {output} выход",
},
models: {
modelsUsed: "Использовано моделей",
estimatedCost: "Оценка стоимости",
tokens: "токены",
sessions: "сессии",
avgPerSession: "ср./сессию",
apiCalls: "вызовы API",
toolCalls: "вызовы инструментов",
noModelsData: "Нет данных по моделям за этот период",
startSession: "Начните сессию, чтобы увидеть данные по моделям",
},
logs: {
title: "Журналы",
autoRefresh: "Автообновление",
file: "Файл",
level: "Уровень",
component: "Компонент",
lines: "Строк",
noLogLines: "Записи журнала не найдены",
},
cron: {
confirmDeleteMessage:
"Это удалит задачу из расписания. Действие нельзя отменить.",
confirmDeleteTitle: "Удалить запланированную задачу?",
newJob: "Новая Cron-задача",
nameOptional: "Имя (необязательно)",
namePlaceholder: "напр. Ежедневная сводка",
prompt: "Запрос",
promptPlaceholder: "Что должен делать агент при каждом запуске?",
schedule: "Расписание (cron-выражение)",
schedulePlaceholder: "0 9 * * *",
scheduleMode: "Расписание",
scheduleModes: {
interval: "Повторяющийся интервал",
daily: "Ежедневно",
weekly: "Еженедельно",
monthly: "Ежемесячно",
once: "Один раз",
custom: "Произвольное (cron-выражение)",
intervalEvery: "Каждые",
intervalUnit: "Единицы",
unitMinutes: "минут",
unitHours: "часов",
unitDays: "дней",
timeOfDay: "Время суток",
weekdays: "Дни недели",
weekdaysShort: ["Вс", "Пн", "Вт", "Ср", "Чт", "Пт", "Сб"],
dayOfMonth: "День месяца",
onceAt: "Выполнить в",
customLabel: "Cron-выражение",
customPlaceholder: "0 9 * * *",
customHint:
"Cron-выражение из пяти полей (минута, час, день, месяц, день недели).",
preview: "Отправляется как",
previewEmpty: "(не заполнено)",
},
scheduleDescribe: {
none: "—",
everyMinutes: "Каждые {n} мин",
everyHours: "Каждые {n} ч",
everyDays: "Каждые {n} дн",
dailyAt: "Ежедневно в {time}",
weeklyAt: "Еженедельно в {days} в {time}",
monthlyAt: "Ежемесячно {day} числа в {time}",
onceAt: "Один раз {time}",
},
deliverTo: "Доставить в",
scheduledJobs: "Запланированные задачи",
noJobs: "Cron-задачи не настроены. Создайте задачу выше.",
last: "Последний",
next: "Следующий",
pause: "Пауза",
resume: "Возобновить",
triggerNow: "Запустить сейчас",
delivery: {
local: "Локально",
telegram: "Telegram",
discord: "Discord",
slack: "Slack",
email: "Email",
},
},
profiles: {
newProfile: "Новый профиль",
name: "Имя",
namePlaceholder: "напр. coder, writer и т.п.",
nameRequired: "Имя обязательно",
nameRule:
"Только строчные буквы, цифры, _ и -; должно начинаться с буквы или цифры; до 64 символов.",
invalidName: "Недопустимое имя профиля",
cloneFromDefault: "Клонировать конфигурацию из профиля по умолчанию",
allProfiles: "Профили",
noProfiles: "Профили не найдены.",
defaultBadge: "по умолчанию",
hasEnv: "env",
model: "Модель",
skills: "Навыки",
rename: "Переименовать",
editSoul: "Редактировать SOUL.md",
soulSection: "SOUL.md (личность / системный промпт)",
soulPlaceholder: "# Как должен вести себя этот агент…",
saveSoul: "Сохранить SOUL",
soulSaved: "SOUL.md сохранён",
openInTerminal: "Скопировать команду CLI",
commandCopied: "Скопировано в буфер обмена",
copyFailed: "Не удалось скопировать",
confirmDeleteTitle: "Удалить профиль?",
confirmDeleteMessage:
"Это безвозвратно удалит профиль '{name}' — конфигурацию, ключи, память, сессии, навыки, cron-задачи. Отменить нельзя.",
created: "Создан",
deleted: "Удалён",
renamed: "Переименован",
},
pluginsPage: {
contextEngineLabel: "Движок контекста",
dashboardSlots: "Слоты панели",
disableRuntime: "Отключить",
enableAfterInstall: "Включить после установки",
enableRuntime: "Включить",
forceReinstall: "Принудительная переустановка (сначала удалить существующую папку)",
headline:
"Поиск, установка, включение и обновление плагинов Hermes (аналог `hermes plugins`).",
identifierLabel: "Git URL или owner/repo",
inactive: "неактивно",
installBtn: "Установить",
installHeading: "Установка из GitHub / Git URL",
installHint: "Используйте сокращение owner/repo или полный https:// или git@ URL для клонирования.",
memoryProviderLabel: "Провайдер памяти",
missingEnvWarn: "Задайте эти переменные в разделе «Ключи», прежде чем плагин сможет работать:",
noDashboardTab: "Нет вкладки в панели",
openTab: "Открыть",
orphanHeading: "Расширения только для панели (без соответствующего plugin.yaml агента)",
pluginListHeading: "Установленные плагины",
providerDefaults: "встроенный / по умолчанию",
providersHeading: "Плагины-провайдеры рантайма",
providersHint:
"Записывает memory.provider (пусто = встроенный) и context.engine в config.yaml. Применяется со следующей сессии.",
refreshDashboard: "Пересканировать расширения панели",
removeConfirm: "Удалить этот плагин из ~/.hermes/plugins/?",
removeHint: "Удалять можно только плагины, установленные пользователем в ~/.hermes/plugins.",
rescanHeading: "Реестр SPA-плагинов",
rescanHint: "Пересканируйте после добавления файлов на диск, чтобы боковая панель подхватила новые манифесты.",
runtimeHeading: "Рантайм шлюза (YAML-плагины)",
saveProviders: "Сохранить настройки провайдеров",
savedProviders: "Настройки провайдеров сохранены.",
sourceBadge: "Источник",
authRequired: "Требуется аутентификация",
authRequiredHint: "Выполните эту команду для аутентификации:",
updateGit: "Git pull",
versionBadge: "Версия",
showInSidebar: "Показывать в боковой панели",
hideFromSidebar: "Скрыть из боковой панели",
},
skills: {
title: "Навыки",
searchPlaceholder: "Поиск навыков и наборов инструментов...",
enabledOf: "{enabled}/{total} включено",
all: "Все",
categories: "Категории",
filters: "Фильтры",
noSkills: "Навыки не найдены. Навыки загружаются из ~/.hermes/skills/",
noSkillsMatch: "Нет навыков, соответствующих запросу или фильтру.",
skillCount: "{count} навык{s}",
resultCount: "{count} результат{s}",
noDescription: "Описание отсутствует.",
toolsets: "Наборы инструментов",
toolsetLabel: "Набор инструментов {name}",
noToolsetsMatch: "Нет наборов инструментов, соответствующих запросу.",
setupNeeded: "Требуется настройка",
disabledForCli: "Отключено для CLI",
more: "+{count} ещё",
},
config: {
configPath: "~/.hermes/config.yaml",
filters: "Фильтры",
sections: "Разделы",
exportConfig: "Экспортировать конфигурацию в JSON",
importConfig: "Импортировать конфигурацию из JSON",
resetDefaults: "Сбросить к значениям по умолчанию",
resetScopeTooltip: "Сбросить {scope} к значениям по умолчанию",
confirmResetScope: "Сбросить все настройки {scope} к значениям по умолчанию? Это обновит только форму — изменения не будут записаны в config.yaml, пока вы не нажмёте «Сохранить».",
resetScopeToast: "{scope} сброшено к значениям по умолчанию — проверьте и сохраните",
rawYaml: "Исходная YAML-конфигурация",
searchResults: "Результаты поиска",
fields: "пол{s}",
noFieldsMatch: 'Нет полей, соответствующих "{query}"',
configSaved: "Конфигурация сохранена",
yamlConfigSaved: "YAML-конфигурация сохранена",
failedToSave: "Не удалось сохранить",
failedToSaveYaml: "Не удалось сохранить YAML",
failedToLoadRaw: "Не удалось загрузить исходную конфигурацию",
configImported: "Конфигурация импортирована — проверьте и сохраните",
invalidJson: "Некорректный JSON-файл",
categories: {
general: "Общие",
agent: "Агент",
terminal: "Терминал",
display: "Отображение",
delegation: "Делегирование",
memory: "Память",
compression: "Сжатие",
security: "Безопасность",
browser: "Браузер",
voice: "Голос",
tts: "Синтез речи",
stt: "Распознавание речи",
logging: "Журналирование",
discord: "Discord",
auxiliary: "Вспомогательные",
},
},
env: {
changesNote: "Изменения сохраняются на диск немедленно. Активные сессии автоматически подхватывают новые ключи.",
confirmClearMessage:
"Сохранённое значение этой переменной будет удалено из вашего файла .env. Это нельзя отменить из интерфейса.",
confirmClearTitle: "Очистить этот ключ?",
description: "Управление API-ключами и секретами, хранящимися в",
hideAdvanced: "Скрыть расширенные",
showAdvanced: "Показать расширенные",
showLess: "Показать меньше",
showMore: "Показать больше",
llmProviders: "Провайдеры LLM",
providersConfigured: "Настроено {configured} из {total} провайдеров",
getKey: "Получить ключ",
notConfigured: "{count} не настроено",
notSet: "Не задано",
keysCount: "{count} ключ{s}",
enterValue: "Введите значение...",
replaceCurrentValue: "Заменить текущее значение ({preview})",
showValue: "Показать реальное значение",
hideValue: "Скрыть значение",
},
oauth: {
title: "Входы провайдеров (OAuth)",
providerLogins: "Входы провайдеров (OAuth)",
description: "Подключено {connected} из {total} OAuth-провайдеров. Процесс входа в настоящее время выполняется через CLI; нажмите «Скопировать команду» и вставьте в терминал для настройки.",
connected: "Подключено",
expired: "Срок истёк",
notConnected: "Не подключено. Выполните {command} в терминале.",
runInTerminal: "в терминале.",
noProviders: "OAuth-совместимые провайдеры не обнаружены.",
login: "Войти",
disconnect: "Отключить",
managedExternally: "Управляется извне",
copied: "Скопировано ✓",
cli: "Копировать",
copyCliCommand: "Скопировать CLI-команду (для внешнего / резервного варианта)",
connect: "Подключить",
sessionExpires: "Сессия истечёт через {time}",
initiatingLogin: "Запуск процесса входа…",
exchangingCode: "Обмен кода на токены…",
connectedClosing: "Подключено! Закрытие…",
loginFailed: "Ошибка входа.",
sessionExpired: "Сессия истекла. Нажмите «Повторить» для нового входа.",
reOpenAuth: "Снова открыть страницу авторизации",
reOpenVerification: "Снова открыть страницу подтверждения",
submitCode: "Отправить код",
pasteCode: "Вставьте код авторизации (с суффиксом #state — допустимо)",
waitingAuth: "Ожидание авторизации в браузере…",
enterCodePrompt: "Открыта новая вкладка. Введите этот код, если будет запрошено:",
pkceStep1: "В новой вкладке открыт claude.ai. Войдите и нажмите «Authorize».",
pkceStep2: "Скопируйте код авторизации, отображённый после авторизации.",
pkceStep3: "Вставьте его ниже и отправьте.",
flowLabels: {
pkce: "Вход через браузер (PKCE)",
device_code: "Код устройства",
external: "Внешний CLI",
},
expiresIn: "истекает через {time}",
},
language: {
switchTo: "Сменить язык",
},
theme: {
title: "Тема",
switchTheme: "Сменить тему",
},
achievements: {
hero: {
kicker: "Agentic Gamerscore",
title: "Hermes Achievements",
subtitle:
"Коллекционные значки Hermes, полученные на основе реальной истории сессий. Известные, но ещё не полученные достижения отображаются как «Обнаруженные»; «Секретные» достижения остаются скрытыми до появления первого подходящего поведения.",
scan_subtitle:
"Анализ истории сессий Hermes. Первое сканирование может занять 5–10 секунд при большой истории.",
},
actions: {
rescan: "Пересканировать",
},
stats: {
unlocked: "Разблокировано",
unlocked_hint: "полученные значки",
discovered: "Обнаружено",
discovered_hint: "известные, ещё не получены",
secrets: "Секреты",
secrets_hint: "скрыты до первого сигнала",
highest_tier: "Высший уровень",
highest_tier_hint: "Copper → Silver → Gold → Diamond → Olympian",
latest: "Последнее",
latest_hint_empty: "запускайте Hermes чаще",
none_yet: "Пока нет",
},
state: {
unlocked: "Разблокировано",
discovered: "Обнаружено",
secret: "Секрет",
},
tier: {
target: "Цель: {tier}",
hidden: "Скрыто",
complete: "Завершено",
objective: "Задача",
},
progress: {
hidden: "скрыто",
},
scan: {
building_headline: "Создание профиля достижений…",
building_detail:
"Чтение сессий, вызовов инструментов, метаданных моделей и состояния разблокировки.",
starting_headline: "Запуск сканирования достижений…",
progress_detail:
"Просканировано {scanned} из {total} сессий · {pct}%. Значки разблокируются по мере поступления истории.",
idle_detail:
"Чтение сессий, вызовов инструментов, метаданных моделей и состояния разблокировки. Значки появляются здесь по мере разблокировки.",
},
guide: {
tiers_header: "Уровни",
secret_header: "Секретные достижения",
secret_body:
"Секретные достижения скрывают свой точный триггер. Как только Hermes обнаруживает связанный сигнал, карточка становится «Обнаруженной» и показывает требование.",
scan_status_header: "Статус сканирования",
scan_status_body:
"Hermes сканирует локальную историю один раз, затем карточки появятся автоматически. Если это занимает несколько секунд — ничего не зависло.",
what_scanned_header: "Что сканируется",
what_scanned_body:
"Сессии, вызовы инструментов, метаданные моделей, ошибки, достижения и локальное состояние разблокировки.",
},
card: {
share_title: "Поделиться этим достижением",
share_label: "Поделиться: {name}",
share_text: "Поделиться",
how_to_reveal: "Как открыть",
what_counts: "Что засчитывается",
evidence_label: "Подтверждение",
evidence_session_fallback: "сессия",
no_evidence: "Подтверждений пока нет",
},
latest: {
header: "Недавние разблокировки",
},
empty: {
no_secrets_header: "В этом сканировании больше не осталось скрытых секретов.",
no_secrets_body:
"Подсказка: секреты обычно начинаются с необычных ошибок или паттернов опытных пользователей — конфликты портов, ограничения прав, отсутствующие переменные окружения, ошибки YAML, коллизии Docker, использование rollback/checkpoint, попадания в кеш или мелкие исправления после большого количества красного текста.",
},
filters: {
all_categories: "Все",
visibility_all: "все",
visibility_unlocked: "разблокированные",
visibility_discovered: "обнаруженные",
visibility_secret: "секретные",
},
share: {
dialog_label: "Поделиться достижением",
header: "Поделиться: {name}",
close: "Закрыть",
rendering: "Отрисовка…",
card_alt: "Карточка для публикации {name}",
error_generic: "Что-то пошло не так.",
x_title: "Открывает X с заранее заполненным постом",
x_button: "Поделиться в X",
copy_title: "Скопировать изображение для вставки в публикацию",
copy_button: "Скопировать изображение",
copied: "Скопировано ✓",
download_button: "Скачать PNG",
hint:
"«Поделиться в X» открывает пост с заранее заполненным текстом в новой вкладке. Сначала нажмите «Скопировать изображение», если хотите прикрепить значок 1200×630 — X позволяет вставить его прямо в редактор твита. «Скачать PNG» сохраняет файл для использования где угодно.",
clipboard_unsupported:
"Копирование изображений в буфер обмена не поддерживается в этом браузере — используйте «Скачать».",
tweet_text: "Just unlocked {tier_part}\"{name}\" in Hermes Agent ☤",
},
},
kanban: {
loading: "Загрузка доски Kanban…",
loadFailed: "Не удалось загрузить доску Kanban: ",
loadFailedHint:
"Бэкенд автоматически создаёт kanban.db при первом чтении. Если ошибка повторяется, проверьте логи панели.",
board: "Доска",
newBoard: "+ Новая доска",
newBoardTitle: "Новая доска",
newBoardDescription:
"Доски позволяют разделять не связанные между собой потоки работы — по одной на проект, репозиторий или область. Воркеры одной доски никогда не видят задачи другой.",
slug: "Slug",
slugHint: "— строчные буквы, дефисы, например atm10-server",
displayName: "Отображаемое имя",
displayNameHint: "(необязательно)",
description: "Описание",
descriptionHint: "(необязательно)",
icon: "Значок",
iconHint: "(один символ или эмодзи)",
switchAfterCreate: "Переключиться на эту доску после создания",
cancel: "Отмена",
creating: "Создание…",
createBoard: "Создать доску",
search: "Поиск",
filterCards: "Фильтр карточек…",
tenant: "Tenant",
allTenants: "Все tenant'ы",
assignee: "Исполнитель",
allProfiles: "Все профили",
showArchived: "Показать архив",
lanesByProfile: "Дорожки по профилю",
nudgeDispatcher: "Подтолкнуть диспетчер",
refresh: "Обновить",
selected: "выбрано",
complete: "Завершить",
archive: "В архив",
apply: "Применить",
clear: "Очистить",
createTask: "Создать задачу в этой колонке",
noTasks: "— нет задач —",
unassigned: "без исполнителя",
untitled: "(без названия)",
loadingDetail: "Загрузка…",
addComment: "Добавить комментарий… (Enter — отправить)",
comment: "Комментарий",
status: "Статус",
workspace: "Рабочая область",
skills: "Навыки",
createdBy: "Создал",
result: "Результат",
comments: "Комментарии",
events: "События",
runHistory: "История запусков",
workerLog: "Журнал воркера",
loadingLog: "Загрузка журнала…",
noWorkerLog:
"— журнала воркера ещё нет (задача не запускалась или журнал был ротирован) —",
noDescription: "— нет описания —",
noComments: "— нет комментариев —",
edit: "изменить",
save: "Сохранить",
dependencies: "Зависимости",
parents: "Родители:",
children: "Потомки:",
none: "нет",
addParent: "— добавить родителя —",
addChild: "— добавить потомка —",
removeDependency: "Удалить зависимость",
block: "Заблокировать",
unblock: "Разблокировать",
notifyHomeChannels: "Уведомить домашние каналы",
diagnostics: "Диагностика",
hide: "Скрыть",
show: "Показать",
attention: "Внимание",
tasksNeedAttention: "задач(и) требуют внимания",
taskNeedsAttention: "1 задача требует внимания",
diagnostic: "диагностика",
open: "Открыть",
close: "Закрыть (Esc)",
reassignTo: "Переназначить на:",
copied: "Скопировано",
copyCommand: "Скопировать команду в буфер обмена",
reclaim: "Вернуть",
reassign: "Переназначить",
renderingError: "Во вкладке Kanban произошла ошибка отрисовки",
reloadView: "Перезагрузить вид",
wsAuthFailed:
"Сбой аутентификации WebSocket — перезагрузите страницу, чтобы обновить токен сессии.",
markDone: "Отметить {n} задач(и) как выполненные?",
markArchived: "Архивировать {n} задач(и)?",
warning: "Предупреждение",
phantomIds: "Фантомные id:",
active: "активно",
ended: "завершено",
noProfile: "(нет профиля)",
showAllAttempts: "Показать все попытки",
sendingUpdates: "Отправка обновлений в",
sendNotifications: "Отправлять уведомления completed / blocked / gave_up в",
archiveBoardConfirm:
"Архивировать доску '{name}'? Она будет перемещена в boards/_archived/, чтобы её можно было восстановить позже. Задачи этой доски больше не будут отображаться нигде в интерфейсе.",
archiveBoardTitle: "Архивировать эту доску",
boardSwitcherHint: "Доски позволяют разделять не связанные между собой потоки работы",
taskCreatedWarning: "Задача создана, но: ",
moveFailed: "Не удалось переместить: ",
bulkFailed: "Массовая операция: ",
completionBlockedHallucination: "⚠ Завершение заблокировано — фантомные id карточек",
suspectedHallucinatedReferences: "⚠ В тексте упомянуты фантомные id карточек",
pickProfileFirst: "Сначала выберите профиль.",
unblockedMessage: "{id} разблокирована. Задача готова к следующему тику.",
unblockFailed: "Не удалось разблокировать: ",
reclaimedMessage: "{id} возвращена. Задача снова в состоянии ready.",
reclaimFailed: "Не удалось вернуть: ",
reassignedMessage: "{id} переназначена на {profile}.",
reassignFailed: "Не удалось переназначить: ",
selectForBulk: "Выбрать для массовых действий",
clickToEdit: "Нажмите, чтобы изменить",
clickToEditAssignee: "Нажмите, чтобы изменить исполнителя",
emptyAssignee: "(пусто = снять назначение)",
columnLabels: {
triage: "Сортировка",
todo: "К выполнению",
scheduled: "Запланировано",
ready: "Готово к работе",
running: "В работе",
blocked: "Заблокировано",
done: "Готово",
archived: "В архиве",
},
columnHelp: {
triage: "Сырые идеи — specifier подготовит спецификацию",
todo: "Ожидает зависимостей или без исполнителя",
scheduled: "Ожидает известной задержки по времени или запланированного продолжения",
ready: "Зависимости выполнены; назначьте профиль для диспетчеризации",
running: "Взято воркером — выполняется",
blocked: "Воркер запросил вмешательство человека",
done: "Завершено",
archived: "В архиве",
},
confirmDone:
"Отметить эту задачу как выполненную? Захват воркера будет освобождён, а зависимые потомки станут готовыми.",
confirmArchive:
"Архивировать эту задачу? Она исчезнет из стандартного вида доски.",
confirmBlocked:
"Отметить эту задачу как заблокированную? Захват воркера будет освобождён.",
completionSummary:
"Сводка завершения для {label}. Сохраняется как результат задачи.",
completionSummaryRequired:
"Перед отметкой задачи как выполненной требуется сводка завершения.",
triagePlaceholder: "Черновая идея — ИИ её проспецифицирует…",
taskTitlePlaceholder: "Название новой задачи…",
specifier: "specifier",
assigneePlaceholder: "исполнитель",
priority: "Приоритет",
skillsPlaceholder:
"навыки (необязательно, через запятую): translation, github-code-review",
noParent: "— без родителя —",
workspacePathDir: "путь к рабочей области (обязательно, например ~/projects/my-app)",
workspacePathOptional:
"путь к рабочей области (необязательно, выводится из исполнителя, если не указан)",
logTruncated: "(показаны последние 100 KB — полный журнал в ",
logAt: ")",
},
};