{
"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": "Контейнеры"
},
"dashboard": {
"title": "Панель управления",
"newApp": "Новое приложение",
"totalWorkloads": "Всего нагрузок",
"runningContainers": "Запущенных контейнеров",
"failedContainers": "Сбойных контейнеров",
"recentWorkloads": "Недавние нагрузки",
"retry": "Повторить",
"noWorkloads": "Нагрузок пока нет.",
"noWorkloadsDesc": "Создайте приложение и выкуйте первую нагрузку, чтобы начать.",
"loadFailed": "Не удалось загрузить панель",
"staleContainers": "Устаревшие контейнеры",
"unusedImagesWarning": "Неиспользуемые Docker-образы занимают дисковое пространство",
"unusedImages": "неиспользуемых образов",
"systemHealth": "Состояние системы",
"daemons": "Демоны",
"systemResources": "Системные ресурсы",
"systemResourcesSubtitle": "CPU, память, диск и топ потребителей"
},
"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": "Не удалось загрузить реестры",
"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": "Вы уверены, что хотите удалить этого пользователя?",
"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": "Подтвердить",
"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": {
"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": "Устаревшие контейнеры",
"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": "Развёртывание",
"static_site": "Статический сайт",
"stale_scanner": "Сканер устаревших",
"stale_cleanup": "Очистка устаревших",
"admin": "Администратор"
},
"metadata": "Подробности"
},
"stats": {
"cpu": "ЦП",
"mem": "ОЗУ",
"unavailable": "Статистика недоступна"
},
"systemHealth": {
"title": "Состояние системы",
"containers": "Контейнеры",
"proxies": "Прокси",
"recentErrors": "Недавние ошибки"
},
"daemons": {
"title": "Демоны",
"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 ловит новые теги, выкладываемые под этой ссылкой.",
"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'и, продвигающие эту ветку, дёргают триггер.",
"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",
"backLabel": "К приложениям",
"eyebrowSuffix": "НОВОЕ ПРИЛОЖЕНИЕ",
"title": "Создать приложение",
"ledePrefix": "Создайте plugin-native нагрузку.",
"ledeSourceLabel": "Источник",
"ledeSourceMid": "= как она деплоится (image, compose, static). Выберите или создайте",
"ledeTriggerLabel": "триггер",
"ledeSuffix": "ниже — при срабатывании source-плагин передеплоит приложение.",
"loadingKinds": "Загрузка доступных видов плагинов…",
"alertTag": "ОШ",
"fieldName": "Имя",
"fieldNameRequired": "ОБЯЗАТЕЛЬНО",
"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 (ядра, 0 = ∞)",
"imageMemory": "Лимит памяти (МБ, 0 = ∞)",
"imageMax": "Макс. инстансов",
"imageMaxHint": "1 = строгий blue-green.",
"imageFoot": "Переменные окружения и тома задаются в отдельных панелях на странице нагрузки после создания.",
"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": "— автоматически отдавать .md файлы как HTML-страницы.",
"staticFoot": "Секрет вебхука для git push-триггеров появляется в панели вебхука нагрузки после создания.",
"staticDetectProvider": "Определить",
"staticDetectedOk": "Определено: {provider}",
"staticDetectedFailed": "Не удалось определить: {error}",
"staticTestConnection": "Проверить соединение",
"staticConnectionOk": "Соединение установлено",
"staticConnectionFailed": "Ошибка соединения: {error}",
"staticBrowseRepos": "Выбрать репозиторий",
"staticBrowseBranches": "Выбрать ветку",
"staticBrowseFolders": "Выбрать папку",
"staticPickerRepoTitle": "Выбор репозитория",
"staticPickerRepoPlaceholder": "Фильтр репозиториев…",
"staticPickerBranchTitle": "Выбор ветки",
"staticPickerBranchPlaceholder": "Фильтр веток…",
"staticFolderRoot": "/ (корень)",
"staticFolderSelectedPrefix": "Выбранная папка:",
"staticTreeLoading": "Загрузка дерева папок…",
"staticTreeEmpty": "В этой ветке нет папок.",
"staticDenoAutoDetected": "Обнаружена папка api/ — режим автоматически переключён на Deno.",
"imageConflictTag": "ОБРАЗ УЖЕ ИСПОЛЬЗУЕТСЯ",
"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": "Всё равно создать",
"errors": {
"detectionFailed": "Не удалось определить провайдера.",
"connectionFailed": "Ошибка соединения.",
"reposFailed": "Не удалось загрузить репозитории.",
"branchesFailed": "Не удалось загрузить ветки.",
"treeFailed": "Не удалось загрузить дерево папок.",
"sourceConfigInvalid": "source_config не является корректным JSON.",
"triggerBindUnknown": "неизвестная ошибка",
"createFailed": "Не удалось создать нагрузку.",
"inspectFailed": "Не удалось проинспектировать образ."
},
"imageInspect": "Инспектировать",
"imageInspectHint": "Подставляет порт и healthcheck из образа, чтобы не вводить вручную.",
"imageInspectOk": "Готово — порт и healthcheck подставлены.",
"imageInspectError": "Ошибка инспекции: {error}",
"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}. Откройте панель «Триггеры» в карточке, чтобы повторить."
}
},
"detail": {
"pageTitleFallback": "Приложение",
"backLabel": "К приложениям",
"eyebrowSuffix": "ПРИЛОЖЕНИЕ",
"kickerId": "id: {id}",
"loading": "Загрузка нагрузки…",
"loadError": "Не удалось загрузить приложение",
"deployError": "Деплой не удался",
"saveError": "Сохранение не удалось",
"deleteError": "Удаление не удалось",
"runtimeState": {
"title": "Статус синхронизации",
"sub": "Последняя успешная синхронизация репозитория и текущее состояние контейнера.",
"status": "Статус",
"lastCommit": "Последний коммит",
"lastSync": "Последняя синхронизация",
"container": "Контейнер",
"neverDeployed": "Ещё не разворачивалось. Нажмите «Деплой», чтобы опубликовать впервые.",
"loading": "Загрузка состояния…"
},
"storage": {
"title": "Постоянное хранилище",
"sub": "Смонтировано в /app/data внутри контейнера.",
"used": "Использовано",
"limit": "Лимит",
"unlimited": "без лимита",
"unavailable": "Не удалось получить размер (контейнер мог быть остановлен).",
"loading": "Вычисление размера…"
},
"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": "— автоматически отдавать .md как HTML.",
"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": "Задайте parent_workload_id у нагрузки, чтобы построить цепочку. Дочерние image-источники могут одним кликом продвинуть текущий запущенный тег родителя.",
"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": "Закрыть"
}
}
}
}
}