cdb9fd57d1
Operators can define metric-threshold alert rules (cpu_percent, memory_percent, memory_bytes; gt/lt) per-workload or global via /api/metric-alert-rules. A periodic evaluator (internal/metricalert, 30s tick) checks the freshest container stats sample per container against enabled rules and, on breach (per-rule-per-workload cooldown), emits into the existing event_log + bus pipeline (source "metric_alert", workload_id set). Alerts therefore surface on the global events page, the per-app activity timeline, and any configured event-trigger webhook -- no new notification plumbing. Mirrors the log_scan_rules store/API/route patterns and the stats.Collector lifecycle. Rule CRUD reads are authed, mutations AdminOnly. Frontend rule-config UI is a follow-up phase. Reviewed: go APPROVE (0 CRITICAL/HIGH).
1755 lines
113 KiB
JSON
1755 lines
113 KiB
JSON
{
|
||
"app": {
|
||
"name": "Tinyforge",
|
||
"version": "v0.1"
|
||
},
|
||
"layout": {
|
||
"serviceStatus": "Состояние служб"
|
||
},
|
||
"health": {
|
||
"connected": "подключён",
|
||
"disconnected": "отключён",
|
||
"rawError": "Технические детали",
|
||
"retryNow": "Проверить сейчас"
|
||
},
|
||
"nav": {
|
||
"dashboard": "Панель",
|
||
"apps": "Приложения",
|
||
"eventTriggers": "Триггеры событий",
|
||
"logScanRules": "Лог-правила",
|
||
"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": "Не удалось очистить образы",
|
||
"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": "выключен"
|
||
}
|
||
},
|
||
"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": "Открыть"
|
||
},
|
||
"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-провайдер как статус коммита для развёрнутого коммита.",
|
||
"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 (если задан) снова возьмёт события на себя."
|
||
},
|
||
"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": "Продвинуть от родителя",
|
||
"chainPromoting": "Продвижение…",
|
||
"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": "Закрыть"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|