{
  "app": {
    "name": "Tinyforge",
    "version": "v0.1"
  },
  "layout": {
    "serviceStatus": "Состояние служб"
  },
  "health": {
    "connected": "подключён",
    "disconnected": "отключён",
    "rawError": "Технические детали",
    "retryNow": "Проверить сейчас"
  },
  "nav": {
    "dashboard": "Панель",
    "apps": "Приложения",
    "eventTriggers": "Триггеры событий",
    "logScanRules": "Лог-правила",
    "metricAlertRules": "Метрик-алерты",
    "sharedSecrets": "Общие секреты",
    "triggers": "Триггеры",
    "proxies": "Прокси",
    "events": "События",
    "settings": "Настройки",
    "logout": "Выйти",
    "dns": "DNS-записи",
    "containers": "Контейнеры",
    "sectionObserve": "Наблюдение",
    "sectionSystem": "Система",
    "closeSidebar": "Закрыть боковую панель",
    "openSidebar": "Открыть боковую панель",
    "quickNavTitle": "Нажмите «g», затем букву для перехода между разделами",
    "quickNavLabel": "быстрая навигация"
  },
  "dashboard": {
    "title": "Панель управления",
    "newApp": "Новое приложение",
    "totalWorkloads": "Всего нагрузок",
    "runningContainers": "Запущенных контейнеров",
    "failedContainers": "Сбойных контейнеров",
    "recentWorkloads": "Недавние нагрузки",
    "retry": "Повторить",
    "noWorkloads": "Нагрузок пока нет.",
    "noWorkloadsDesc": "Создайте приложение и выкуйте первую нагрузку, чтобы начать.",
    "loadFailed": "Не удалось загрузить панель",
    "staleContainers": "Устаревшие контейнеры",
    "unusedImagesWarning": "Неиспользуемые Docker-образы занимают дисковое пространство",
    "unusedImages": "неиспользуемых образов",
    "systemHealth": "Состояние системы",
    "daemons": "Демоны",
    "systemResources": "Системные ресурсы",
    "systemResourcesSubtitle": "CPU, память, диск и топ потребителей",
    "statSubWorkloads": "нагрузки →",
    "statSubRunning": "запущено",
    "statSubNeedAttention": "требует внимания",
    "statSubStale": "устаревшие →"
  },
  "resources": {
    "cpuCores": "Ядра CPU",
    "memory": "Память",
    "running": "Запущено",
    "dockerDisk": "Диск Docker",
    "workloadUtilization": "Использование нагрузкой",
    "windowMinutes": "{n} минут",
    "windowHours": "{n} часов",
    "noSamples": "Пока нет данных — сбор идёт каждые {interval}с.",
    "collectionDisabled": "Сбор статистики отключён. Включите его в Настройках, чтобы заполнить график.",
    "diskImages": "Образы",
    "diskContainers": "Контейнеры",
    "diskVolumes": "Тома",
    "diskBuildCache": "Кэш сборки",
    "reclaimable": "{size} можно освободить",
    "topConsumers": "Топ потребителей",
    "byCpu": "по CPU",
    "byMemory": "по памяти",
    "noRunning": "Нет запущенных контейнеров.",
    "instance": "экземпляр",
    "site": "сайт",
    "showHistory": "Показать историю",
    "hideHistory": "Скрыть историю",
    "cpuSeries": "CPU %",
    "memorySeries": "Память %",
    "loading": "Загрузка…",
    "sectionTitle": "Ресурсы",
    "showLogs": "Показать логи",
    "hideLogs": "Скрыть логи",
    "dockerUnavailable": "Docker недоступен. Проверьте, что демон запущен."
  },
  "statsSettings": {
    "intervalLabel": "Интервал сбора статистики (с)",
    "intervalHelp": "Как часто собираются замеры ресурсов. 0 отключает сбор. Диапазон: 5–300с.",
    "retentionLabel": "Хранение статистики (часы)",
    "retentionHelp": "Как долго хранятся замеры ресурсов. 0 отключает сбор. Диапазон: 0–24ч."
  },
  "tagPicker": {
    "registry": "Реестр",
    "local": "Локальный"
  },
  "settings": {
    "title": "Настройки",
    "general": "Общие",
    "integrations": "Интеграции",
    "dns": "DNS",
    "maintenance": "Обслуживание",
    "registries": "Реестры",
    "credentials": "Учётные данные",
    "authentication": "Аутентификация",
    "backup": "Резервные копии",
    "appearance": "Внешний вид",
    "groupMain": "Обзор",
    "groupProxy": "Маршрутизация",
    "groupSystem": "Система",
    "groupSecurity": "Безопасность",
    "staleThreshold": "Порог устаревания (дни)",
    "staleThresholdHelp": "Контейнеры, неактивные дольше этого срока, будут помечены как устаревшие.",
    "dockerCleanup": "Очистка Docker-образов",
    "dockerCleanupHelp": "Удаление неиспользуемых Docker-образов ваших проектов. Удаляются только образы, не используемые активными экземплярами.",
    "pruneThreshold": "Порог предупреждения (МБ)",
    "pruneThresholdHelp": "Показывать предупреждение на дашборде, когда неиспользуемые образы превышают этот размер. 0 = отключено.",
    "pruneImages": "Очистить неиспользуемые образы",
    "pruning": "Очистка...",
    "pruneResult": "Удалено {count} образов, освобождено {mb} МБ",
    "pruneConfirmMessage": "Будут удалены неиспользуемые Docker-образы ваших проектов. Образы активных экземпляров не затрагиваются.",
    "pruneFailed": "Не удалось очистить образы",
    "buildCacheCleanupHelp": "Освобождение места на диске, занятого кэшем сборки Docker (сборки образов и статических сайтов). Удаляется только неиспользуемый кэш — при следующем развёртывании приложения используют кэш, который ещё задействован.",
    "pruneBuildCache": "Очистить кэш сборки",
    "pruningCache": "Очистка...",
    "pruneCacheResult": "Удалено записей кэша сборки: {count}, освобождено {mb} МБ",
    "pruneBuildCacheConfirmMessage": "Будут удалены неиспользуемые слои кэша сборки Docker во всём демоне. Используемые слои сохраняются, поэтому приложения, которые скоро переразвернутся, сохранят тёплый кэш; остальные пересоберутся с нуля при следующем развёртывании.",
    "pruneCacheFailed": "Не удалось очистить кэш сборки",
    "proxyProvider": "Провайдер прокси",
    "proxyProviderHelp": "Выберите способ управления обратным прокси для развёрнутых контейнеров.",
    "proxyNone": "Нет",
    "proxyNoneDesc": "Без прокси — контейнеры доступны напрямую по порту",
    "proxyNpm": "Nginx Proxy Manager",
    "proxyNpmDesc": "Маршруты через NPM API (настройте учётные данные ниже)",
    "npm": "Nginx Proxy Manager",
    "traefik": "Traefik",
    "traefikLabelsTitle": "Справка по Docker-меткам",
    "traefikLabelsDesc": "Эти метки автоматически добавляются к развёрнутым контейнерам. Показаны для справки.",
    "proxyTraefik": "Traefik",
    "proxyTraefikDesc": "Автообнаружение через Docker-метки — без API-вызовов",
    "proxyNoneWarning": "Переключение на «Нет» не удаляет существующие прокси-маршруты. Возможно, потребуется очистить их вручную.",
    "traefikEntrypoint": "Точка входа",
    "traefikEntrypointHelp": "Имя точки входа Traefik для HTTPS-маршрутов",
    "traefikCertResolver": "Резолвер сертификатов",
    "traefikCertResolverHelp": "Имя резолвера TLS-сертификатов (напр., letsencrypt)",
    "traefikNetwork": "Docker-сеть",
    "traefikNetworkHelp": "Сеть, которую слушает Traefik (оставьте пустым для глобальной сети)",
    "traefikApiUrl": "URL API Traefik",
    "traefikApiUrlHelp": "Необязательно — для проверки состояния (напр., http://traefik:8080)"
  },
  "settingsGeneral": {
    "title": "Общие настройки",
    "globalConfig": "Глобальная конфигурация",
    "globalConfigDesc": "Базовая инфраструктура: домен, сеть и интервал опроса, используемые Tinyforge для оркестрации контейнеров.",
    "configureNpm": "Выбран Nginx Proxy Manager.",
    "configureTraefik": "Выбран Traefik.",
    "configureLink": "Настроить провайдера",
    "domain": "Домен",
    "domainHelp": "Базовый домен для маршрутизации (напр., example.com → stage-dev-app.example.com)",
    "serverIp": "IP сервера (Docker Host)",
    "serverIpHelp": "IP машины с Docker. Используется для удалённого NPM.",
    "publicIp": "Публичный IP (для DNS)",
    "publicIpHelp": "IP для DNS A-записей — обычно адрес прокси/балансировщика. Если пусто, используется IP сервера.",
    "dockerNetwork": "Docker-сеть",
    "dockerNetworkHelp": "Docker-сеть, общая для контейнеров и прокси. Должна совпадать с сетью NPM/Traefik.",
    "subdomainPattern": "Шаблон поддомена",
    "subdomainPatternHelp": "Шаблон для автоматически генерируемых поддоменов",
    "subdomainVarsTitle": "Доступные переменные",
    "varProject": "Имя проекта",
    "varStage": "Имя стадии",
    "varTag": "Тег образа",
    "varPort": "Порт контейнера",
    "pollingInterval": "Интервал опроса (секунды)",
    "pollingIntervalHelp": "Как часто проверять реестры на новые теги (60-86400)",
    "notificationUrl": "URL уведомлений",
    "notificationUrlHelp": "URL вебхука для уведомлений о деплоях",
    "saveSettings": "Сохранить настройки",
    "saving": "Сохранение...",
    "saved": "Настройки успешно сохранены",
    "saveFailed": "Не удалось сохранить настройки",
    "loadFailed": "Не удалось загрузить настройки",
    "webhookUrl": "URL вебхука",
    "webhookDesc": "Этот секретный URL получает уведомления о push-событиях из вашего CI-пайплайна.",
    "noWebhookUrl": "URL вебхука не настроен",
    "copy": "Копировать",
    "copied": "URL вебхука скопирован в буфер обмена",
    "regenerateUrl": "Перегенерировать URL",
    "regenerating": "Перегенерация...",
    "regenerated": "URL вебхука перегенерирован",
    "regenerateFailed": "Не удалось перегенерировать URL вебхука",
    "regenerateWarning": "Внимание: перегенерация сделает текущий URL недействительным. Обновите ваши CI-пайплайны.",
    "sslCertificate": "SSL-сертификат",
    "sslCertificateHelp": "Wildcard-сертификат из NPM для автоматического SSL на прокси-хостах",
    "selectCertificate": "Выбрать сертификат",
    "noCertificate": "Нет (без SSL)",
    "clearCertificate": "Очистить",
    "loadingCertificates": "Загрузка сертификатов...",
    "noCertificatesFound": "Wildcard-сертификаты в NPM не найдены",
    "dnsConfig": "Настройки DNS",
    "wildcardDns": "Wildcard DNS настроен",
    "wildcardDnsHelp": "Когда включено, все поддомены разрешаются на ваш сервер через wildcard DNS правило. Отключите для управления DNS-записями для каждого сервиса.",
    "dnsProvider": "DNS-провайдер",
    "dnsProviderHelp": "Выберите DNS-провайдера для автоматического управления записями",
    "cloudflareApiToken": "API-токен Cloudflare",
    "cloudflareApiTokenHelp": "API-токен с правами редактирования DNS для вашей зоны",
    "cloudflareApiTokenPlaceholder": "Введите API-токен Cloudflare",
    "cloudflareApiTokenConfigured": "API-токен настроен",
    "cloudflareZone": "Зона Cloudflare",
    "cloudflareZoneHelp": "Выберите DNS-зону для управления записями",
    "selectZone": "Выбрать зону",
    "noZone": "Зона не выбрана",
    "loadingZones": "Загрузка зон...",
    "noZonesFound": "Зоны для этого токена не найдены",
    "testConnection": "Проверить соединение",
    "testingConnection": "Проверка...",
    "connectionSuccess": "Соединение успешно",
    "connectionFailed": "Ошибка соединения",
    "baseVolumePath": "Базовый путь томов",
    "baseVolumePathHelp": "Добавляется к относительным путям источников (напр., /data + my-app/uploads = /data/my-app/uploads)"
  },
  "settingsRegistries": {
    "title": "Реестры контейнеров",
    "description": "Управление реестрами контейнеров для обнаружения образов.",
    "addRegistry": "Добавить реестр",
    "editRegistry": "Редактировать реестр",
    "addNewRegistry": "Добавить новый реестр",
    "name": "Название",
    "nameHelp": "Понятное название для этого реестра",
    "url": "URL",
    "urlHelp": "Базовый URL реестра",
    "type": "Тип",
    "typeHelp": "Тип реестра для совместимости API",
    "token": "Токен",
    "tokenHelpNew": "API-токен для аутентификации",
    "tokenHelpEdit": "Оставьте пустым, чтобы сохранить текущий токен",
    "owner": "Владелец",
    "ownerHelp": "Владельцы пакетов через запятую (напр., alexei,my-org)",
    "save": "Сохранить",
    "saving": "Сохранение...",
    "update": "Обновить",
    "test": "Тест",
    "testing": "Тестирование...",
    "edit": "Изменить",
    "delete": "Удалить",
    "noRegistries": "Реестры ещё не настроены.",
    "addFirst": "Добавьте первый реестр",
    "registryUpdated": "Реестр обновлён",
    "registryAdded": "Реестр добавлен",
    "registryDeleted": "Реестр «{name}» удалён",
    "testSuccess": "Подключение к «{name}» успешно",
    "saveFailed": "Не удалось сохранить реестр",
    "deleteFailed": "Не удалось удалить реестр",
    "testFailed": "Тест подключения не удался",
    "loadFailed": "Не удалось загрузить реестры",
    "deleteTitle": "Удалить реестр?",
    "deleteConfirm": "Удалить реестр «{name}»? Это действие необратимо.",
    "healthChecking": "Проверка...",
    "healthConnected": "Подключено",
    "healthUnreachable": "Недоступно"
  },
  "settingsNpm": {
    "testConnection": "Проверить соединение",
    "testing": "Проверка...",
    "testSuccess": "Подключение к NPM успешно",
    "testFailed": "Не удалось подключиться к NPM",
    "saveFailedConnection": "Невозможно сохранить — проверка соединения не пройдена",
    "remoteMode": "Удалённый NPM",
    "remoteModeHelp": "Включите, если NPM работает на другой машине. Перенаправление на IP сервера с опубликованными портами.",
    "remoteModeWarning": "Требуется IP сервера в общих настройках. Порты автоматически привязываются к случайным портам хоста.",
    "accessList": "Список доступа по умолчанию",
    "accessListHelp": "Список доступа NPM для HTTP-аутентификации на прокси-хостах. Можно переопределить для каждого проекта.",
    "noAccessList": "Глобальные настройки",
    "selectAccessList": "Выберите список доступа",
    "noAccessLists": "Списки доступа в NPM не найдены",
    "accessListLoadFailed": "Не удалось загрузить списки доступа"
  },
  "settingsCredentials": {
    "title": "Учётные данные",
    "description": "Управление учётными данными для Nginx Proxy Manager и токенами реестров. Все значения зашифрованы.",
    "npm": "Nginx Proxy Manager",
    "npmDesc": "Учётные данные для управления прокси-хостами через NPM API",
    "configured": "Настроено",
    "npmUrl": "URL NPM",
    "npmUrlHelp": "URL API Nginx Proxy Manager",
    "email": "Email",
    "emailHelp": "Email администратора NPM",
    "password": "Пароль",
    "passwordHelpNew": "Пароль администратора NPM (будет зашифрован)",
    "passwordHelpEdit": "Введите новый пароль для замены текущего",
    "changeCredentials": "Изменить учётные данные",
    "save": "Сохранить",
    "saving": "Сохранение...",
    "saved": "Учётные данные NPM сохранены",
    "saveFailed": "Не удалось сохранить учётные данные NPM",
    "loadFailed": "Не удалось загрузить учётные данные",
    "registryTokens": "Токены реестров",
    "registryTokensDesc": "Токены аутентификации реестров управляются для каждого реестра в разделе",
    "registriesLink": "Реестры",
    "registryTokensSuffix": ". Каждый реестр хранит свой токен в зашифрованном виде.",
    "notSet": "Не задано"
  },
  "settingsBackup": {
    "title": "Управление резервными копиями",
    "description": "Управление резервными копиями базы данных и настройка автоматического резервного копирования.",
    "autoBackup": "Автоматическое резервное копирование",
    "autoBackupHelp": "Автоматически создавать резервные копии с заданным интервалом.",
    "interval": "Интервал копирования",
    "intervalHelp": "Как часто создавать автоматические резервные копии.",
    "intervalHours": "{hours} часов",
    "retention": "Количество хранимых копий",
    "retentionHelp": "Максимальное количество хранимых резервных копий. Старые удаляются первыми.",
    "backupNow": "Создать копию",
    "creatingBackup": "Создание...",
    "backupCreated": "Резервная копия создана",
    "backupFailed": "Не удалось создать резервную копию",
    "backupList": "Резервные копии",
    "noBackups": "Резервных копий пока нет. Создайте вручную или включите автоматическое копирование.",
    "columnFilename": "Файл",
    "columnSize": "Размер",
    "columnType": "Тип",
    "columnDate": "Создано",
    "columnActions": "Действия",
    "download": "Скачать",
    "delete": "Удалить",
    "restore": "Восстановить",
    "deleteConfirm": "Вы уверены, что хотите удалить эту резервную копию?",
    "deleted": "Резервная копия удалена",
    "deleteFailed": "Не удалось удалить резервную копию",
    "restoreConfirm": "Вы уверены, что хотите восстановить из этой копии? Текущая база данных будет заменена и сервер будет перезапущен. Все текущие данные будут потеряны.",
    "restoreWarning": "Это действие необратимо!",
    "restored": "База данных восстановлена. Сервер перезапускается...",
    "restoreFailed": "Не удалось восстановить резервную копию",
    "typeManual": "Ручная",
    "typeAuto": "Авто",
    "typePreDeploy": "Перед деплоем",
    "preDeploy": "Снимок перед каждым деплоем",
    "preDeployHelp": "Создавать снимок БД Tinyforge в начале каждого деплоя проекта. Независимо от периодического расписания выше; восстанавливается из списка ниже по типу «Перед деплоем».",
    "save": "Сохранить",
    "saving": "Сохранение...",
    "saved": "Настройки копирования сохранены",
    "saveFailed": "Не удалось сохранить настройки копирования"
  },
  "settingsAuth": {
    "title": "Настройки аутентификации",
    "description": "Настройка режима аутентификации и управление пользователями.",
    "authMode": "Режим аутентификации",
    "local": "Локальный (логин/пароль)",
    "oidc": "OIDC (SSO)",
    "oidcConfig": "Конфигурация OIDC-провайдера",
    "issuerUrl": "URL издателя",
    "clientId": "ID клиента",
    "clientSecret": "Секрет клиента",
    "redirectUrl": "URL перенаправления",
    "saveSettings": "Сохранить настройки",
    "saving": "Сохранение...",
    "saved": "Настройки сохранены",
    "saveFailed": "Не удалось сохранить",
    "loadFailed": "Не удалось загрузить настройки",
    "localUsers": "Локальные пользователи",
    "username": "Имя пользователя",
    "email": "Email",
    "role": "Роль",
    "created": "Создан",
    "noUsers": "Пользователи не найдены.",
    "addUser": "Добавить пользователя",
    "viewer": "Наблюдатель",
    "admin": "Администратор",
    "userCreated": "Пользователь создан",
    "userDeleted": "Пользователь удалён",
    "createFailed": "Не удалось создать пользователя",
    "deleteFailed": "Не удалось удалить пользователя",
    "deleteConfirm": "Вы уверены, что хотите удалить этого пользователя?",
    "deleteConfirmMessage": "Удалить пользователя «{username}»? Это действие необратимо.",
    "usernameRequired": "Имя пользователя и пароль обязательны",
    "networkError": "Ошибка сети",
    "password": "Пароль"
  },
  "login": {
    "title": "Tinyforge",
    "subtitle": "Войдите в свой аккаунт",
    "username": "Имя пользователя",
    "password": "Пароль",
    "signIn": "Войти",
    "signingIn": "Вход...",
    "or": "или",
    "ssoButton": "Войти через SSO (OIDC)",
    "loginFailed": "Ошибка входа",
    "networkError": "Ошибка сети"
  },
  "proxies": {
    "title": "Прокси-маршруты",
    "description": "Активные прокси-маршруты от контейнеров и статических сайтов.",
    "domain": "Домен",
    "project": "Проект / Сайт",
    "stage": "Этап / Режим",
    "tag": "Тег",
    "port": "Порт",
    "status": "Статус",
    "source": "Источник",
    "sourceContainer": "Контейнер",
    "sourceStatic": "Статический сайт",
    "sourceDeno": "Deno-сайт",
    "filterAll": "Все",
    "filterContainers": "Контейнеры",
    "filterSites": "Сайты",
    "noRoutes": "Нет прокси-маршрутов",
    "noRoutesDesc": "Прокси-маршруты создаются автоматически при развёртывании контейнера с прокси или публикации статического сайта.",
    "searchPlaceholder": "Поиск по домену, проекту или тегу...",
    "noMatch": "Нет маршрутов, соответствующих поиску.",
    "loadFailed": "Не удалось загрузить прокси-маршруты",
    "route": "маршрут",
    "routes": "маршрутов",
    "actions": "Действия",
    "viewTriggers": "Триггеры",
    "viewTriggersTitle": "Посмотреть привязки триггеров для этой нагрузки"
  },
  "common": {
    "cancel": "Отмена",
    "confirm": "Подтвердить",
    "close": "Закрыть",
    "toggle": "Переключить",
    "dismissNotification": "Закрыть уведомление",
    "delete": "Удалить",
    "edit": "Изменить",
    "change": "Изменить",
    "save": "Сохранить",
    "retry": "Повторить",
    "loading": "Загрузка...",
    "noData": "Нет данных",
    "project": "Проект",
    "stack": "Стек",
    "site": "Сайт",
    "back": "Назад",
    "actions": "Действия",
    "stop": "Остановить",
    "start": "Запустить",
    "restart": "Перезапустить",
    "remove": "Удалить",
    "instance": "экземпляр",
    "instances": "экземпляров",
    "next": "Далее",
    "yes": "Да",
    "no": "Нет",
    "saving": "Сохранение...",
    "refresh": "Обновить",
    "all": "Все",
    "running": "Работает",
    "stopped": "Остановлен",
    "missing": "Отсутствует"
  },
  "containers": {
    "eyebrowSuffix": "ГЛОБАЛЬНО",
    "errLoad": "Не удалось загрузить контейнеры",
    "searchPlaceholder": "Поиск по нагрузке, роли, образу, поддомену…",
    "kindFilterLabel": "Тип нагрузки",
    "stateFilterLabel": "Состояние контейнера",
    "emptyTitle": "Нет контейнеров",
    "emptyDesc": "Разверните проект, стек или сайт — контейнеры появятся здесь.",
    "noMatch": "Нет контейнеров, подходящих под фильтры.",
    "showingN": "Показано {visible} из {total} контейнеров",
    "col": {
      "workload": "Нагрузка",
      "kind": "Тип",
      "role": "Роль",
      "image": "Образ",
      "state": "Состояние",
      "subdomain": "Поддомен",
      "lastSeen": "Замечен"
    }
  },
  "empty": {
    "noRegistries": "Нет реестров",
    "noRegistriesDesc": "Добавьте реестр контейнеров для обнаружения образов.",
    "noUsers": "Нет пользователей",
    "noUsersDesc": "Добавьте локальных пользователей для управления доступом."
  },
  "validation": {
    "required": "Поле {field} обязательно",
    "invalidUrl": "Неверный формат URL",
    "invalidDomain": "Неверный формат домена",
    "invalidIp": "Неверный формат IP",
    "invalidEmail": "Неверный формат email",
    "invalidPort": "Порт должен быть от 1 до 65535",
    "invalidPollingInterval": "Интервал опроса должен быть от 60 до 86400 секунд",
    "invalidProjectName": "Допускаются только строчные буквы, цифры и дефисы",
    "requiredWhenUpdating": "Поле {field} обязательно при обновлении учётных данных",
    "requiredForNew": "Поле {field} обязательно для новых реестров"
  },
  "theme": {
    "light": "Светлая",
    "dark": "Тёмная",
    "system": "Системная"
  },
  "entityPicker": {
    "search": "Поиск...",
    "noResults": "Ничего не найдено"
  },
  "stale": {
    "title": "Устаревшие контейнеры",
    "eyebrowSuffix": "УСТАРЕВШИЕ",
    "noStale": "Нет устаревших контейнеров",
    "noStaleDesc": "Все контейнеры исправны и работают.",
    "cleanup": "Очистить",
    "cleanupAll": "Очистить все",
    "confirmCleanup": "Это остановит и удалит контейнер. Продолжить?",
    "confirmBulkCleanup": "Это остановит и удалит все устаревшие контейнеры. Продолжить?",
    "daysStale": "дней устарел",
    "lastAlive": "Последний раз жив",
    "count": "Устаревшие",
    "cleanedUp": "Контейнер очищен",
    "bulkCleanedUp": "{count} контейнеров очищено",
    "cleanupFailed": "Не удалось очистить",
    "loadFailed": "Не удалось загрузить устаревшие контейнеры"
  },
  "logs": {
    "title": "Логи контейнера",
    "lines": "строк",
    "follow": "Следить",
    "following": "Слежение...",
    "loading": "Загрузка логов...",
    "noLogs": "Нет вывода логов"
  },
  "events": {
    "title": "Журнал событий",
    "noEvents": "Событий не найдено",
    "noEventsDesc": "События будут отображаться здесь по мере их возникновения.",
    "loadMore": "Загрузить ещё",
    "newEvents": "новых событий",
    "totalCount": "всего {count}",
    "clearAll": "Очистить всё",
    "clearAllTitle": "Очистить журнал событий",
    "clearAllMessage": "Все записи журнала событий будут удалены безвозвратно.",
    "cleared": "Удалено {count} событий",
    "clearFailed": "Не удалось очистить события",
    "filter": {
      "severity": "Уровень",
      "source": "Источник",
      "dateRange": "Период",
      "search": "Поиск событий...",
      "lastHour": "Последний час",
      "last24h": "Последние 24 часа",
      "last7d": "Последние 7 дней",
      "allTime": "За всё время",
      "clear": "Сбросить фильтры"
    },
    "severity": {
      "info": "Инфо",
      "warn": "Предупреждение",
      "error": "Ошибка"
    },
    "source": {
      "deploy": "Развёртывание",
      "image": "Образ",
      "compose": "Compose",
      "dockerfile": "Dockerfile",
      "static_site": "Статический сайт",
      "stale_scanner": "Сканер устаревших",
      "stale_cleanup": "Очистка устаревших",
      "metric_alert": "Метрика",
      "admin": "Администратор"
    },
    "metadata": "Подробности"
  },
  "stats": {
    "cpu": "ЦП",
    "mem": "ОЗУ",
    "unavailable": "Статистика недоступна"
  },
  "systemHealth": {
    "containers": "Контейнеры",
    "proxies": "Прокси",
    "recentErrors": "Недавние ошибки"
  },
  "daemons": {
    "title": "Демоны",
    "notReachable": "{provider} недоступен.",
    "refresh": "Обновить",
    "refreshing": "Обновление",
    "docker": "Docker Engine",
    "npm": "Nginx Proxy Manager",
    "traefik": "Traefik",
    "proxy": "Прокси",
    "online": "Онлайн",
    "offline": "Оффлайн",
    "notConfigured": "Не настроено",
    "containers": "Контейнеры",
    "running": "Запущено",
    "paused": "Пауза",
    "stopped": "Остановлено",
    "version": "Версия",
    "apiVersion": "Версия API",
    "platform": "Платформа",
    "kernel": "Ядро",
    "cpu": "CPU",
    "memory": "Память",
    "storage": "Хранилище",
    "images": "Образы",
    "latency": "Задержка",
    "rootDir": "Корневой каталог",
    "provider": "Провайдер",
    "endpoint": "Адрес",
    "proxyHosts": "Прокси-хосты",
    "managed": "наши",
    "external": "внешние",
    "accessLists": "Списки доступа",
    "certificates": "Сертификаты",
    "dockerHint": "Проверьте, что Docker-демон запущен и сокет доступен.",
    "proxyHint": "Проверьте URL прокси, учётные данные и доступность сервиса.",
    "noProxyDesc": "Провайдер прокси не настроен. Tinyforge поддерживает Nginx Proxy Manager или Traefik.",
    "configureProxy": "Настроить в параметрах",
    "dockerNotReachable": "Docker-демон недоступен.",
    "dockerUnreachable": "Docker недоступен",
    "proxyUnreachable": "Прокси недоступен",
    "reachable": "доступен"
  },
  "dns": {
    "title": "DNS-записи",
    "description": "Просмотр и управление DNS-записями, созданными Tinyforge.",
    "wildcardActive": "Режим Wildcard DNS активен",
    "wildcardActiveDesc": "DNS-записи управляются внешне через wildcard DNS. Отключите wildcard DNS в настройках для индивидуального управления записями.",
    "refresh": "Обновить",
    "syncNow": "Синхронизировать",
    "syncing": "Синхронизация...",
    "syncComplete": "Синхронизация завершена: {created} создано, {deleted} удалено, {synced} уже синхронизировано",
    "syncFailed": "Ошибка синхронизации DNS",
    "searchPlaceholder": "Поиск по FQDN...",
    "allConsumers": "Все потребители",
    "managed": "Управляемые (инстансы)",
    "standalone": "Автономные прокси",
    "orphaned": "Осиротевшие",
    "allStatuses": "Все статусы",
    "statusSynced": "Синхронизировано",
    "statusMissing": "Отсутствует",
    "statusOrphaned": "Осиротевшее",
    "columnFqdn": "FQDN",
    "columnType": "Тип",
    "columnValue": "Значение",
    "columnConsumer": "Потребитель",
    "columnStatus": "Статус",
    "columnActions": "Действия",
    "noConsumer": "Нет потребителя",
    "noRecords": "DNS-записи не найдены. Записи появятся здесь после развёртывания сервисов.",
    "noMatchingRecords": "Нет записей, соответствующих текущим фильтрам.",
    "deleteRecord": "Удалить запись",
    "recordDeleted": "DNS-запись {fqdn} удалена",
    "deleteFailed": "Не удалось удалить DNS-запись",
    "loadFailed": "Не удалось загрузить DNS-записи",
    "totalRecords": "Всего: {count}",
    "syncedCount": "Синхронизировано: {count}",
    "missingCount": "Отсутствует: {count}",
    "orphanedCount": "Осиротевших: {count}"
  },
  "language": {
    "en": "Английский",
    "ru": "Русский"
  },
  "timezone": {
    "eyebrow": "The Forge // Хронограф",
    "title": "Часовой пояс отображения",
    "subtitle": "Все даты в Tinyforge — лог событий, деплои, бэкапы, сайты — показываются в этом поясе.",
    "modeLabel": "Режим определения",
    "modeAuto": "Автоопределение",
    "modeManual": "Вручную",
    "autoDetect": "Автоопределение из браузера",
    "autoBadge": "Авто",
    "activeZone": "Активный пояс",
    "changeZone": "Сменить часовой пояс",
    "clickToChange": "Нажмите, чтобы выбрать пояс →",
    "pickerTitle": "Выбор часового пояса",
    "pickerPlaceholder": "Поиск — город, регион, смещение UTC…",
    "groupAuto": "Определение",
    "groupPopular": "Популярные",
    "groupAll": "Все пояса",
    "previewFull": "Полная метка времени",
    "previewDate": "Только дата",
    "previewHint": "Метки времени в логе событий будут выглядеть именно так."
  },
  "settingsDns": {
    "title": "Настройка DNS",
    "description": "Выберите, использовать ли wildcard-запись или отдельные поддомены, управляемые DNS-провайдером."
  },
  "settingsIntegrations": {
    "title": "Интеграции",
    "outgoing": "Исходящие уведомления",
    "outgoingDesc": "Куда Tinyforge отправляет события деплоев и алертов. Укажите webhook-URL (Apprise, Discord, Slack, свой обработчик).",
    "incoming": "Входящие вебхуки",
    "incomingMovedDesc": "Входящие вебхуки теперь привязаны к конкретному проекту или сайту. Откройте страницу проекта или статического сайта, чтобы увидеть и перегенерировать URL."
  },
  "webhookLog": {
    "title": "Последние доставки вебхуков",
    "description": "Последние 14 дней входящих вебхуков — результат, состояние подписи и причина. Обновляется каждые 30 секунд.",
    "refresh": "Обновить",
    "loadFailed": "Не удалось загрузить журнал доставок",
    "empty": "Пока нет доставок.",
    "colTime": "Когда",
    "colStatus": "Статус",
    "colOutcome": "Результат",
    "colSignature": "Подпись",
    "colDetail": "Подробности",
    "colSource": "Источник",
    "outcome": {
      "deploy": "Развёрнуто",
      "skip": "Пропущено",
      "rejected": "Отклонено",
      "not_found": "Не найдено",
      "bad_request": "Неверный запрос",
      "error": "Ошибка"
    },
    "sig": {
      "valid": "верна",
      "invalid": "неверна",
      "missing": "отсутствует",
      "unconfigured": "выкл"
    }
  },
  "webhookPanel": {
    "copy": "Копировать",
    "copied": "Webhook-URL скопирован в буфер обмена",
    "copyFailed": "Не удалось скопировать",
    "noUrl": "Webhook-URL не настроен",
    "loadFailed": "Не удалось загрузить webhook-URL",
    "regenerate": "Перегенерировать URL",
    "regenerated": "Webhook-URL перегенерирован",
    "regenerateFailed": "Не удалось перегенерировать webhook-URL",
    "regenerateWarning": "Перегенерация инвалидирует текущий URL. Обновите CI-пайплайны и Git-вебхуки, использующие его.",
    "confirmRegenerate": "Заменить текущий URL?",
    "confirmYes": "Перегенерировать",
    "confirmNo": "Отмена",
    "signingTitle": "Подпись входящих вебхуков (HMAC)",
    "signingDesc": "Проверка подписи HMAC-SHA256 — утечка только URL не позволит подделать запрос. Совместимо с секретами вебхуков Gitea/GitHub.",
    "signingActive": "Секрет подписи настроен.",
    "signingInactive": "Секрет подписи не задан — входящие запросы не проверяются помимо URL.",
    "signingIssue": "Сгенерировать секрет",
    "signingRotate": "Перевыпустить секрет",
    "signingDisable": "Отключить подпись",
    "signingDisableConfirm": "Отключить",
    "signingIssued": "Новый секрет подписи выпущен — скопируйте его сейчас",
    "signingIssueFailed": "Не удалось сгенерировать секрет подписи",
    "signingDisabled": "Подпись отключена",
    "signingDisableFailed": "Не удалось отключить подпись",
    "signingShownOnce": "Скопируйте секрет сейчас — он больше не будет показан.",
    "signingDismiss": "Скрыть",
    "signingHint": "Используйте это значение как webhook-секрет в Gitea/GitHub/GitLab. Tinyforge ожидает заголовок {header}.",
    "signingCopied": "Секрет подписи скопирован в буфер обмена",
    "requireSignature": "Требовать подпись",
    "requireSignatureHelp": "Отклонять запросы без действительной подписи. Сначала сгенерируйте секрет.",
    "signingRequireFailed": "Не удалось обновить требование подписи"
  },
  "outgoingWebhook": {
    "signingOn": "Подпись включена",
    "signingOff": "Без подписи",
    "signingSecret": "HMAC-секрет",
    "noSecret": "Секрет не задан — исходящие события отправляются без подписи.",
    "reveal": "Показать",
    "generate": "Сгенерировать",
    "copy": "Копировать",
    "copied": "Секрет скопирован в буфер обмена",
    "copyFailed": "Не удалось скопировать",
    "loadFailed": "Не удалось загрузить секрет",
    "regenerate": "Перегенерировать",
    "regenerated": "Секрет перегенерирован",
    "regenerateFailed": "Не удалось перегенерировать секрет",
    "confirmRegenerateTitle": "Перегенерировать секрет?",
    "confirmRegenerate": "Текущий секрет инвалидируется немедленно. Все получатели должны быть обновлены синхронно — иначе начнут отклонять события.",
    "confirmDisableTitle": "Отключить HMAC-подпись?",
    "confirmDisable": "Будущие события пойдут без заголовка X-Hub-Signature-256. Получатели, требующие подпись, начнут их отклонять.",
    "confirmYes": "Подтвердить",
    "confirmNo": "Отмена",
    "disable": "Отключить подпись",
    "disabled": "Подпись отключена",
    "disableFailed": "Не удалось отключить подпись",
    "sendTestTitle": "Отправить тестовое событие",
    "sendTestHelp": "Отправляет синтетическое событие \"test\" на разрешённый URL с текущим секретом.",
    "sendTest": "Отправить тест",
    "sending": "Отправка…",
    "testFailed": "Не удалось отправить тестовое событие",
    "tier": "Уровень",
    "signed": "Подписано",
    "unsigned": "Без подписи",
    "deliveryId": "Доставка",
    "responseBody": "Тело ответа",
    "networkError": "Сетевая ошибка",
    "fallbackTo": "URL не задан на этом уровне — события унаследуются от {label}.",
    "noUrlConfigured": "URL не задан. Настройте его выше перед тестом."
  },
  "settingsMaintenance": {
    "title": "Обслуживание",
    "thresholds": "Пороги",
    "thresholdsDesc": "Настройте, когда Tinyforge помечает контейнеры как устаревшие и предупреждает о неиспользуемых образах.",
    "dangerZone": "Опасная зона"
  },
  "observability": {
    "section": "Наблюдаемость",
    "manage": "управление",
    "loading": "Загрузка…",
    "anyEvent": "любое событие",
    "noUrlSet": "URL не настроен",
    "configured": "НАСТРОЕН",
    "clear": "Очистить",
    "advanced": "Расширенно",
    "cancel": "Отмена",
    "save": "Сохранить",
    "saving": "Сохранение…",
    "delete": "Удалить",
    "deleting": "Удаление…",
    "refresh": "Обновить",
    "open": "Открыть",
    "edit": "Изменить",
    "back": "Назад",
    "regex": {
      "sampleLabel": "Пример строки",
      "placeholder": "вставьте сюда характерную строку лога",
      "promptType": "введите образец для проверки шаблона",
      "noMatch": "НЕТ СОВПАДЕНИЯ",
      "noMatchHint": "шаблон не совпал с этой строкой",
      "match": "СОВПАЛО",
      "invalid": "REGEX",
      "captures": "Группы"
    }
  },
  "triggers": {
    "title": "Триггеры событий",
    "titleNew": "Новый триггер",
    "titleSingular": "Триггер",
    "lede": "Фильтруйте записи журнала событий (события деплоев, вывод сканера логов, будущие источники) и отправляйте webhook при совпадении. Фильтры объединяются по И; пустой фильтр означает «совпадает всё».",
    "ledeNew": "Создайте правило «фильтр + действие». Диспетчер объединяет фильтры по И. Оставьте поле пустым, чтобы пропустить это измерение.",
    "stat": {
      "total": "ВСЕГО",
      "enabled": "ВКЛЮЧЕНО",
      "disabled": "ВЫКЛЮЧЕНО"
    },
    "toolbar": {
      "newButton": "Новый триггер",
      "backToList": "К списку триггеров"
    },
    "empty": {
      "heading": "Триггеров пока нет",
      "body": "Настройте триггер, чтобы пересылать записи журнала событий в Slack, мост уведомлений или любой HTTP-приёмник. Tinyforge подписывает запросы заголовком X-Hub-Signature-256, если задан секрет.",
      "cta": "Создать первый триггер"
    },
    "list": {
      "name": "Имя",
      "filters": "Фильтры",
      "action": "Действие",
      "status": "Статус",
      "open": "Открыть"
    },
    "detail": {
      "config": "Конфигурация",
      "configSub": "id #{id} · обновлено {updatedAt}",
      "dangerZone": "Опасная зона",
      "dangerZoneSub": "Удаление триггера происходит сразу. Восстановления нет.",
      "sendTest": "Отправить тест",
      "sending": "Отправка…",
      "testHttp": "HTTP {code}",
      "testSigned": "подписано",
      "testOk": "OK",
      "testFail": "ОШИБКА",
      "deleteButton": "Удалить триггер",
      "deleteTitle": "Удалить триггер?",
      "deleteMessage": "Триггер «{name}» будет удалён немедленно. Действие необратимо."
    },
    "form": {
      "name": "Имя",
      "namePlaceholder": "например, Slack #alerts при сбое деплоя",
      "required": "ОБЯЗАТЕЛЬНО",
      "andComposed": "ОБЪЕДИНЕНИЕ ПО И",
      "filtersLabel": "Фильтры",
      "actionLabel": "Действие",
      "actionWebhookBadge": "WEBHOOK",
      "severityCsv": "Уровень (CSV)",
      "severityPlaceholder": "warn,error",
      "sourceCsv": "Источник (CSV)",
      "sourcePlaceholder": "deploy,logscan",
      "messageRegex": "Регулярное выражение сообщения (необязательно)",
      "messageRegexPlaceholder": "(?i)\\bpanic\\b",
      "invalidRegex": "Некорректный regex — сервер отклонит.",
      "urlLabel": "URL",
      "urlPlaceholder": "https://hooks.slack.com/services/...",
      "secretLabel": "HMAC-секрет (необязательно)",
      "secretPlaceholder": "оставьте пустым для неподписанной доставки",
      "secretHint": "Приёмники проверяют X-Hub-Signature-256 по сырому телу запроса.",
      "secretRotateHint": "Хранится в зашифрованном виде. После создания API не возвращает значение — оставьте плейсхолдер без изменений, чтобы сохранить существующий секрет, введите новое значение для смены или очистите и сохраните, чтобы отключить подпись.",
      "enabled": "Включён",
      "enabledHint": "Выключенные триггеры остаются в таблице, но не срабатывают.",
      "submit": "Создать триггер",
      "submitting": "Создание…",
      "webhookUrl": "URL webhook"
    },
    "status": {
      "enabled": "включён",
      "disabled": "выключен"
    }
  },
  "metricalert": {
    "title": "Правила метрик-алертов",
    "titleNew": "Создать новый алерт",
    "titleSingular": "Правило алерта",
    "lede": "Пороговые проверки, которые наблюдатель выполняет по выборкам CPU и памяти каждого запущенного контейнера. Когда выборка пересекает порог, правило записывается в event_log с указанной важностью, откуда триггеры событий подхватывают его и рассылают по настроенным вебхукам. Включено {enabled} из {total}.",
    "ledeNew": "Выберите метрику, оператор сравнения и порог. Оставьте поле рабочей нагрузки пустым, чтобы создать глобальное правило для всех нагрузок, или ограничьте его одной нагрузкой.",
    "stat": {
      "total": "ВСЕГО",
      "global": "ГЛОБАЛЬНЫЕ",
      "workload": "НАГРУЗКА",
      "enabled": "ВКЛЮЧЕНО"
    },
    "toolbar": {
      "newButton": "Новый алерт",
      "backToList": "К списку алертов"
    },
    "filter": {
      "all": "ВСЕ",
      "global": "ГЛОБАЛЬНЫЕ",
      "workload": "НАГРУЗКА"
    },
    "empty": {
      "heading": "Пока нет правил алертов",
      "body": "Начните с глобального правила, например «CPU больше 80%», затем сузьте его, ограничив правило отдельной рабочей нагрузкой.",
      "cta": "Создать первый алерт"
    },
    "list": {
      "name": "Название",
      "condition": "Условие",
      "scope": "Область",
      "severity": "Важность",
      "status": "Статус",
      "open": "Открыть"
    },
    "detail": {
      "config": "Конфигурация",
      "configSub": "id #{id} · область {scope}",
      "dangerZone": "Опасная зона",
      "dangerZoneSub": "Удаление правила алерта немедленно убирает его и прекращает срабатывания.",
      "deleteButton": "Удалить алерт",
      "deleteTitle": "Удалить правило алерта?",
      "deleteMessage": "Правило «{name}» будет удалено немедленно и перестанет срабатывать."
    },
    "form": {
      "name": "Название",
      "namePlaceholder": "напр. Перегрузка CPU воркера",
      "condition": "Условие",
      "metric": "Метрика",
      "comparator": "Оператор",
      "threshold": "Порог",
      "thresholdPlaceholder": "напр. 80",
      "thresholdHintPercent": "Процент от лимита (0–100). Правило срабатывает, когда выборка пересекает этот порог.",
      "thresholdHintBytes": "Абсолютные байты (напр. 536870912 для 512 МиБ). Правило срабатывает, когда выборка памяти пересекает этот порог.",
      "matchShape": "Параметры срабатывания",
      "matchShapeOpts": "ВАЖНОСТЬ · ЗАДЕРЖКА",
      "severity": "Важность",
      "cooldown": "Задержка (с)",
      "cooldownHint": "Задержка действует на каждое правило и контейнер отдельно — одно правило на двух контейнерах работает независимо. Она ограничивает, как часто длительное превышение повторно пишется в event_log.",
      "scope": "Область",
      "scopeHint": "Правила, привязанные к нагрузке, применяются только к её контейнерам. Оставьте пустым, чтобы применить правило ко всем нагрузкам.",
      "scopeGlobal": "Глобально (применяется ко всем нагрузкам)",
      "scopePick": "Выбрать нагрузку…",
      "scopePickTitle": "Выберите нагрузку",
      "scopeClear": "Сделать глобальным",
      "scopeSelected": "Нагрузка",
      "scopeUnknown": "Неизвестная нагрузка",
      "enabled": "Включено",
      "enabledHint": "Отключённые правила остаются в таблице, но не срабатывают.",
      "required": "ОБЯЗАТЕЛЬНО",
      "optional": "НЕОБЯЗАТЕЛЬНО",
      "submit": "Создать алерт",
      "submitting": "Создаём…"
    },
    "metric": {
      "cpu_percent": "CPU %",
      "memory_percent": "Память %",
      "memory_bytes": "Память (байты)"
    },
    "metricShort": {
      "cpu": "CPU",
      "memory": "Память"
    },
    "comparator": {
      "gt": "больше чем",
      "lt": "меньше чем"
    },
    "unit": {
      "percent": "%",
      "bytes": "байт"
    },
    "scope": {
      "global": "глобально",
      "workload": "нагрузка {id}"
    },
    "status": {
      "enabled": "включено",
      "disabled": "отключено"
    }
  },
  "sharedsecrets": {
    "eyebrow": "Система",
    "title": "Общие секреты",
    "titleNew": "Создать новый секрет",
    "titleSingular": "Общий секрет",
    "lede": "Именованные переменные окружения, которые реконсилятор внедряет в подходящие нагрузки. Задайте секрету глобальную область, чтобы он применялся ко всем приложениям, или ограничьте его одним приложением. Значения доступны только для записи — они сохраняются один раз и никогда не возвращаются. Включено {enabled} из {total}.",
    "ledeNew": "Укажите секрету ключ переменной окружения и значение. Задайте глобальную область, чтобы применить его ко всем приложениям, или ограничьте одним приложением. Значение доступно только для записи — после сохранения оно больше не отображается.",
    "stat": {
      "total": "ВСЕГО",
      "global": "ГЛОБАЛЬНЫЕ",
      "app": "ПРИЛОЖЕНИЕ",
      "enabled": "ВКЛЮЧЕНО"
    },
    "toolbar": {
      "newButton": "Новый секрет",
      "backToList": "К списку секретов"
    },
    "filter": {
      "all": "ВСЕ",
      "global": "ГЛОБАЛЬНЫЕ",
      "app": "ПРИЛОЖЕНИЕ"
    },
    "empty": {
      "heading": "Пока нет общих секретов",
      "body": "Начните с глобального секрета, например DATABASE_URL, затем сузьте его, ограничив секрет отдельным приложением.",
      "cta": "Создать первый секрет"
    },
    "list": {
      "name": "Название",
      "scope": "Область",
      "value": "Значение",
      "encrypted": "Шифрование",
      "status": "Статус",
      "open": "Открыть",
      "valueSet": "задано",
      "valueNone": "—",
      "encOn": "зашифровано",
      "encOff": "открыто"
    },
    "detail": {
      "config": "Конфигурация",
      "configSub": "область {scope}",
      "dangerZone": "Опасная зона",
      "dangerZoneSub": "Удаление общего секрета немедленно убирает его и прекращает внедрение.",
      "deleteButton": "Удалить секрет",
      "deleteTitle": "Удалить общий секрет?",
      "deleteMessage": "Секрет «{name}» будет удалён немедленно и перестанет внедряться."
    },
    "form": {
      "name": "Название",
      "namePlaceholder": "напр. DATABASE_URL",
      "nameHint": "Ключ переменной окружения, внедряемый в подходящие нагрузки.",
      "value": "Значение",
      "valuePlaceholder": "Введите значение секрета",
      "valuePlaceholderEdit": "Оставьте пустым, чтобы сохранить текущее значение",
      "valueHintNew": "Значение секрета. Хранится только для записи — после сохранения больше не отображается.",
      "valueHintEditSet": "Значение задано. Оставьте пустым, чтобы сохранить его, или введите новое для замены.",
      "valueHintEditUnset": "Значение ещё не сохранено. Введите его, чтобы задать.",
      "encrypted": "Шифрование",
      "encryptedHint": "Зашифрованные секреты хранятся запечатанными и расшифровываются только при внедрении. Отключайте только для не секретных значений конфигурации.",
      "encryptedFlipWarning": "Изменение настройки шифрования требует повторного ввода значения. Введите значение выше, чтобы сохранить.",
      "scope": "Область",
      "scopeGlobalOption": "Глобально — все приложения",
      "scopeAppOption": "Приложение — одно приложение",
      "scopeAppEmpty": "Приложение не выбрано",
      "scopePick": "Выбрать приложение…",
      "scopePickTitle": "Выберите приложение",
      "scopeClear": "Очистить приложение",
      "scopeSelected": "Приложение",
      "scopeUnknown": "Неизвестное приложение",
      "scopeHint": "Глобальные секреты применяются ко всем приложениям. Секреты с областью приложения применяются только к нагрузкам этого приложения.",
      "description": "Описание",
      "descriptionPlaceholder": "Необязательная заметка о назначении секрета",
      "enabled": "Включено",
      "enabledHint": "Отключённые секреты остаются в таблице, но не внедряются.",
      "required": "ОБЯЗАТЕЛЬНО",
      "optional": "НЕОБЯЗАТЕЛЬНО",
      "submit": "Создать секрет",
      "submitting": "Создаём…",
      "conflict": "Общий секрет с такой областью и названием уже существует."
    },
    "scope": {
      "global": "Глобально",
      "app": "Приложение · {name}"
    },
    "status": {
      "enabled": "включено",
      "disabled": "отключено"
    }
  },
  "logscan": {
    "title": "Правила сканирования логов",
    "titleNew": "Новое правило",
    "titleSingular": "Правило",
    "lede": "Регулярные выражения, которые сканер применяет к потоку логов каждого работающего контейнера. Совпавшие строки попадают в event_log с уровнем правила, откуда триггеры событий передают их на настроенные webhook-приёмники. Включено {enabled} из {total}.",
    "ledeNew": "Сканируйте логи контейнеров по регулярному выражению. Оставьте поле «нагрузка» пустым, чтобы создать глобальное правило. Чтобы переопределить глобальное для одной нагрузки, используйте действие «Переопределить» на странице нагрузки.",
    "stat": {
      "total": "ВСЕГО",
      "global": "ГЛОБАЛЬНЫЕ",
      "workload": "НАГРУЗКА",
      "overrides": "ПЕРЕОПРЕДЕЛЕНИЯ",
      "activeTails": "АКТИВНЫХ TAIL",
      "droppedBucket": "ЛИМИТ",
      "droppedCooldown": "COOLDOWN",
      "compileErrors": "ОШИБКИ КОМПИЛЯЦИИ"
    },
    "stats": {
      "heading": "Статистика сканера",
      "headingSub": "Счётчики отбрасываний движка и ошибки компиляции из последнего снимка. Счётчики сбрасываются при перезапуске сервера.",
      "noCompileErrors": "Все правила компилируются без ошибок.",
      "compileErrorsHeading": "Ошибки компиляции (правило отброшено из снимка)",
      "tailsExplain": "Сейчас открыто goroutine-tail'ов по контейнерам у менеджера сканера."
    },
    "toolbar": {
      "newButton": "Новое правило",
      "backToList": "К списку правил"
    },
    "filter": {
      "all": "ВСЕ",
      "global": "ГЛОБАЛЬНЫЕ",
      "workload": "НАГРУЗКА",
      "overrides": "ПЕРЕОПРЕДЕЛЕНИЯ"
    },
    "empty": {
      "heading": "Правил пока нет",
      "body": "Начните с глобального правила вроде (?i)\\bpanic\\b с уровнем error, затем сужайте по нагрузкам через переопределения на странице нагрузки.",
      "cta": "Создать первое правило"
    },
    "list": {
      "name": "Имя",
      "pattern": "Шаблон",
      "scope": "Область",
      "severity": "Уровень",
      "streams": "Потоки",
      "status": "Статус",
      "open": "Открыть"
    },
    "detail": {
      "config": "Конфигурация",
      "configSub": "id #{id} · область {scope}",
      "regexTest": "Проверка regex",
      "regexTestSub": "Предпросмотр использует JavaScript-движок regex в браузере. Нажмите «Проверить на сервере», чтобы получить авторитетную проверку Go RE2 — это единственный надёжный сигнал для конструкций, специфичных для RE2.",
      "runServerTest": "Проверить на сервере",
      "testing": "Проверка…",
      "serverTestHint": "Сначала введите пример строки выше",
      "serverTestSendHint": "Отправить пример на backend /test",
      "serverMatch": "СОВПАЛО (СЕРВЕР)",
      "serverNoMatch": "НЕТ СОВПАДЕНИЯ",
      "serverNoMatchHint": "серверный regex не совпал с примером",
      "serverError": "ОШИБКА",
      "dangerZone": "Опасная зона",
      "dangerZoneSub": "Удаление глобального правила каскадно удаляет его переопределения для нагрузок.",
      "deleteButton": "Удалить правило",
      "deleteTitle": "Удалить правило?",
      "deleteMessage": "Правило «{name}» будет удалено немедленно. Переопределения по нагрузкам, ссылающиеся на него, также удалятся."
    },
    "form": {
      "name": "Имя",
      "namePlaceholder": "например, Panic в воркере",
      "pattern": "Шаблон",
      "regex": "REGEX",
      "patternPlaceholder": "(?i)\\bpanic\\b",
      "invalidRegex": "Некорректный regex — сервер отклонит.",
      "matchShape": "Параметры совпадения",
      "matchShapeOpts": "УРОВЕНЬ · ПОТОКИ · COOLDOWN",
      "severity": "Уровень",
      "streams": "Потоки",
      "cooldown": "Cooldown (с)",
      "cooldownHint": "Cooldown — на правило × на контейнер: одно правило, срабатывающее в двух контейнерах, считается независимо. Token bucket ограничивает выдачу на контейнер до 10 событий / 60с, чтобы не переполнить event_log.",
      "scope": "Область",
      "scopePlaceholder": "пусто для глобального правила или вставьте id нагрузки",
      "scopeHint": "Правила области нагрузки применяются только к её контейнерам. Переопределения для отдельных нагрузок проще создавать со страницы нагрузки.",
      "scopeGlobal": "Глобально (применяется ко всем нагрузкам)",
      "scopePick": "Выбрать нагрузку…",
      "scopePickTitle": "Выберите нагрузку",
      "scopeClear": "Сделать глобальным",
      "scopeSelected": "Нагрузка",
      "scopeUnknown": "Неизвестная нагрузка",
      "enabled": "Включено",
      "enabledHint": "Выключенные правила остаются в таблице, но не срабатывают.",
      "required": "ОБЯЗАТЕЛЬНО",
      "optional": "НЕОБЯЗАТЕЛЬНО",
      "submit": "Создать правило",
      "submitting": "Создание…"
    },
    "scope": {
      "global": "глобальное",
      "workload": "нагрузка {id}",
      "override": "переопределение #{id}",
      "overrideShort": "переопр. #{id}"
    },
    "status": {
      "enabled": "включено",
      "disabled": "выключено",
      "on": "вкл",
      "off": "выкл"
    },
    "panel": {
      "heading": "Лог-правила",
      "subEmpty": "Для этой нагрузки правил нет",
      "subCount": "Действует правил: {count}",
      "subCountOne": "Действует 1 правило",
      "emptyHint": "Для этой нагрузки нет правил сканирования логов. Создайте через «Новое правило» — глобальные правила применяются автоматически; для этой нагрузки также можно завести свои или переопределения.",
      "newRule": "Новое правило",
      "footerHint": "Глобальные правила применяются ко всем нагрузкам. Правила нагрузки — только здесь. Переопределения замещают глобальное для этой нагрузки — изменяйте уровень или отключайте их, не трогая исходное глобальное.",
      "override": "Переопределить",
      "overriding": "Переопределение…",
      "overrideTitle": "Создать переопределение глобального правила для этой нагрузки"
    }
  },
  "redeployTriggers": {
    "section": "Кузница",
    "title": "Триггеры передеплоя",
    "titleNew": "Новый триггер",
    "titleSingular": "Триггер",
    "lede": "Источники сигналов передеплоя — push в registry, события git, ручной запуск, расписания, webhook'и, совпадения в логах. Триггер создаётся один раз и веером раздаёт сигнал всем привязанным к нему нагрузкам.",
    "ledeNew": "Выберите вид, дайте имя и решите, могут ли внешние системы дёргать его через webhook. Привязку к нагрузкам делайте со страницы нагрузки после создания.",
    "ledeDetail": "Редактируйте конфигурацию триггера, управляйте webhook-приёмом и просматривайте все нагрузки, слушающие этот сигнал.",
    "stat": {
      "total": "ВСЕГО",
      "byKind": "{kind}",
      "withWebhook": "С WEBHOOK",
      "boundWorkloads": "НАГРУЗОК"
    },
    "kind": {
      "registry": "Registry",
      "git": "Git",
      "manual": "Ручной",
      "schedule": "Расписание",
      "webhook": "Webhook",
      "logscan": "Лог-скан",
      "unknown": "Неизвестный"
    },
    "kindShort": {
      "registry": "REG",
      "git": "GIT",
      "manual": "MAN",
      "schedule": "CRN",
      "webhook": "HK",
      "logscan": "LOG",
      "unknown": "?"
    },
    "kindHint": {
      "registry": "Следит за образом контейнера; срабатывает при push нового тега, подходящего под шаблон.",
      "git": "Срабатывает при продвижении указанной ветки или создании тега, подходящего под шаблон.",
      "manual": "Срабатывает только через кнопку Deploy на странице нагрузки или POST /workloads/{id}/deploy.",
      "schedule": "Срабатывает по фиксированному cron-расписанию.",
      "webhook": "Чистый webhook — срабатывает при обращении к URL приёма.",
      "logscan": "Срабатывает, когда правило сканирования логов совпадает со строкой.",
      "unknown": "Неизвестный вид триггера — используйте сырой JSON-редактор."
    },
    "toolbar": {
      "newButton": "Новый триггер",
      "backToList": "К списку триггеров"
    },
    "filter": {
      "all": "ВСЕ",
      "ariaLabel": "Фильтр по виду"
    },
    "empty": {
      "heading": "Триггеров пока нет",
      "body": "Триггер — источник сигнала передеплоя: registry-watcher, git-hook, ручная кнопка, расписание или webhook. Создайте один и привяжите к скольким угодно нагрузкам.",
      "cta": "Создать первый триггер"
    },
    "list": {
      "name": "Имя",
      "kind": "Вид",
      "bindings": "Нагрузки",
      "webhook": "Webhook",
      "created": "Создан",
      "open": "Открыть",
      "webhookOn": "ВКЛ",
      "webhookOff": "—",
      "noBindings": "—",
      "bindingsCount": "{count}"
    },
    "detail": {
      "config": "Конфигурация триггера",
      "configSub": "вид {kind} · id {id} · обновлено {updatedAt}",
      "webhook": "Webhook-приём",
      "webhookSub": "Когда включено, внешние системы могут дёргать триггер по URL ниже. Каждая привязанная нагрузка будет передеплоена по очереди.",
      "webhookEnable": "Включить webhook-приём",
      "webhookEnableHint": "Когда выключено, триггер срабатывает только из внутренних источников (по конфигу его вида) и кнопки ручного деплоя.",
      "webhookRequireSig": "Требовать HMAC-подпись",
      "webhookRequireSigHint": "Отклонять запросы без корректного X-Hub-Signature-256. Рекомендуется, если URL доступен из публичной сети.",
      "webhookUrlLabel": "URL приёма",
      "webhookUrlNote": "Вставьте это в настройки CI / registry / webhook GitHub. Сегмент-секрет — это пароль, обращайтесь как с паролем.",
      "webhookCopy": "Копировать",
      "webhookCopied": "Скопировано",
      "webhookRotate": "Сменить секрет",
      "webhookRotating": "Смена…",
      "webhookDisabledNote": "Webhook-приём выключен. Включите тумблер, сохраните — и URL появится здесь.",
      "bindings": "Привязанные нагрузки",
      "bindingsSub": "Все нагрузки, слушающие этот триггер. Чтобы привязать новую нагрузку, откройте её страницу и добавьте этот триггер оттуда.",
      "bindingsEmpty": "К этому триггеру пока не привязана ни одна нагрузка. Откройте нагрузку и привяжите этот триггер из её панели «Триггеры».",
      "bindingsListItem": {
        "openWorkload": "Открыть нагрузку",
        "unbind": "Отвязать"
      },
      "bindingEnabledHint": "Выключите, чтобы оставить привязку, но запретить триггеру передеплоить эту нагрузку.",
      "dangerZone": "Опасная зона",
      "dangerZoneSub": "Удаление триггера происходит сразу. Все привязки к нему удаляются каскадом.",
      "deleteButton": "Удалить триггер",
      "deleteTitle": "Удалить триггер?",
      "deleteMessage": "Триггер «{name}» будет удалён немедленно вместе с {count} привязкой(-ами). Действие необратимо.",
      "rotateTitle": "Сменить секрет webhook?",
      "rotateMessage": "Текущий URL приёма перестанет работать сразу. После смены обновите URL во всех внешних интеграциях.",
      "rotateConfirm": "Сменить",
      "unbindTitle": "Отвязать нагрузку?",
      "unbindMessage": "Нагрузка «{name}» перестанет передеплоиваться при срабатывании этого триггера. Сама нагрузка не удаляется.",
      "unbindConfirm": "Отвязать",
      "lastFired": "Последний запуск",
      "lastFiredNever": "Ни разу не срабатывал",
      "scheduleStatus": "Состояние расписания",
      "scheduleStatusSub": "Рабочее состояние внутреннего планировщика для этого триггера. «Запустить сейчас» сдвигает следующий запуск и начинает отсчёт нового интервала с этого момента.",
      "fireNow": "Запустить сейчас",
      "fireNowTitle": "Запустить триггер немедленно и сбросить окно следующего срабатывания.",
      "fireNowDisabledTitle": "Привяжите хотя бы одну нагрузку перед запуском.",
      "firing": "Запуск…",
      "fireConfirmTitle": "Запустить триггер расписания?",
      "fireConfirmMessage": "Триггер «{name}» сработает немедленно и развернёт {count} связанных нагрузок. Следующий естественный запуск будет через полный интервал от текущего момента.",
      "fireConfirm": "Запустить",
      "fireResult": "Сработал · задеплоено {deployed}/{bindings} · ошибок {errored}"
    },
    "form": {
      "kindLabel": "Вид",
      "kindHint": "Выберите источник сигнала передеплоя. Форма ниже подстраивается под вид.",
      "name": "Имя",
      "namePlaceholder": "например, ghcr.io/me/api · main",
      "required": "ОБЯЗАТЕЛЬНО",
      "configLabel": "Конфигурация",
      "image": "Ссылка на образ",
      "imagePlaceholder": "registry.example.com/owner/app",
      "imageHint": "Полная ссылка на образ без тега — Tinyforge ловит новые теги, выкладываемые под этой ссылкой.",
      "browseImages": "Выбрать",
      "browseImagesHint": "Выберите образ из настроенного реестра вместо ручного ввода ссылки.",
      "browseImagesTitle": "Выбор образа",
      "browseImagesSearch": "Поиск образов…",
      "tagPattern": "Шаблон тега",
      "tagPatternPlaceholder": "*",
      "tagPatternHint": "Glob path.Match (например, v*, release-*). * совпадает с любым тегом.",
      "repo": "Репозиторий",
      "repoPlaceholder": "owner/name",
      "repoHint": "owner/name в формате git-хостинга, не зависит от провайдера.",
      "mode": "Режим",
      "modePush": "Push в ветку",
      "modeTag": "Создание тега",
      "branch": "Ветка",
      "branchPlaceholder": "main",
      "branchHint": "Только push'и, продвигающие эту ветку, дёргают триггер.",
      "branchPattern": "Шаблон ветки (preview-деплои)",
      "branchPatternPlaceholder": "feat/* или * для любой ветки",
      "branchPatternHint": "Если задан, любой push в подходящую ветку создаёт отдельный preview-деплой. Оставьте пустым, чтобы выключить.",
      "manualNote": "У ручных триггеров нет конфига. Они срабатывают только через кнопку Deploy на странице нагрузки или POST /workloads/{id}/deploy.",
      "scheduleNote": "Срабатывает по фиксированному интервалу, который ведёт внутренний планировщик Tinyforge. Внешний webhook не нужен — включите его ниже только если CI тоже должен запускать триггер вручную.",
      "intervalPresets": "Быстрые пресеты",
      "intervalPreset": {
        "hourly": "Каждый час",
        "daily": "Каждый день",
        "weekly": "Каждую неделю"
      },
      "interval": "Интервал",
      "intervalHint": "Длительность в формате Go (например «30m», «6h», «24h», «168h»). Минимум 1 минута.",
      "scheduleReference": "Фиксированная ссылка (опционально)",
      "scheduleReferencePlaceholder": "stable",
      "scheduleReferenceHint": "Опциональный тег, ветка или ревизия, которые источник будет подтягивать на каждом срабатывании. Оставьте пустым, чтобы использовать значение по умолчанию.",
      "unknownNote": "У этого вида ещё нет встроенной формы. Используйте JSON-редактор ниже; сервер валидирует форму.",
      "advancedToggle": "Расширенный JSON",
      "advancedHint": "Запасной вариант для опытных пользователей — заменяет структурированную форму сырым payload'ом.",
      "configJson": "JSON конфигурации",
      "configJsonHint": "Должен распарситься как корректный JSON-объект. Структура проверяется сервером по виду.",
      "invalidJson": "Некорректный JSON — сервер отклонит.",
      "webhookEnabled": "Включить webhook-приём сразу",
      "webhookEnabledHint": "Генерирует секретный URL, по которому внешние системы могут дёргать триггер.",
      "webhookRequireSig": "Требовать HMAC-подпись",
      "webhookRequireSigHint": "Отклонять неподписанные запросы. Секрет — тот же, что вшит в URL — подпишите тело HMAC-SHA256 и пришлите в X-Hub-Signature-256.",
      "submit": "Создать триггер",
      "submitting": "Создание…",
      "cancel": "Отмена"
    },
    "binding": {
      "enabled": "Включена",
      "disabled": "Выключена"
    }
  },
  "apps": {
    "list": {
      "eyebrowSuffix": "ПРИЛОЖЕНИЯ",
      "title": "Приложения",
      "ledePrefix": "Plugin-native деплои —",
      "ledeKindImage": "image",
      "ledeKindCompose": "compose",
      "ledeKindStatic": "static",
      "ledeMiddle": ", или",
      "ledeSuffix": ", с подключаемыми триггерами передеплоя. Старые проекты, стеки и сайты на время переезда остаются в собственных разделах.",
      "statTotal": "ВСЕГО",
      "statImage": "IMAGE",
      "statCompose": "COMPOSE",
      "statStatic": "STATIC",
      "refresh": "Обновить",
      "newApp": "Новое приложение",
      "filterAriaLabel": "Фильтр по source-плагину",
      "filterAll": "ВСЕ",
      "loadError": "Не удалось загрузить приложения",
      "alertTag": "ОШ",
      "emptyTitle": "Приложений пока нет",
      "emptyBody": "Приложения объединяют image, compose и static-деплои за единым plugin-driven интерфейсом. Создайте первое, чтобы увидеть его здесь.",
      "emptyCta": "Создать первое приложение",
      "colName": "Имя",
      "colSource": "Источник",
      "colTrigger": "Триггер",
      "colCreated": "Создано",
      "colActions": "Действия",
      "rowOpen": "Открыть",
      "gitopsBadge": "GitOps",
      "gitopsBadgeTitle": "Конфигурация деплоя этого приложения управляется из репозитория."
    },
    "new": {
      "pageTitle": "Новое приложение · Tinyforge",
      "wizard": {
        "stepBasics": "Основное",
        "stepConfigure": "Настройка",
        "stepTrigger": "Триггер",
        "stepReview": "Обзор",
        "next": "Далее",
        "back": "Назад"
      },
      "backLabel": "К приложениям",
      "eyebrowSuffix": "НОВОЕ ПРИЛОЖЕНИЕ",
      "title": "Создать приложение",
      "ledePrefix": "Создайте plugin-native нагрузку.",
      "ledeSourceLabel": "Источник",
      "ledeSourceMid": "= как она деплоится (image, compose, static). Выберите или создайте",
      "ledeTriggerLabel": "триггер",
      "ledeSuffix": "ниже — при срабатывании source-плагин передеплоит приложение.",
      "loadingKinds": "Загрузка доступных видов плагинов…",
      "alertTag": "ОШ",
      "fieldName": "Имя",
      "fieldNameRequired": "ОБЯЗАТЕЛЬНО",
      "fieldRequired": "Обязательно",
      "fieldNamePlaceholder": "my-app",
      "fieldNameHint": "В нижнем регистре, без пробелов. Используется в именах контейнеров и поддоменах.",
      "fieldSourcePlugin": "Source-плагин",
      "fieldSourceLabel": "Источник",
      "fieldSourceHint": "Список берётся из запущенного демона — видны только вкомпилированные плагины. Триггеры (registry / git / manual) настраиваются ниже как отдельные записи.",
      "fieldSourceConfig": "Конфигурация источника",
      "fieldConfigYaml": "YAML",
      "fieldConfigForm": "ФОРМА",
      "fieldConfigJson": "JSON",
      "advancedJson": "Редактировать JSON",
      "backToForm": "К форме",
      "resetSample": "Сбросить к примеру",
      "switchToJsonTitle": "Переключиться на сырой JSON-редактор",
      "switchToFormTitle": "Вернуться к форме",
      "jsonOk": "JSON ОК",
      "jsonInvalid": "JSON НЕВЕРНЫЙ",
      "linesUnit": "строк",
      "composeHeader": "compose.yaml · compose",
      "composeAriaLabel": "Compose YAML",
      "composeProjectLabel": "Имя compose-проекта (опционально)",
      "composeProjectPlaceholder": "(по умолчанию — нормализованное имя нагрузки)",
      "composePlaceholder": "services:\n  web:\n    image: nginx:alpine\n    ports:\n      - \"80\"",
      "imageHeader": "image-источник · параметры рантайма",
      "imageRefLabel": "Образ (путь в реестре)",
      "imageRefPlaceholder": "registry.example.com/owner/app",
      "imageRefHint": "Полная ссылка без тега; тег задаётся при деплое — триггером или полем «Тег по умолчанию» ниже.",
      "imagePort": "Порт",
      "imageHealthcheck": "Путь healthcheck",
      "imageDefaultTag": "Тег по умолчанию",
      "imageRegistryLabel": "Реестр (для приватных pull-ов)",
      "imageRegistryPublic": "(публичный — без авторизации)",
      "imageRegistryHint": "Имя должно совпадать с записью на странице «Реестры». Оставьте пустым для публичных образов.",
      "imageCpu": "Лимит CPU",
      "imageCpuHint": "Ядра, 0 = ∞",
      "imageMemory": "Лимит памяти",
      "imageMemoryHint": "МБ, 0 = ∞",
      "imageMax": "Макс. инстансов",
      "imageMaxHint": "1 = строгий blue-green.",
      "imageFoot": "Переменные окружения и тома задаются в отдельных панелях на странице нагрузки после создания.",
      "dockerfileHeader": "dockerfile-источник · сборка из git-репозитория",
      "dockerfileBuildEyebrow": "сборка · dockerfile",
      "dockerfileContextPath": "Контекст сборки",
      "dockerfileContextPathPlaceholder": "(пусто = корень репо)",
      "dockerfilePath": "Путь к Dockerfile",
      "dockerfilePort": "Порт контейнера",
      "dockerfilePortRequired": "Укажите порт, который слушает приложение (1–65535).",
      "dockerfileFoot": "Tinyforge склонирует репо, соберёт образ из Dockerfile и запустит контейнер. Переменные окружения и тома — на странице нагрузки после создания.",
      "staticHeader": "static-источник · страницы из репозитория",
      "staticProvider": "Провайдер",
      "staticBaseUrl": "Base URL",
      "staticBaseUrlPlaceholder": "https://git.example.com",
      "staticRepoOwner": "Владелец репозитория",
      "staticRepoOwnerPlaceholder": "owner",
      "staticRepoName": "Имя репозитория",
      "staticRepoNamePlaceholder": "pages",
      "staticBranch": "Ветка",
      "staticBranchPlaceholder": "main",
      "staticFolder": "Папка (опционально)",
      "staticFolderPlaceholder": "(корень репозитория)",
      "staticToken": "Токен доступа (приватные репозитории)",
      "staticTokenPlaceholder": "(оставьте пустым для публичных репозиториев)",
      "staticTokenHint": "Шифруется при хранении. Нужен только для приватных репозиториев.",
      "staticMode": "Режим",
      "staticModeStaticDesc": "— раздача файлов через nginx; ноль рантайм-оверхеда.",
      "staticModeDenoDesc": "— Deno-рантайм с опциональной динамической маршрутизацией.",
      "staticRenderMarkdown": "Рендерить markdown",
      "staticRenderMarkdownDesc": "— автоматически отдавать <code>.md</code> файлы как HTML-страницы.",
      "sourceReportCommitStatus": "Отправлять статус коммита",
      "sourceReportCommitStatusDesc": "— отправлять статус деплоя обратно в Git-провайдер как статус коммита для развёрнутого коммита.",
      "deployStrategy": {
        "label": "Стратегия деплоя",
        "recreateName": "Пересоздание",
        "recreateDesc": "Остановить старый контейнер, затем запустить новый. Короткий простой во время замены.",
        "blueGreenName": "Без простоя",
        "blueGreenDesc": "Запустить новый контейнер, проверить health-check, переключить трафик и убрать старый. Без простоя.",
        "defaultBadge": "по умолчанию",
        "denoCaveat": "Deno-сайты с постоянным хранилищем используют пересоздание, чтобы избежать двух писателей на одном томе."
      },
      "staticFoot": "Секрет вебхука для git push-триггеров появляется в панели вебхука нагрузки после создания.",
      "staticDetectProvider": "Определить",
      "staticDetectedOk": "Определено: {provider}",
      "staticDetectedFailed": "Не удалось определить: {error}",
      "staticTestConnection": "Проверить соединение",
      "staticConnectionOk": "Соединение установлено",
      "staticConnectionFailed": "Ошибка соединения: {error}",
      "staticBrowseRepos": "Обзор",
      "staticBrowseBranches": "Выбрать ветку",
      "staticBrowseFolders": "Выбрать папку",
      "staticPickerRepoTitle": "Выбор репозитория",
      "staticPickerRepoPlaceholder": "Фильтр репозиториев…",
      "staticPickerBranchTitle": "Выбор ветки",
      "staticPickerBranchPlaceholder": "Фильтр веток…",
      "staticFolderRoot": "/ (корень)",
      "staticFolderSelectedPrefix": "Выбранная папка:",
      "staticTreeLoading": "Загрузка дерева папок…",
      "staticTreeEmpty": "В этой ветке нет папок.",
      "staticDenoAutoDetected": "Обнаружена папка <code>api/</code> — режим автоматически переключён на Deno.",
      "imageConflictTag": "ОБРАЗ УЖЕ ИСПОЛЬЗУЕТСЯ",
      "imageConflictChecking": "Проверка конфликтов…",
      "imageConflictHeading": "Этот образ уже используется в {count} нагрузке(ах):",
      "imageConflictOpenBtn": "Открыть",
      "imageConflictAcknowledgeNote": "Если это намеренно (например, отдельный этап), нажмите «Создать» ещё раз для продолжения.",
      "imageConflictBlockedSubmit": "Обнаружены конфликты по этому образу — изучите список выше и нажмите «Создать» повторно для продолжения.",
      "sourceConfigJsonTitle": "source_config.json · {kind}",
      "sourceConfigJsonAria": "Конфигурация source-плагина (JSON)",
      "triggerNumLabel": "Триггер",
      "triggerNumOptional": "ОПЦИОНАЛЬНО",
      "triggerNewTag": "НОВЫЙ",
      "triggerPickTag": "ВЫБРАТЬ",
      "triggerSkipTag": "ПРОПУСК",
      "noteSkipTag": "ПРОПУСК",
      "noteEmptyTag": "∅",
      "faceLabel": "Публичный фронт",
      "faceOptional": "ОПЦИОНАЛЬНО",
      "faceSubdomain": "Поддомен",
      "faceSubdomainPlaceholder": "myapp",
      "faceDomain": "Домен",
      "faceDomainPlaceholder": "(наследуется из настроек)",
      "facePort": "Целевой порт",
      "faceHint": "Оставьте пустым, чтобы не создавать прокси-маршрут. Заполнение любого поля создаст одну запись фронта, привязанную к этой нагрузке.",
      "cancel": "Отмена",
      "submit": "Создать приложение",
      "submitting": "Создание…",
      "submitAnyway": "Всё равно создать",
      "unsavedChanges": "В этом приложении есть несохранённые изменения. Покинуть страницу, не создавая его?",
      "unsavedChangesTitle": "Несохранённые изменения",
      "unsavedChangesConfirm": "Покинуть",
      "errors": {
        "detectionFailed": "Не удалось определить Git-провайдера по этому URL. Проверьте, что базовый URL верен и доступен.",
        "connectionFailed": "Не удалось подключиться к репозиторию. Проверьте URL провайдера, владельца/репозиторий и токен доступа (для приватных репозиториев).",
        "reposFailed": "Не удалось получить список репозиториев. Проверьте базовый URL и токен доступа.",
        "branchesFailed": "Не удалось получить список веток. Проверьте репозиторий и токен доступа.",
        "treeFailed": "Не удалось загрузить дерево папок. Проверьте репозиторий, ветку и токен доступа.",
        "sourceConfigInvalid": "source_config не является корректным JSON.",
        "triggerBindUnknown": "неизвестная ошибка",
        "createFailed": "Не удалось создать нагрузку.",
        "inspectFailed": "Не удалось проинспектировать образ — убедитесь, что он скачан локально и ссылка указана верно."
      },
      "imageInspect": "Инспектировать",
      "imageInspectHint": "Подставляет порт и healthcheck из образа, чтобы не вводить вручную.",
      "imageInspectOk": "Готово — порт и healthcheck подставлены.",
      "triggers": {
        "section": "Триггер",
        "sectionSub": "Необязательно. Выберите, откуда придёт сигнал передеплоя — слежение за реестром, git-событие или ручная кнопка.",
        "modeInline": "Создать триггер",
        "modeInlineHint": "Создаёт новую запись триггера, привязанную к этому приложению — подходит для частого случая 1:1.",
        "modePick": "Выбрать существующий",
        "modePickHint": "Привязать существующий триггер, чтобы несколько приложений делили один сигнал.",
        "modeSkip": "Пропустить — добавить позже",
        "modeSkipHint": "Приложение создаётся без привязки триггера. Ручной деплой по-прежнему работает.",
        "switchToPick": "Выбрать существующий →",
        "switchToInline": "← Создать новый триггер",
        "switchToSkip": "Пропустить",
        "pickPlaceholder": "Выберите триггер…",
        "pickEmpty": "Триггеров ещё нет — создайте один выше или перейдите в /triggers.",
        "pickLabel": "Существующий триггер",
        "pickHint": "Один триггер можно привязать к нескольким приложениям. Управление автономными триггерами — в /triggers.",
        "pickWebhookOn": "ВЕБХУК ВКЛ",
        "skippedNote": "Триггер не будет привязан. Добавьте его из панели «Триггеры» в карточке приложения после создания.",
        "bindError": "Приложение создано, но привязка триггера не удалась: {error}. Откройте панель «Триггеры» в карточке, чтобы повторить."
      },
      "manifest": {
        "title": "Манифест",
        "name": "Имя",
        "source": "Источник",
        "trigger": "Триггер",
        "publicFace": "Публичный фронт",
        "unnamed": "(без имени)",
        "registryPublic": "публичный реестр",
        "folderRoot": "корень",
        "triggerManual": "Только вручную",
        "internalOnly": "Только внутренний"
      }
    },
    "detail": {
      "pageTitleFallback": "Приложение",
      "backLabel": "К приложениям",
      "eyebrowSuffix": "ПРИЛОЖЕНИЕ",
      "kickerId": "id: {id}",
      "loading": "Загрузка нагрузки…",
      "loadError": "Не удалось загрузить приложение",
      "deployError": "Деплой не удался",
      "saveError": "Сохранение не удалось",
      "deleteError": "Удаление не удалось",
      "activity": {
        "title": "Активность",
        "subtitle": "Недавние деплои и события этого приложения",
        "empty": "Пока нет активности. Деплои и события появятся здесь.",
        "recentNote": "Показана недавняя активность.",
        "loadMore": "Загрузить ещё",
        "filterAll": "Все",
        "filterErrors": "Ошибки",
        "noErrors": "Нет ошибок в загруженной активности."
      },
      "runtimeState": {
        "title": "Статус синхронизации",
        "sub": "Последняя успешная синхронизация репозитория и текущее состояние контейнера.",
        "status": "Статус",
        "lastCommit": "Последний коммит",
        "lastSync": "Последняя синхронизация",
        "container": "Контейнер",
        "neverDeployed": "Ещё не разворачивалось. Нажмите «Деплой», чтобы опубликовать впервые.",
        "loading": "Загрузка состояния…"
      },
      "storage": {
        "title": "Постоянное хранилище",
        "sub": "Смонтировано в /app/data внутри контейнера.",
        "used": "Использовано",
        "limit": "Лимит",
        "unlimited": "без лимита",
        "unavailable": "Не удалось получить размер (контейнер мог быть остановлен).",
        "loading": "Вычисление размера…"
      },
      "buildLog": {
        "title": "Журнал сборки",
        "sub": "Живой поток вывода сборки Docker.",
        "clear": "Очистить"
      },
      "notifications": {
        "title": "Маршруты уведомлений",
        "sub": "Множественные точки доставки для событий деплоя/сборки. При пустом списке используется устаревший единственный URL.",
        "loading": "Загрузка маршрутов…",
        "empty": "Нет настроенных маршрутов уведомлений. Добавьте, чтобы получать события в отдельный канал.",
        "addFirst": "Добавить первый маршрут",
        "add": "Добавить маршрут",
        "edit": "Изменить",
        "delete": "Удалить",
        "name": "Имя",
        "namePlaceholder": "Slack #alerts",
        "url": "URL вебхука",
        "secret": "Секрет подписи",
        "secretPlaceholder": "Опционально — приёмник проверяет HMAC",
        "secretEditPlaceholder": "Оставьте пустым, чтобы сохранить текущий секрет",
        "secretHint": "HMAC-SHA256 от тела запроса, заголовок X-Hub-Signature-256.",
        "eventTypes": "Типы событий",
        "eventTypesPlaceholder": "deploy_failure,build_failure (пусто = все)",
        "eventTypesHint": "Список через запятую. Пусто — маршрут срабатывает на любое событие.",
        "enabled": "Включён",
        "save": "Сохранить",
        "saving": "Сохранение…",
        "cancel": "Отмена",
        "allEvents": "все события",
        "signed": "подписан",
        "disabled": "выключен",
        "confirmDeleteTitle": "Удалить маршрут уведомлений?",
        "confirmDeleteMessage": "Маршрут перестанет срабатывать. Устаревший URL уведомлений на workload (если задан) снова возьмёт события на себя."
      },
      "snapshots": {
        "title": "Снимки данных",
        "sub": "Сохранение host-bind томов данных приложения в виде загружаемого архива.",
        "loading": "Загрузка снимков…",
        "empty": "Снимков пока нет.",
        "coverage": "Будет сохранено томов: {count}.",
        "noCoverage": "Нет host-bind томов для снимка. Снимки доступны для приложений на основе образа с томами в области absolute, stage или project.",
        "liveWarning": "Снимок делается «на лету» — остановите приложение для полностью согласованной копии баз данных.",
        "skippedTitle": "Не удастся сохранить томов: {count}:",
        "labelPlaceholder": "Необязательная метка (напр. перед обновлением)",
        "create": "Создать снимок",
        "creating": "Сохранение…",
        "created": "Снимок создан.",
        "createFailed": "Не удалось создать снимок",
        "colLabel": "Метка",
        "colCreated": "Создан",
        "colVolumes": "Тома",
        "colSize": "Размер",
        "unlabeled": "(без метки)",
        "download": "Скачать",
        "delete": "Удалить",
        "deleted": "Снимок удалён.",
        "downloadFailed": "Не удалось скачать снимок",
        "deleteFailed": "Не удалось удалить снимок",
        "confirmDeleteTitle": "Удалить снимок?",
        "confirmDeleteMessage": "Архив снимка будет удалён безвозвратно. Это действие нельзя отменить."
      },
      "deployHistory": {
        "title": "История деплоев",
        "sub": "Все деплои этого приложения, новые сверху. Откатитесь, чтобы повторно развернуть предыдущую версию.",
        "loading": "Загрузка истории деплоев…",
        "empty": "Деплоев пока нет.",
        "colWhen": "Когда",
        "colReason": "Причина",
        "colReference": "Версия",
        "colOutcome": "Результат",
        "colBy": "Кем",
        "rollback": "Откатить",
        "rolledBack": "Откат до {ref}…",
        "rollbackFailed": "Не удалось откатить",
        "confirmTitle": "Откатиться к этой версии?",
        "confirmMessage": "Версия {ref} будет развёрнута заново. Текущая версия заменяется после успешной проверки отката."
      },
      "metrics": {
        "title": "Использование ресурсов",
        "sub": "CPU и память контейнеров этого приложения во времени.",
        "loading": "Загрузка метрик…",
        "empty": "Метрик пока нет. Сбор может быть отключён, или приложение работало слишком недолго для замера.",
        "windowLabel": "Период",
        "cpuSeries": "CPU",
        "memorySeries": "Память"
      },
      "gitops": {
        "title": "GitOps",
        "sub": "Опишите конфигурацию деплоя в репозитории и применяйте её по запросу.",
        "loading": "Загрузка статуса GitOps…",
        "disabledLead": "GitOps для этого приложения отключён.",
        "disabledSub": "Включите его, чтобы управлять конфигурацией деплоя из",
        "badge": "GitOps",
        "badgeTitle": "Конфигурация деплоя этого приложения управляется из репозитория.",
        "toggleLabel": "Включено",
        "toggleAria": "Включить GitOps для этого приложения",
        "toggleHint": "Читать конфигурацию деплоя из файла в репозитории приложения.",
        "enabledToast": "GitOps включён.",
        "disabledToast": "GitOps отключён.",
        "toggleFailed": "Не удалось обновить настройки GitOps.",
        "pillSynced": "Синхронизировано",
        "pillChangesOne": "1 изменение",
        "pillChangesMany": "изменений: {count}",
        "pillNoFile": "Нет файла",
        "pillFetchFailed": "Ошибка загрузки",
        "pillInvalid": "Некорректно",
        "pillDisabled": "Отключено",
        "metaPath": "Путь",
        "metaCommit": "Коммит",
        "metaLastSync": "Последняя синхр.",
        "metaNeverSynced": "Не синхронизировано",
        "inSyncTitle": "Текущая конфигурация совпадает с репозиторием",
        "inSyncSub": "Все объявленные поля уже применены. Синхронизировать нечего.",
        "driftAria": "Поля, отличающиеся между файлом в репозитории и текущей конфигурацией",
        "driftColField": "Поле",
        "driftColRepo": "Репозиторий",
        "driftColLive": "Текущее",
        "driftFoot": "Синхронизация применит значения из репозитория, заменив текущие выше.",
        "noFileLead": "В ветке нет файла конфигурации",
        "noFileSub": "GitOps включён, но ничего не найдено по пути",
        "fetchFailedLead": "Не удалось прочитать конфигурацию из репозитория",
        "invalidLead": "Конфигурацию из репозитория не удалось разобрать",
        "copy": "Копировать",
        "copied": "Скопировано",
        "copyAria": "Скопировать файл конфигурации в буфер обмена",
        "syncHintDrift": "Синхронизируйте, чтобы применить конфигурацию из репозитория к текущей.",
        "syncHintClean": "Текущая конфигурация уже совпадает с репозиторием.",
        "syncNow": "Синхронизировать",
        "syncing": "Синхронизация…",
        "syncedToast": "Применено полей: {count} из {sha}.",
        "syncFailed": "Ошибка синхронизации.",
        "confirmTitle": "Применить конфигурацию из репозитория?",
        "confirmMessage": "Конфигурация из репозитория будет применена к текущей конфигурации приложения. Текущие значения объявленных полей будут заменены.",
        "gateTitle": "Управляется через .tinyforge.yml",
        "gateBody": "Редактируйте конфигурацию в репозитории и синхронизируйте — изменения здесь будут перезаписаны при следующей синхронизации.",
        "gateFieldsLabel": "Управляемые поля",
        "field": {
          "port": "Порт",
          "healthcheck": "Healthcheck",
          "deploy_strategy": "Стратегия деплоя"
        }
      },
      "toolbar": {
        "stop": "Стоп",
        "start": "Старт",
        "openSite": "Открыть",
        "more": "Ещё"
      },
      "liveBadge": {
        "running": "РАБОТАЕТ",
        "transitioning": "ПЕРЕХОД",
        "stopped": "ОСТАНОВЛЕНО",
        "notDeployed": "НЕ РАЗВЁРНУТО",
        "mixed": "СМЕШАННО · {running}/{total} РАБОТАЕТ"
      },
      "stats": {
        "title": "Ресурсы",
        "sub": "CPU и память запущенного контейнера.",
        "subMany": "CPU и память по каждому из {count} контейнеров."
      },
      "webhooks": {
        "title": "Привязки вебхуков",
        "sub": "Триггеры, привязанные к приложению — управление URL и подписями на странице триггера.",
        "openTrigger": "Открыть триггер",
        "disabled": "отключён",
        "empty": "К приложению не привязан ни один триггер."
      },
      "errors": {
        "stopFailed": "Не удалось остановить.",
        "stopNothing": "Останавливать нечего — нет запущенного контейнера.",
        "stopAllFailed": "Остановка не удалась — все контейнеры отклонили запрос.",
        "startFailed": "Не удалось запустить.",
        "startNothing": "Запускать нечего — сначала выполните Деплой, чтобы создать контейнер.",
        "startAllFailed": "Запуск не удался — все контейнеры отклонили запрос.",
        "runtimeStateFailed": "Не удалось загрузить состояние.",
        "storageFailed": "Не удалось загрузить размер хранилища."
      },
      "alertTag": "ОШ",
      "createdAt": "создано",
      "refreshLabel": "Обновить",
      "editButton": "Изменить",
      "deleteButton": "Удалить",
      "editTitle": "Редактирование конфигурации",
      "editSubPrefix": "Источник",
      "editSubSuffix": "· триггеры настраиваются в панели «Триггеры» ниже",
      "editFieldName": "Имя",
      "editFieldParent": "Родительская нагрузка",
      "editFieldOptional": "ОПЦИОНАЛЬНО",
      "editFieldParentPlaceholder": "UUID нагрузки (пусто для корневой)",
      "editSourceConfig": "Конфигурация источника",
      "editConfigYaml": "YAML",
      "editConfigForm": "ФОРМА",
      "editConfigJson": "JSON",
      "advancedJson": "Расширенный JSON",
      "backToForm": "К форме",
      "switchToJsonTitle": "Переключиться на сырой JSON-редактор",
      "switchToFormTitle": "Вернуться к форме",
      "jsonOk": "JSON ОК",
      "jsonInvalid": "JSON НЕВЕРНЫЙ",
      "editComposeProject": "Имя compose-проекта (опционально)",
      "editComposeProjectPlaceholder": "(по умолчанию — нормализованное имя нагрузки)",
      "editComposePlaceholder": "services:\n  web:\n    image: nginx:alpine",
      "editComposeAria": "Compose YAML",
      "editComposeHeader": "compose.yaml",
      "editImageHeader": "image-источник · параметры рантайма",
      "editImageRef": "Образ (путь в реестре)",
      "editImageRefPlaceholder": "registry.example.com/owner/app",
      "editImagePort": "Порт",
      "editImageHealthcheck": "Путь healthcheck",
      "editImageDefaultTag": "Тег по умолчанию",
      "editImageRegistry": "Реестр (для приватных pull-ов)",
      "editImageRegistryPublic": "(публичный — без авторизации)",
      "editImageCpu": "Лимит CPU (ядра, 0 = ∞)",
      "editImageMemory": "Лимит памяти (МБ, 0 = ∞)",
      "editImageMax": "Макс. инстансов",
      "editImageFoot": "Переменные окружения и тома живут в своих панелях ниже — сохранение здесь их не затронет.",
      "editStaticHeader": "static-источник · страницы из репозитория",
      "editStaticProvider": "Провайдер",
      "editStaticBaseUrl": "Base URL",
      "editStaticBaseUrlPlaceholder": "https://git.example.com",
      "editStaticRepoOwner": "Владелец репозитория",
      "editStaticRepoName": "Имя репозитория",
      "editStaticBranch": "Ветка",
      "editStaticFolder": "Папка (опционально)",
      "editStaticFolderPlaceholder": "(корень репозитория)",
      "editStaticToken": "Токен доступа (приватные репозитории)",
      "editStaticTokenPlaceholder": "(оставьте пустым для публичных репозиториев)",
      "editStaticMode": "Режим",
      "editStaticModeStaticDesc": "— раздача файлов через nginx.",
      "editStaticModeDenoDesc": "— Deno-рантайм с динамической маршрутизацией.",
      "editStaticRenderMarkdown": "Рендерить markdown",
      "editStaticRenderMarkdownDesc": "— автоматически отдавать <code>.md</code> как HTML.",
      "editDockerfileHeader": "dockerfile-источник · сборка из git-репозитория",
      "editDockerfileBuildEyebrow": "сборка · dockerfile",
      "editDockerfileContextPath": "Контекст сборки",
      "editDockerfileContextPathPlaceholder": "(пусто = корень репо)",
      "editDockerfilePath": "Путь к Dockerfile",
      "editDockerfilePort": "Порт контейнера",
      "editTestConnection": "Проверить соединение",
      "editTestConnectionOk": "Соединение установлено",
      "editTestConnectionFailed": "Ошибка соединения: {error}",
      "editTestConnectionUnknownError": "Неизвестная ошибка",
      "overrideKeyUnitSingular": "КЛЮЧ",
      "overrideKeyUnitPlural": "КЛЮЧИ",
      "editTestConnectionIncomplete": "Заполните провайдера, base URL, owner и name.",
      "editSourceJsonHeader": "source_config.json",
      "editSourceJsonAria": "Конфигурация source-плагина (JSON)",
      "editPublicFaces": "Публичные фронты",
      "editPublicFacesTag": "JSON МАССИВ",
      "editPublicFacesHeader": "public_faces.json",
      "editPublicFacesAria": "Конфигурация публичных фронтов (JSON-массив)",
      "editCancel": "Отмена",
      "editSave": "Сохранить",
      "editSaving": "Сохранение…",
      "manualDeployTitle": "Ручной деплой",
      "manualDeployOk": "ОК",
      "manualDeployDispatched": "Отправлено {reference} как {by}",
      "manualDeployRefAria": "Референс для деплоя",
      "manualDeployRefPlaceholder": "референс (тег образа, git sha; пусто — по умолчанию)",
      "manualDeployButton": "Деплой",
      "manualDeployDispatching": "Отправка…",
      "manualDeployHint": "Задайте конкретный тег образа, git sha или ветку, чтобы принудительно деплоить. Оставьте пустым, чтобы source-плагин выбрал референс по умолчанию.",
      "containersTitle": "Контейнеры",
      "containersEmpty": "Контейнеров пока нет",
      "containersCount": "{count} согласовано",
      "containersEmptyInline": "Контейнеров пока нет — задеплойте, чтобы поднять первый.",
      "containersColRole": "Роль",
      "containersColState": "Состояние",
      "containersColImage": "Образ",
      "containersColSubdomain": "Поддомен",
      "containersColLastSeen": "Последний раз виден",
      "containersColActions": "Действия",
      "containersLogsAction": "Логи",
      "chainTitle": "Цепочка",
      "chainSubFromParent": "продвигается от родителя",
      "chainSubParentOf": "родитель для",
      "chainChildSingular": "дочерней нагрузки",
      "chainChildPlural": "дочерних нагрузок",
      "chainParentLabel": "Родитель",
      "chainSelfLabel": "Эта",
      "chainChildrenLabel": "Дочерние",
      "chainPromoteButton": "Продвинуть от родителя",
      "chainPromoteToChild": "Продвинуть сюда",
      "chainPromoting": "Продвижение…",
      "chainPromoteConfirmTitle": "Продвинуть версию?",
      "chainPromoteConfirmMessage": "Продвинуть запущенную версию {source} в {target} и развернуть её?",
      "chainPromoteConfirmYes": "Продвинуть и развернуть",
      "chainPromoteOk": "Версия {tag} продвинута в {target}",
      "chainPromoteFailed": "Не удалось продвинуть",
      "chainHint": "Задайте <code>parent_workload_id</code> у нагрузки, чтобы построить цепочку. Дочерние image-источники могут одним кликом продвинуть текущий запущенный тег родителя.",
      "previews": {
        "title": "Превью-окружения",
        "subEmpty": "нет активных превью",
        "subCountOne": "1 активное превью",
        "subCount": "активных превью: {count}",
        "tag": "Превью",
        "tagTitle": "Превью-развёртывание этой нагрузки для отдельной ветки",
        "armedEmpty": "Нет активных превью — отправьте пуш в ветку, соответствующую шаблону",
        "noneEmpty": "Пока нет активных превью.",
        "open": "Открыть",
        "noUrl": "нет публичного URL",
        "teardown": "Удалить",
        "teardownTitle": "Удалить превью?",
        "teardownMessage": "Это удалит превью для ветки «{name}» вместе с его контейнерами и маршрутами прокси. Новый пуш в эту ветку создаст его заново.",
        "teardownConfirm": "Удалить",
        "teardownPending": "Удаление…",
        "teardownFailed": "Не удалось удалить",
        "stateRunning": "Работает",
        "statePending": "Запускается",
        "stateStopped": "Остановлено",
        "stateUnknown": "Неизвестно",
        "hint": "Превью создаются автоматически, когда пуш приходит в ветку, соответствующую <code>branch_pattern</code> git-триггера, и удаляются при удалении ветки. Каждое получает собственный поддомен с префиксом-слагом."
      },
      "volumesTitle": "Тома",
      "volumesEmpty": "Нет монтирований",
      "volumesCountSingular": "{count} монтирование",
      "volumesCountPlural": "{count} монтирований",
      "volumesColTarget": "Цель",
      "volumesColSource": "Источник",
      "volumesColScope": "Скоуп",
      "volumesColUpdated": "Обновлено",
      "volumesColActions": "Действия",
      "volumeSource": "Источник (хост)",
      "volumeSourcePlaceholder": "/srv/data/myapp",
      "volumeTarget": "Цель (контейнер)",
      "volumeTargetPlaceholder": "/data",
      "volumeScope": "Скоуп",
      "volumeAddButton": "Добавить / Заменить",
      "volumeSaving": "Сохранение…",
      "volumeHint": "Абсолютные монтирования прокидывают путь хоста в контейнер. Другие скоупы приняты для будущих сценариев; сегодня при деплое применяется только absolute.",
      "volumeTargetError": "Цель должна быть абсолютным путём в контейнере (например, /data)",
      "volumeSetFailed": "Не удалось задать том",
      "volumeDeleteFailed": "Не удалось удалить том",
      "envTitle": "Окружение",
      "envEmpty": "Нет переопределений",
      "envCountSingular": "{count} переопределение",
      "envCountPlural": "{count} переопределений",
      "envColKey": "Ключ",
      "envColValue": "Значение",
      "envColUpdated": "Обновлено",
      "envColActions": "Действия",
      "envEncrypted": "ЗАШИФРОВАНО",
      "envKey": "Ключ",
      "envKeyPlaceholder": "DATABASE_URL",
      "envValue": "Значение",
      "envValuePlaceholder": "(пусто — снять)",
      "envEncryptLabel": "Шифровать при хранении",
      "envAddButton": "Добавить / Заменить",
      "envSaving": "Сохранение…",
      "envHint": "Зашифрованные значения после записи доступны только на запись — API скрывает их при чтении. Ротация — установка нового значения.",
      "envKeyRequired": "Ключ обязателен",
      "envSetFailed": "Не удалось задать переменную",
      "envDeleteFailed": "Не удалось удалить переменную",
      "sourceConfigTitle": "Конфигурация источника",
      "sourceConfigCopy": "Копировать",
      "sourceConfigCopied": "Скопировано",
      "sourceConfigCopyAria": "Копировать конфиг источника",
      "publicFacesTitle": "Публичные фронты",
      "publicFacesCopyAria": "Копировать публичные фронты",
      "deleteConfirmTitle": "Удалить это приложение?",
      "deleteConfirmMessage": "Сносит все контейнеры и прокси-маршруты, принадлежащие «{name}», затем удаляет запись. Это нельзя отменить.",
      "deleteConfirmFallbackName": "эта нагрузка",
      "deleteConfirmYes": "Да, удалить",
      "deleteConfirmDeleting": "Удаление…",
      "manualDeploySub": "Обходит настроенные триггеры и отправляет деплой напрямую через source-плагин.",
      "chainTriggersZero": "без триггеров",
      "chainTriggersOne": "1 триггер",
      "chainTriggersMany": "{count} триггер(ов)",
      "bindings": {
        "title": "Триггеры",
        "subEmpty": "Триггеры не привязаны. Ручной деплой работает — добавьте триггер, чтобы подключить передеплой по реестру / git / вебхуку.",
        "subCount": "{count} привязанный триггер",
        "subCountMany": "{count} привязанных триггеров",
        "addButton": "Добавить триггер",
        "openTrigger": "Открыть триггер",
        "unbindAction": "Отвязать",
        "rowEnabled": "Включён",
        "rowDisabled": "Выключен",
        "rowEnableHint": "Отключите, чтобы сохранить привязку, но остановить передеплой этого приложения.",
        "loading": "Загрузка триггеров…",
        "loadError": "Не удалось загрузить привязки триггеров",
        "unbindTitle": "Отвязать триггер?",
        "unbindMessage": "Триггер «{name}» перестанет передеплоить это приложение. Сам триггер не удаляется — он остаётся в /triggers и сохраняет привязки к другим приложениям.",
        "unbindConfirm": "Отвязать",
        "modal": {
          "title": "Добавить триггер",
          "subtitle": "Привяжите триггер к этому приложению — создайте новый или выберите существующий, чтобы делить его.",
          "tabInline": "Создать новый",
          "tabPick": "Выбрать существующий",
          "submitInline": "Создать и привязать",
          "submitPick": "Привязать",
          "submitting": "Привязка…",
          "cancel": "Отмена",
          "error": "Не удалось привязать",
          "pickPlaceholder": "Выберите триггер…",
          "pickEmpty": "Триггеров ещё нет — переключитесь на «Создать новый», чтобы добавить.",
          "pickLabel": "Существующий триггер",
          "pickKind": "Фильтр по виду",
          "pickKindAll": "Все виды"
        },
        "override": {
          "toggle": "Переопределить",
          "title": "Переопределения привязки",
          "subtitle": "Переопределите поля конфига триггера только для этого приложения. Верхнеуровневые ключи отсюда побеждают; остальное наследуется из триггера.",
          "badgeOne": "ПЕРЕОПРЕДЕЛЕНО: 1 ПОЛЕ",
          "badgeMany": "ПЕРЕОПРЕДЕЛЕНО ПОЛЕЙ: {count}",
          "badgeTitle": "Эта привязка переопределяет одно или несколько полей конфига триггера.",
          "baseLabel": "Конфиг триггера",
          "baseLoading": "Загрузка конфига триггера…",
          "baseHint": "Конфиг родительского триггера в режиме чтения. Редактируйте его на странице триггера, если изменения нужны для всех привязок.",
          "editLabel": "Переопределение (JSON-объект)",
          "editHint": "Слияние по верхнему уровню: переопределяются только указанные здесь ключи. Оставьте {} — будет наследоваться без изменений.",
          "previewLabel": "Итоговый конфиг",
          "previewHint": "Предпросмотр того, что увидит эта привязка при срабатывании триггера (конфиг триггера + наложенное переопределение).",
          "invalidJson": "Переопределение должно быть JSON-объектом.",
          "tooLarge": "Размер переопределения — {size} Б, превышает серверный лимит {limit} Б.",
          "errInvalidJson": "Нельзя сохранить: переопределение не является валидным JSON-объектом.",
          "errTooLarge": "Нельзя сохранить: переопределение превышает серверный лимит 8 КиБ.",
          "saveButton": "Сохранить переопределение",
          "saving": "Сохранение…",
          "resetButton": "Сбросить к наследованию",
          "closeButton": "Закрыть"
        }
      }
    }
  }
}
