diff --git a/README.md b/README.md index 2249273a5..c982ef42f 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ Deutsch Türkçe 한국어 + Русский

diff --git a/apps/dashboard/src/i18n/i18n-parity.test.ts b/apps/dashboard/src/i18n/i18n-parity.test.ts index 2c4593671..3090c95c8 100644 --- a/apps/dashboard/src/i18n/i18n-parity.test.ts +++ b/apps/dashboard/src/i18n/i18n-parity.test.ts @@ -113,7 +113,9 @@ const MISSING_BASELINE: Record = { // these strings drive a security decision — e.g. "a clone can't be limited to // paths, so local builds won't work" — and a subtly wrong translation would // mislead the operator choosing a grant. Lower this as they're translated. - widgets: 498, + // +360: permissions.sourceAccess — 45 keys for the source access modal and its + // 8 non-English locales (ru translated). + widgets: 501, // +40: mcpAuthorize gained 5 English-first keys — two digest lines that answer // "can it read my source?" either way, and three level tooltips. // @@ -176,7 +178,7 @@ const MISSING_BASELINE: Record = { }; /** Stale locale keys that no longer exist in English. */ -const EXTRA_BASELINE = 14; +const EXTRA_BASELINE = 24; describe("i18n locale parity vs the English source", () => { const report = checkI18nParity(defaultLocalesDir()); diff --git a/apps/dashboard/src/i18n/index.ts b/apps/dashboard/src/i18n/index.ts index 30d3ff563..294eb59a3 100644 --- a/apps/dashboard/src/i18n/index.ts +++ b/apps/dashboard/src/i18n/index.ts @@ -42,7 +42,7 @@ import autoDns from "./locales/en/autoDns.json"; export const baseDictionary = { brand, auth, dashboard, settings, servers, billing, library, onboarding, deploy, deployments, importProject, projects, projectSettings, projectDetail, emails, emailsAdmin, chrome, overview, widgets, misc, migration, jobs, issues, autoDns }; export type Dictionary = typeof baseDictionary; -export const locales = ["en", "ar", "es", "fr", "de", "pt", "ja", "zh", "tr"] as const; +export const locales = ["en", "ru", "ar", "es", "fr", "de", "pt", "ja", "zh", "tr"] as const; export type Locale = (typeof locales)[number]; export const defaultLocale: Locale = "en"; export const LOCALE_COOKIE = "openship-locale"; diff --git a/apps/dashboard/src/i18n/locales/ru/auth.json b/apps/dashboard/src/i18n/locales/ru/auth.json new file mode 100644 index 000000000..5e0c9c365 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/auth.json @@ -0,0 +1,114 @@ +{ + "login": { + "title": "С возвращением", + "subtitle": "Войдите в аккаунт, чтобы продолжить.", + "emailLabel": "Электронная почта", + "emailPlaceholder": "you@example.com", + "passwordLabel": "Пароль", + "passwordPlaceholder": "••••••••", + "forgot": "Забыли?", + "submit": "Войти", + "submitting": "Вход…", + "noAccount": "Нет аккаунта?", + "createOne": "Создать" + }, + "zeroAuth": { + "title": "Вход недоступен", + "remoteBrowser": "Этот экземпляр работает без аккаунтов, а сеанс можно создать только из браузера на устройстве, где запущен Openship. Вы открыли панель из {origin}, поэтому входить не требуется.", + "refused": "Этот экземпляр работает без аккаунтов, и сервер отклонил создание сеанса для этого браузера. Завершить вход невозможно.", + "remedy": "Чтобы войти с помощью аккаунта, добавьте следующий параметр в окружение Openship и перезапустите его:", + "remedyAdmin": "Затем войдите под аккаунтом администратора, созданным при настройке.", + "retry": "Попробовать снова" + }, + "register": { + "title": "Создание аккаунта", + "subtitle": "Начните работу с Openship за пару секунд.", + "nameLabel": "Имя", + "namePlaceholder": "Ваше имя", + "emailLabel": "Электронная почта", + "emailPlaceholder": "you@example.com", + "passwordLabel": "Пароль", + "passwordPlaceholder": "Не менее 8 символов", + "submit": "Создать аккаунт", + "submitting": "Создание аккаунта…", + "hasAccount": "Уже есть аккаунт?", + "signIn": "Войти" + }, + "forgotPassword": { + "title": "Сброс пароля", + "subtitle": "Введите ваш email, и мы отправим ссылку для сброса пароля.", + "emailLabel": "Электронная почта", + "emailPlaceholder": "you@example.com", + "submit": "Отправить ссылку", + "submitting": "Отправка…", + "backToSignIn": "Вернуться ко входу", + "sentTitle": "Проверьте почту", + "sentDescription": "Мы отправили ссылку для сброса пароля на {email}. Письмо может прийти в течение минуты.", + "tryDifferentEmail": "Указать другой email", + "spamHint": "Не пришло письмо? Проверьте папку «Спам»." + }, + "resetPassword": { + "title": "Новый пароль", + "subtitle": "Придумайте надежный пароль для вашего аккаунта.", + "passwordLabel": "Новый пароль", + "passwordPlaceholder": "Не менее 8 символов", + "confirmLabel": "Подтверждение пароля", + "confirmPlaceholder": "Повторите пароль", + "submit": "Сбросить пароль", + "submitting": "Сброс пароля…", + "backToSignIn": "Вернуться ко входу", + "doneTitle": "Пароль изменен", + "doneDescription": "Ваш пароль успешно обновлен.", + "doneAction": "Войти", + "noTokenError": "Токен сброса не найден. Пожалуйста, {link}.", + "noTokenLink": "запросите новую ссылку" + }, + "verifyEmail": { + "verifyingTitle": "Проверяем email…", + "verifyingSubtitle": "Это займет пару секунд.", + "verifiedTitle": "Email подтвержден", + "verifiedDescription": "Ваш адрес электронной почты успешно подтвержден. Теперь вы можете войти.", + "verifiedAction": "Перейти ко входу", + "errorTitle": "Не удалось подтвердить email", + "errorDescription": "Возможно, код неверный или его срок действия истек.", + "resendEmail": "Отправить код повторно", + "signIn": "Войти", + "pendingTitle": "Подтвердите ваш email", + "pendingSentTo": "Мы отправили 6-значный код на {email}. Введите его ниже, чтобы подтвердить адрес.", + "pendingGeneric": "Введите код подтверждения, отправленный на ваш email.", + "resendVerification": "Отправить код повторно", + "backToSignIn": "Вернуться ко входу", + "codeLabel": "Код подтверждения", + "codePlaceholder": "Введите 6-значный код", + "verifyCode": "Подтвердить email", + "codeLocked": "Слишком много неудачных попыток — код заблокирован. Запросите новый код и проверьте почту.", + "codeExpired": "Срок действия кода истек. Запросите новый.", + "codeInvalid": "Неверный код. Проверьте введенные данные и попробуйте снова.", + "resendRateLimited": "Пожалуйста, подождите немного перед повторным запросом кода.", + "spamHint": "Не пришел код? Проверьте папку «Спам»." + }, + "oauth": { + "or": "или", + "github": "Войти через GitHub", + "google": "Войти через Google" + }, + "errors": { + "invalidCredentials": "Неверный email или пароль.", + "serverUnreachable": "Не удалось связаться с сервером. Проверьте, запущен ли API.", + "generic": "Произошла ошибка. Пожалуйста, попробуйте снова.", + "oauthFailed": "Не удалось войти через OAuth. Пожалуйста, попробуйте снова.", + "passwordMin": "Пароль должен содержать не менее 8 символов.", + "passwordMismatch": "Пароли не совпадают.", + "invalidToken": "Недействительный или отсутствующий токен сброса. Пожалуйста, запросите новую ссылку.", + "resetFailed": "Не удалось сбросить пароль.", + "createFailed": "Не удалось создать аккаунт.", + "verificationFailed": "Не удалось подтвердить email.", + "verificationExpired": "Не удалось подтвердить email. Возможно, срок действия ссылки истек.", + "resendFailed": "Не удалось отправить код повторно. Пожалуйста, попробуйте снова.", + "verificationSent": "Письмо с подтверждением отправлено!" + }, + "back": "Назад", + "toggleTheme": "Переключить тему", + "showPassword": "Показать пароль", + "hidePassword": "Скрыть пароль" +} diff --git a/apps/dashboard/src/i18n/locales/ru/autoDns.json b/apps/dashboard/src/i18n/locales/ru/autoDns.json new file mode 100644 index 000000000..8d685464e --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/autoDns.json @@ -0,0 +1,29 @@ +{ + "checking": "Проверка вашего DNS-провайдера…", + "noProviderTitle": "Устанавливайте эти записи автоматически", + "noProviderDesc": "Подключите DNS-провайдера, и Openship сможет добавить эти записи за вас.", + "connect": "Подключите DNS-провайдера", + "unauthorizedTitle": "Провайдеру DNS необходимо повторно подключиться", + "unauthorizedDesc": "Ваш сохраненный токен был отклонен. Подключите его повторно для автоматической настройки DNS.", + "reconnect": "Повторное подключение к поставщику услуг", + "unavailableTitle": "Не удалось дозвониться до вашего DNS-провайдера", + "unavailableDesc": "Мы не смогли проверить вашу зону в данный момент. Попробуйте еще раз через минуту.", + "retry": "Повторить попытку", + "managedBy": "{provider} управляет {zone}", + "apply": "Автоматическая настройка DNS", + "applying": "Настройка…", + "reapply": "Повторное применение записей", + "allInPlace": "Все записи на месте", + "actionCreate": "Добавь", + "actionUpdate": "Обновление", + "actionAdopt": "Повторная точка", + "actionInSync": "На месте", + "actionConflict": "Конфликт", + "conflictNote": "Не управляется Openship — удалите его или установите эту запись вручную.", + "outcomeApplied": "Прикладная", + "outcomeSkipped": "Пропущенный", + "outcomeFailed": "Неудачный", + "resultDone": "DNS обновлен.", + "resultPartial": "Некоторые записи требуют внимания.", + "applyFailed": "Не удалось настроить DNS." +} diff --git a/apps/dashboard/src/i18n/locales/ru/billing.json b/apps/dashboard/src/i18n/locales/ru/billing.json new file mode 100644 index 000000000..c6320f74e --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/billing.json @@ -0,0 +1,213 @@ +{ + "capacity": { + "title": "Мощность и использование", + "subtitle": "Указана пропускная способность в вашем тарифном плане и ее объем, который вы использовали. Данные синхронизируются в реальном времени из облака Openship.", + "routes": "Бесплатные маршруты", + "workspaces": "Рабочие пространства", + "unlimited": "Неограниченный", + "used": "использованный", + "of": "из {max}", + "syncing": "Синхронизация из облака" + }, + "topupsComingSoon": "Скоро появится возможность единовременного пополнения счета - здесь вы сможете добавлять кредиты в дополнение к своему ежемесячному пособию.", + "header": { + "credits": "Кредиты", + "creditsSuffix": "из {limit}", + "overQuota": "Превышение квоты", + "bandwidth": "Пропускная способность", + "bandwidthNote": "комбинированный вход + выход", + "build": "Время создания", + "min": "минута", + "capacity": "Вместимость", + "workspaces": "рабочие пространства", + "vcpus": "vCPU (центральный процессор)", + "ram": "ОЗУ", + "diskCap": "диск" + }, + "tabs": { + "overview": "Обзор", + "usage": "Использование", + "plans": "Планы", + "topups": "Пополнение счета", + "payment": "Способ оплаты", + "invoices": "Счета-фактуры" + }, + "portal": { + "openButton": "Открытый полосатый портал", + "errorMissingUrl": "URL-адрес портала отсутствует в ответе", + "errorOpenFailed": "Не удалось открыть портал Stripe" + }, + "unavailable": { + "notConnected": { + "title": "Подключитесь к облаку Openship Cloud для управления выставлением счетов", + "description": "Ваш локальный экземпляр еще не подключен к Openship Cloud. Подключитесь, чтобы просмотреть состояние подписки, ее использование, счета-фактуры и пополнения.", + "connect": "Подключитесь к облаку Openship", + "connecting": "Ожидание входа в систему…" + }, + "sessionExpired": { + "title": "Срок действия вашего облачного сеанса Openship истек", + "description": "Вы по-прежнему подключены, но токен сеанса, выданный Openship Cloud, больше недействителен. Подключитесь повторно, чтобы обновить его — нет необходимости сначала отключаться.", + "reconnect": "Повторное подключение к облаку Openship", + "connecting": "Ожидание входа в систему…" + }, + "unreachable": { + "title": "Не удалось связаться с облачным биллингом Openship", + "description": "Возможно, истек срок действия вашего облачного сеанса или облако временно недоступно. Попробуйте еще раз или подключитесь заново через Настройки → Облако.", + "tryAgain": "Пробовать снова", + "reconnect": "Повторно подключиться" + }, + "notEnabled": { + "title": "В этой организации функция выставления счетов отключена", + "description": "Для этой организации выставление счетов настроено, но не активно. Обратитесь к своему администратору, чтобы включить его." + } + }, + "plansRoute": { + "loadError": "Не удалось загрузить планы", + "genericError": "Что-то пошло не так", + "tryAgain": "Пробовать снова", + "checkoutError": "Не удалось запустить проверку" + }, + "pricing": { + "custom": "Обычай", + "comingSoon": "Скоро будет", + "mostPopular": "Самый популярный", + "currentPlan": "Текущий план", + "contactSales": "Свяжитесь с отделом продаж", + "freeForever": "Свободен навсегда", + "upgrade": "Обновлять" + }, + "topups": { + "loadError": "Не удалось загрузить пакеты для пополнения счета", + "title": "Пополнение счета кредитами", + "description": "Одноразовые кредитные карты начисляются с помощью Stripe. Срок действия кредитных карт никогда не истекает, и они суммируются в дополнение к вашему ежемесячному пособию.", + "tryAgain": "Пробовать снова", + "credits": "кредиты", + "redirecting": "Перенаправление…", + "buy": "Купить", + "empty": "На данный момент пакеты для пополнения счета недоступны.", + "receiptsTitle": "Последние пополнения счета", + "receiptsDescription": "Управление квитанциями осуществляется в Stripe — откройте платежный портал, чтобы просмотреть историю своих счетов и загрузить квитанции.", + "opening": "Открытие…", + "openPortal": "Открытый полосатый портал", + "checkoutError": "Не удалось запустить проверку", + "portalError": "Не удалось открыть платежный портал" + }, + "overview": { + "creditsLeft": "оставшиеся кредиты", + "planLabel": "План {name}", + "usedThisPeriod": "Использовал этот период", + "resets": "Сбрасывает настройки", + "resetsInDay": "В {n} день", + "resetsInDays": "В {n} днях", + "none": "—", + "upgradeToPro": "Перейти на профессиональный уровень", + "recentActivity": "Недавняя активность", + "last7Days": "Последние 7 дней", + "viewFullUsage": "Просмотр полного объема использования", + "noUsageYet": "Пока не используется", + "usageError": "Не удалось загрузить использование", + "needMoreCredits": "Нужно больше кредитов?", + "oneTimeTopups": "Единовременное пополнение счета без изменения подписки", + "seeAllPacks": "Посмотреть все пакеты", + "packsError": "Не удалось загрузить пакеты", + "noPacks": "Пакеты для пополнения счета недоступны.", + "creditsAmount": "{n} кредиты", + "oneTime": "{price} одноразовый", + "buy": "Купить", + "checkoutError": "Не удалось запустить проверку" + }, + "usage": { + "loadError": "Не удалось загрузить использование", + "kpi": { + "balance": "Баланс", + "balanceSuffix": "из {limit} кредитов", + "consumed": "Потребленный за этот период", + "credits": "кредиты", + "burnRate": "Скорость горения", + "burnRateSuffix": "кредиты в день (последние 7 дней)", + "projected": "Прогнозируемый срок на конец периода", + "noPeriod": "период не установлен" + }, + "granularity": { + "day": "день", + "week": "неделя" + }, + "chart": { + "title": "Использование с течением времени", + "subtitle": "Сложенные в стопку единицы измерения в соответствии с {unit}." + }, + "breakdown": { + "title": "Распределение ресурсов", + "subtitle": "Кредиты начисляются пропорционально дозированному использованию ресурсов в выбранном диапазоне.", + "resource": "Ресурс", + "units": "Единицы", + "credits": "Кредиты", + "percentOfTotal": "% от общего числа", + "loading": "Погрузка…", + "empty": "Не используется в выбранном диапазоне." + }, + "resources": { + "cpu": { + "label": "Процессорное время", + "units": "vCPU-часы" + }, + "memory": { + "label": "Память", + "units": "ГИГАБАЙТ-часы" + }, + "disk": { + "label": "Дисковый ввод-вывод", + "units": "Гб" + }, + "network": { + "label": "Сеть", + "units": "Гб" + } + }, + "toolbar": { + "workspace": "Рабочее место", + "workspaceTooltip": "В версии 1.1 появится разбивка по рабочим пространствам", + "allWorkspaces": "Все рабочие области", + "to": "к" + }, + "empty": "Нет данных об использовании для выбранного диапазона." + }, + "chart": { + "cpu": "ЦП", + "memory": "Память", + "diskIo": "Дисковый ввод-вывод", + "network": "Сеть", + "weekTick": "Шк {n}" + }, + "layout": { + "title": "Выставление счетов и использование", + "subtitle": "Управляйте своей подпиской, использованием и способами оплаты." + }, + "sidebar": { + "planSuffix": "План {name}", + "status": "Статус", + "statusInactive": "Неактивный", + "upgradeTo": "Обновление до {name}", + "contactSales": "Свяжитесь с отделом продаж", + "freeForever": "Свободен навсегда", + "perMonth": "${price}/месяц", + "statuses": { + "active": "Активный", + "trialing": "Испытание", + "past_due": "Просроченный платеж", + "canceled": "Отмененный", + "incomplete": "Незавершенный", + "incomplete_expired": "Истекший", + "unpaid": "Неоплаченный", + "paused": "Остановился" + } + }, + "paymentPanel": { + "title": "Способ оплаты", + "description": "Управление картами, банковскими счетами и платежными реквизитами осуществляется на клиентском портале Stripe. Откройте портал, чтобы добавить, удалить или обновить свои способы оплаты." + }, + "invoicesPanel": { + "title": "Счета-фактуры", + "description": "Счета и квитанции доступны на клиентском портале Stripe. Откройте портал, чтобы просмотреть историю выставления счетов и загрузить счета в формате PDF." + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/brand.json b/apps/dashboard/src/i18n/locales/ru/brand.json new file mode 100644 index 000000000..e03a1c9b4 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/brand.json @@ -0,0 +1,10 @@ +{ + "0": "O", + "1": "p", + "2": "e", + "3": "n", + "4": "S", + "5": "h", + "6": "я", + "7": "p" +} diff --git a/apps/dashboard/src/i18n/locales/ru/chrome.json b/apps/dashboard/src/i18n/locales/ru/chrome.json new file mode 100644 index 000000000..15197379e --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/chrome.json @@ -0,0 +1,86 @@ +{ + "accountSwitcher": { + "workspacesCount": "{count} рабочие области", + "newWorkspace": "Новое рабочее пространство", + "createTitle": "Создайте рабочее пространство", + "createDescription": "Отдельная организация для проектов, развертываний, серверов и участников.", + "nameLabel": "Имя", + "namePlaceholder": "Корпорация Acme", + "cancel": "Отменить", + "create": "Создавать", + "toastTitle": "Организация", + "switchFailed": "Не удалось переключиться", + "createFailed": "Не удалось создать" + }, + "sidebar": { + "workspaceFallback": "Рабочее место", + "workspacesCount": "{count} рабочие области", + "switchOrganization": "Организация коммутатора", + "current": "Текущий", + "cloudLabel": "Облако: {email}", + "linkedToCloud": "Связан с облаком Openship как {email}", + "backToSetup": "Вернуться к настройке", + "personal": "Личный" + }, + "mailRail": { + "selectServer": "Выберите почтовый сервер", + "switchServer": "Переключить почтовый сервер", + "setupIncomplete": "Настройка не завершена" + }, + "migration": { + "inProgressTitle": "Продолжается миграция", + "inProgressBody": "Ваши данные перемещаются. Эта страница обновится после завершения перехода — обычно это занимает 30-90 секунд.", + "inProgressHint": "Не закрывайте эту вкладку. Мы проверяем статус переноса каждые несколько секунд и будем загружать автоматически.", + "newLocation": "Новое местоположение", + "switchBackPrompt": "Вам нужно вернуть однопользовательский режим на этот компьютер?", + "switchBackAction": "Переключитесь обратно на однопользовательский режим", + "cloudTitle": "Этот экземпляр был перемещен в облако Openship", + "cloudBody": "Теперь ваша команда сотрудничает по ссылке, указанной ниже. В этом локальном экземпляре больше нет ваших проектов, настроек или развертываний — откройте облачную панель мониторинга, чтобы продолжить.", + "cloudCta": "Откройте облачную панель мониторинга", + "tunneledTitle": "Теперь до вашего открытого корабля можно добраться по туннелю", + "tunneledBody": "Партнеры по команде могут войти в систему по ссылке, указанной ниже, когда ваш компьютер подключен к сети. Данные по—прежнему хранятся на этом устройстве - туннель просто передает их через наклонный край.", + "tunneledCta": "Открытый URL-адрес туннеля", + "serverTitle": "Этот экземпляр был перемещен на ваш сервер", + "serverBody": "Теперь ваша команда сотрудничает по ссылке, указанной ниже. В этом локальном экземпляре больше нет ваших проектов, настроек или развертываний — откройте панель управления командой, чтобы продолжить.", + "serverCta": "Откройте панель управления командой" + }, + "notFound": { + "title": "Страница не найдена", + "descGlobal": "Страница, которую вы ищете, не существует или была перемещена.", + "descDashboard": "Эта страница не существует или, возможно, была перемещена. Проверьте URL-адрес или вернитесь на свою панель мониторинга.", + "backToDashboard": "Вернуться к панели управления", + "viewDeployments": "Просмотр развертываний", + "copyId": "Идентификатор копии" + }, + "error": { + "title": "На этой странице произошла ошибка", + "description": "Что-то на этом экране не удалось отобразить. Повторная попытка обычно приводит к устранению неполадок — ничего из того, что вы развернули, не было затронуто.", + "tryAgain": "Пробовать снова", + "goToProjects": "Перейти к проектам", + "refCode": "Ссылка" + }, + "apiDown": { + "title": "Не удается связаться с API", + "description": "Панель мониторинга запущена, но она не может взаимодействовать с API Openship, поэтому показывать пока нечего. Ваши развертывания продолжают выполняться независимо от этого.", + "hintStatus": "Убедитесь, что API запущен: запустите \"openship status` на хосте.", + "hintStart": "Не запускается? Начните с `открыть корабль`.", + "hintRemote": "Управление удаленным ящиком? Подтвердите его URL-адрес и то, что порт API доступен отсюда.", + "retry": "Повторить попытку", + "docs": "Документы для самостоятельного размещения" + }, + "errorLinks": { + "docs": "Документация", + "github": "Сообщить о проблеме" + }, + "window": { + "minimize": "Минимизировать", + "maximize": "Максимизировать", + "restore": "Восстанавливать", + "close": "Закрывать", + "navigation": "Навигация", + "back": "Назад", + "forward": "Вперед", + "reload": "Перезагрузить", + "devTools": "Инструменты разработчика" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/dashboard.json b/apps/dashboard/src/i18n/locales/ru/dashboard.json new file mode 100644 index 000000000..a96d1d223 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/dashboard.json @@ -0,0 +1,220 @@ +{ + "home": { + "goodMorning": "Доброе утро", + "goodAfternoon": "Добрый день", + "goodEvening": "Добрый вечер", + "subtitle": "Вот что происходит в ваших проектах", + "statsProjects": "Проекты", + "statsDeployments": "Развертывания", + "statsSuccessful": "Успешный", + "statsFailed": "Неудачный", + "recentProjects": "Недавние проекты", + "yourLatestActivity": "Ваше последнее занятие", + "viewAll": "Посмотреть все", + "noProjectsYet": "Пока нет проектов", + "createFirstProject": "Создайте свой первый проект", + "justNow": "прямо сейчас", + "minutesAgo": "{n}м назад", + "hoursAgo": "{n}h назад", + "daysAgo": "{n} назад", + "monthsAgo": "{n}mo назад", + "statusLive": "Жить", + "statusPaused": "Остановился", + "yourProjects": "Ваши проекты", + "loading": "Загрузка...", + "projectCountOne": "Проект {count}", + "projectCountOther": "Проекты {count}", + "viewAllProjects": "Просмотреть все проекты {count} →", + "viewAllApps": "Просмотреть все приложения {count} →", + "greetingName": "{greeting}, {name}", + "importGit": "Импортировать Git", + "importGitDesc": "Из хранилища", + "mcpDeploy": "Развертывание MCP", + "mcpDeployDesc": "Подключите агента искусственного интеллекта", + "settingsCard": "Настройки", + "settingsCardDesc": "Аккаунт и команда", + "docs": "Доктора", + "docsDesc": "Учить больше", + "activityTitle": "Деятельность", + "systemStatus": "Состояние системы", + "operational": "Оперативный", + "oneIssue": "1 проблема", + "manyIssues": "Проблемы с {n}", + "recentTitle": "Недавний", + "activityEmpty": "Ваши действия будут отображаться здесь", + "appsEmptyTitle": "Приложений пока нет", + "appsEmptyDesc": "Один клик, полностью автономный хостинг - базы данных, автоматизация, аналитика, хранилища паролей и многое другое, работающие на ваших собственных серверах.", + "allSystemsOperational": "Все системы в рабочем состоянии", + "runningSmoothly": "Ваши проекты идут гладко", + "time": { + "justNow": "прямо сейчас", + "minutes": "{n}м назад", + "hours": "{n}h назад", + "days": "{n} назад", + "months": "{n}mo назад" + } + }, + "nav": { + "home": "Домой", + "new-project": "Новый проект", + "projects": "Проекты", + "apps": "Приложения", + "deployments": "Развертывания", + "issues": "Проблемы", + "backups": "Резервные копии", + "domains": "Домены", + "monitoring": "Мониторинг", + "servers": "Серверы", + "emails": "Электронные письма", + "jobs": "Работы", + "settings": "Настройки", + "billing": "Выставление счетов и использование", + "mailSetup": "Настройка почты", + "mailSetupProgress": "Ход настройки", + "addMailbox": "Добавить почтовый ящик", + "webmail": "Веб-почта", + "sections": { + "main": "Главный", + "settings": "Настройки", + "infrastructure": "Инфраструктура", + "mail": "Почта", + "delivery": "Доставка", + "system": "Система", + "account": "Счет" + } + }, + "sidebar": { + "expand": "Развернуть боковую панель", + "collapse": "Свернуть боковую панель" + }, + "user": { + "logout": "Выйти из системы", + "loggingOut": "Выход из системы…", + "profile": "Профиль", + "preferences": "Предпочтения" + }, + "pages": { + "apps": { + "title": "Приложения", + "description": "Управляемые сервисы в один клик - установите и запустите Convex, WordPress, mail и многое другое.", + "createButton": "Установить приложение", + "loading": "Загрузка приложений…", + "countOne": "Установлено приложение {count}", + "countOther": "Установленные приложения {count}", + "emptyTitle": "Установите свое первое приложение", + "emptyDescription": "Запустите Convex, n8n, Ghost и другие — одним щелчком мыши, полностью автономно. Выберите один из них, чтобы начать.", + "popular": "Популярные приложения", + "alsoDeploy": "Вы также можете развернуть", + "browseAll": "Просматривайте все приложения", + "moreApps": "+{count} еще", + "catalogTitle": "Установите приложение", + "catalogDescription": "Управляемые сервисы в один клик. Выберите один из них, чтобы установить его как приложение.", + "catalogSearchPlaceholder": "Поисковые приложения…", + "catalogNoResults": "Ни одно приложение не соответствует вашему запросу.", + "categories": { + "all": "Все", + "backend": "Бэкэнд", + "database": "База данных", + "cms": "CMS-сервер", + "analytics": "Аналитика", + "automation": "Автоматизация", + "mail": "Почта", + "other": "Инструменты" + }, + "installing": "Установка…", + "install": "Устанавливать", + "cancel": "Отменить", + "nameLabel": "Имя", + "configTitle": "Настроить {app}", + "comingSoon": "Скоро будет" + }, + "projects": { + "title": "Проекты", + "description": "Легко развертывайте свои приложения и управляйте ими", + "createButton": "Создать проект", + "stats": { + "totalProjects": "Общее количество проектов", + "liveNow": "Живи сейчас", + "avgPerDay": "Среднее значение в день", + "successRate": "Показатель успеха" + }, + "searchPlaceholder": "Поисковые проекты...", + "pinnedProjects": "Закрепленные проекты", + "otherProjects": "Другие проекты", + "noResultsFound": "Не найдено проектов, соответствующих \"{query}\"", + "emptyState": { + "title": "Начните свой первый проект", + "description": "Импортируйте репозиторий Git, используйте шаблон или выполняйте развертывание из CLI. Здесь будут отображаться ваши проекты.", + "createProject": "Создать проект", + "browseTemplates": "Просмотр шаблонов", + "zeroConfig": "Развертывание с нулевой конфигурацией", + "instant": "Моментальный", + "instantDesc": "Развертывание за считанные секунды", + "global": "Глобальный", + "globalDesc": "более 100 пограничных регионов", + "previews": "Предварительный просмотр", + "previewsDesc": "URL-адрес для каждой ветви", + "rollbacks": "Откаты", + "rollbacksDesc": "Возврат в один клик", + "commandPalette": "Или нажмите {key}, чтобы открыть командную палитру" + }, + "view": { + "label": "Смотреть", + "list": "Список", + "grid": "Сетка" + } + }, + "deployments": { + "title": "Развертывания", + "description": "Просматривайте историю развертываний и управляйте ею." + }, + "domains": { + "title": "Домены", + "description": "Управляйте пользовательскими доменами и записями DNS." + }, + "monitoring": { + "title": "Мониторинг", + "description": "Журналы, показатели и проверки работоспособности ваших служб." + }, + "servers": { + "title": "Серверы", + "description": "Управляйте своими серверами развертывания и инфраструктурой." + }, + "settings": { + "title": "Настройки", + "description": "Настройки учетной записи, команды и платформы." + }, + "billing": { + "title": "Выставление счетов и использование", + "description": "Управляйте своей подпиской, использованием и способами оплаты." + } + }, + "quickLinks": { + "title": "Быстрые действия", + "subtitle": "Переходите к общим задачам", + "deployProject": { + "title": "Развертывание проекта", + "description": "Импорт из Git" + }, + "projects": { + "title": "Проекты", + "description": "Все проекты" + }, + "deployments": { + "title": "Развертывания", + "description": "История создания" + }, + "settings": { + "title": "Настройки", + "description": "Управление доступом" + }, + "domains": { + "title": "Домены", + "description": "Пользовательские домены" + }, + "billing": { + "title": "Выставление счетов и использование", + "description": "Использование и планы" + } + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/deploy.json b/apps/dashboard/src/i18n/locales/ru/deploy.json new file mode 100644 index 000000000..749b64b24 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/deploy.json @@ -0,0 +1,315 @@ +{ + "page": { + "projectNameLabel": "Название проекта", + "projectNameHint": "Уникальный идентификатор для вашего развертывания", + "uploadedFolder": "Загруженная папка", + "errorInvalidUrlTitle": "Неверный URL-адрес хранилища", + "errorInvalidUrlDetails": "Формат URL-адреса хранилища не распознается. Пожалуйста, проверьте URL-адрес и повторите попытку.", + "errorLoadProjectTitle": "Не удалось загрузить проект", + "errorLoadRepoTitle": "Не удалось загрузить репозиторий", + "errorScanFolderFailed": "Нам не удалось просканировать эту папку. Убедитесь, что путь указан правильно и доступен.", + "errorLoadRepoFailed": "Мы не смогли загрузить это хранилище. Возможно, оно закрыто, не существует или у вас нет к нему доступа." + }, + "header": { + "private": "Частный", + "public": "Общественный", + "help": "Помогите" + }, + "domainSettings": { + "saveFailed": "Не удалось сохранить домены", + "toastTitle": "Домены", + "routeFreeLabel": "Свободный поддомен", + "routeFreeDesc": "Бесплатный URL-адрес {domain}, готовый мгновенно.", + "routeCustomLabel": "Пользовательский домен", + "routeCustomDesc": "Укажите свой собственный домен для этого развертывания.", + "routeNoneLabel": "Никто", + "routeNoneDesc": "Публичного URL—адреса нет - только внутренний. Доступ к нему осуществляется через порт на хосте." + }, + "dns": { + "title": "Конфигурация DNS", + "addRecordsFor": "Добавьте эти записи к вашему DNS-провайдеру для", + "selfInfoPre": "Направьте ", + "recordA": "Рекорд", + "selfInfoMid": " на вашем сервере IP — адрес HTTPS выдается автоматически при первом развертывании.", + "recordTxt": "Текстовая запись", + "verifySuffix": " для подтверждения права собственности.", + "cloudInfoPre": "Добавьте ", + "recordCname": "Запись CNAME", + "cloudInfoMid": " для маршрутизации, затем добавьте ", + "modalTitle": "Укажите свой домен, затем разверните", + "modalSubtitle": "HTTPS запускается при первом развертывании, как только ваш домен будет указан здесь, или пропустите и добавьте DNS позже на вкладке Домены.", + "autoConfigTitle": "Автоматическая настройка с помощью моего DNS-провайдера", + "autoConfigDesc": "Подключите своего регистратора, и мы добавим эти записи за вас.", + "comingSoon": "Скоро будет", + "deployAction": "Развертывать", + "cancel": "Отменить", + "loadingRecords": "Загрузка записей DNS…", + "serverIpPlaceholder": "публичный IP-адрес вашего сервера", + "record": { + "purposeA": "Указывает {hostname} на IP-адрес этого сервера", + "purposeCname": "Маршрутизирует {hostname} через пограничную сеть", + "purposeCnameAlias": "Указывает {hostname} на {target}", + "purposeTxt": "Доказывает, что вы являетесь владельцем {hostname} — мы просматриваем эту запись, когда вы нажимаете Подтвердить", + "fieldType": "Тип", + "fieldName": "Имя", + "fieldValue": "Ценность", + "fieldTtl": "ТТЛ", + "ttlValue": "Автоматический (или 3600)", + "apexHint": "“@” — это сам домен. Некоторые провайдеры хотят, чтобы это поле оставалось пустым", + "fullName": "Полное имя, если это необходимо вашему провайдеру:", + "proxyNote": "Оставьте все прокси/CDN выключенными (Cloudflare: серое облако, “только DNS”), чтобы для этого домена можно было использовать HTTPS.", + "copy": "Копировать" + } + }, + "buildSummary": { + "title": "Сводка по развертыванию", + "domain": "Домен", + "extraMore": " +{count} еще", + "services": "Услуги", + "servicesValue": "{total} всего · {exposed} открыто", + "buildLocation": "Местоположение постройки", + "framework": "Рамки", + "app": "Апп", + "install": "Устанавливать", + "build": "Строить", + "output": "Выход", + "stack": "Стек", + "runtime": "Время выполнения", + "port": "Порт", + "localMachine": "Локальный компьютер", + "cloud": "Облако Openship", + "server": "Сервер" + }, + "checklist": { + "title": "Контрольный список развертывания", + "servicesDetected": "Обнаруженные службы", + "servicesCount": "Сервисы {count}", + "publicDomains": "Публичные домены", + "exposedOf": "{exposed} из {exposable}, выставленного", + "canBeExposed": "{count} может быть открыт", + "buildServices": "Услуги по созданию", + "toBuild": "{count} для построения", + "environment": "Окружающая среда", + "varsAcross": "Переменные {vars} в сервисах {services}", + "noEnvVars": "Переменные env не установлены", + "domains": "Домены" + }, + "sidebar": { + "copyCloneToken": "Копировать клонировать токен", + "cloneTokenTitle": "Токен клонирования", + "cloneTokenNoRepo": "Для этого развертывания нет репозитория на GitHub.", + "cloneTokenCopiedTitle": "Скопированный токен клонирования", + "cloneTokenCopied": "скопирована команда git clone. Срок действия встроенного токена истекает в течение часа.", + "cloneTokenFailed": "Не удалось отчеканить токен-клон", + "newEnvironment": "Новая среда", + "selectBranch": "Выберите филиал", + "saving": "Экономия…", + "saveChanges": "Сохранить изменения", + "deploying": "Развертывание…", + "deploy": "Развертывать", + "freeDomainFeature": "Используйте бесплатные домены .{domain} на вашем собственном сервере", + "freeDomainDesc": "Свободный.Домены {domain} маршрутизируются через Openship Cloud. Чтобы развернуть этот проект на вашем собственном сервере, либо подключите Openship Cloud, либо переключите этот проект на пользовательский домен.", + "freeDomainHint": "Если вы не хотите подключать Openship Cloud, измените домен проекта с бесплатного на пользовательский перед развертыванием.", + "servicesFreeDomainFeature": "Используйте бесплатные домены .{domain} для своих сервисов", + "servicesFreeDomainDesc": "Один или несколько доступных сервисов работают бесплатно.Домены {domain}. Чтобы развернуть их на своем собственном сервере, либо подключите Openship Cloud, либо переключите эти сервисы на пользовательские домены.", + "servicesFreeDomainHint": "Пользовательские домены работают без Openship Cloud. Бесплатные управляемые домены этого не делают.", + "unreachableTitle": "Ни одна государственная служба не доступна", + "unreachableBody": "В этом стеке есть службы приложений с портами, но ни одна из них не настроена на общедоступный домен. При развертывании сейчас службы могут запускаться внутри системы, но пользователи не смогут получить к ним доступ по URL-адресу.", + "beforeDeploying": "Перед развертыванием", + "unreachableStep1": "Выберите сервис, который должен быть общедоступным.", + "unreachableStep2": "Включите доступ к этой службе.", + "unreachableStep3": "Установите поддомен или пользовательский домен и выберите общедоступный порт.", + "reviewServices": "Услуги по проверке", + "deployAnyway": "Развертывать в любом случае" + }, + "skeleton": { + "settings1": "Загрузка сохраненных настроек", + "settings2": "Восстановление конфигурации", + "local1": "Проект сканирования", + "local2": "Чтение манифестов", + "local3": "Обнаруживающая структура", + "repo1": "Подключение к GitHub", + "repo2": "Извлекающий репозиторий", + "repo3": "Анализ структуры" + }, + "targetStep": { + "heading": "Где вы хотите развернуться?", + "loadingSubtitle": "Загрузка доступных объектов развертывания", + "loadingCheck": "Проверка серверов и облачного подключения...", + "deployAndBuildHeading": "Развертывание и сборка", + "chooseSubtitle": "Выберите, где будет запускаться ваше приложение", + "onlyOneSubtitle": "В настоящее время доступен только один целевой объект для развертывания", + "noTargetSubtitle": "Цель для развертывания пока не доступна", + "noTargetBody": "Подключите облако Openship или добавьте сервер, чтобы продолжить это развертывание.", + "addServer": "Добавьте свой собственный сервер", + "continue": "Продолжать", + "chooseServer": "Выберите сервер", + "thisServerBadge": "Этот сервер", + "thisServerHost": "Текущие развертывания на хосте выполняются здесь", + "searchPlaceholder": "Поисковые серверы…", + "noServersMatch": "Ни один сервер не соответствует вашему запросу.", + "requireCloudFeature": "Развертывание в облаке Openship", + "saveDefault": "Сохраняйте как значение по умолчанию для каждого развертывания.", + "saveDefaultHint": "Измените его позже в настройках или для каждого развертывания в окне выбора на этой странице.", + "savedToastTitle": "Значения по умолчанию", + "savedToast": "Сохранен в качестве цели развертывания по умолчанию", + "saveFailedToast": "Не удалось сохранить значение по умолчанию - ваше развертывание все равно продолжится", + "gitForwardLabel": "Перешлите мои учетные данные git", + "gitForwardDescPre": "Клонируйте на сервере, используя свой локальный ", + "gitForwardDescPost": " идентификация — нет необходимости в сборке и загрузке. На сервере ничего не хранится.", + "options": { + "serverViaSsh": "Выполните развертывание на вашем удаленном сервере по SSH.", + "servers": "Ваши серверы", + "serversCount": "Сконфигурированные серверы {count}.", + "cloud": "Облако Openship", + "cloudConnectedDesc": "Развертывание в управляемой облачной инфраструктуре. Настройка сервера не требуется.", + "cloudDisconnectedDesc": "Подключите свою облачную учетную запись Openship и выполните развертывание в управляемой инфраструктуре." + }, + "build": { + "heading": "Местоположение постройки", + "prepareHeading": "Подготовьте местоположение", + "subtitle": "Где выполняется сборка", + "prepareSubtitle": "Где осуществляется поэтапное репо", + "advanced": "Передовой", + "advancedSummary": "{action} на {location}", + "actionBuild": "Строить", + "actionPrepare": "Подготовить", + "options": "Опции", + "localLabel": "Эта машина", + "localDesc": "Стройте здесь, отправляйте результат.", + "remoteLabel": "Дистанционный", + "remoteDesc": "Отталкивайтесь от цели развертывания.", + "cloudLabel": "Облако Openship", + "cloudDesc": "Управляемая облачная сборка.", + "cloudLocalLabel": "Эта машина", + "cloudLocalDesc": "Постройте здесь, загрузите результаты." + }, + "hint": { + "buildTitle": "Мы будем строить там, где вы разместите свои войска", + "prepareTitle": "Мы подготовим место вашего развертывания", + "cloud": "Сборки выполняются в управляемой облачной инфраструктуре - настраивать ничего не нужно.", + "serverNamed": "Сборки выполняются на вашем сервере \"{name}\". Если это небольшой VPS, сборка на этом компьютере может быть намного быстрее. Вы можете изменить это на следующем экране или сохранить настройки в настройках.", + "server": "Сборки выполняются на вашем сервере. Если это небольшой VPS-сервер, сборка на этом компьютере может быть намного быстрее. Вы можете изменить это на следующем экране или сохранить настройки в настройках.", + "local": "Сборки выполняются на этом компьютере. Вы можете изменить это на следующем экране или сохранить настройки в разделе \"Настройки\".", + "chooseBuildLocation": "Выберите место сборки" + }, + "clone": { + "heading": "Местоположение клона", + "descLead": "Сборка всегда выполняется на сервере. ", + "descDesktop": "Учетные данные пересылаются временно и никогда не сохраняются.", + "descServer": "Использует токен с коротким сроком службы.", + "apiHostDesktopLabel": "На вашем устройстве", + "apiHostServerLabel": "На Openship", + "apiHostDesktopDesc": "Клонируйте здесь, затем загружайте.", + "apiHostServerDesc": "Клонируйте на Openship, затем загружайте.", + "serverLabel": "На сервере", + "serverDesc": "Клонировать на сервере. Загрузка невозможна." + }, + "rollbackTitle": "Откат и резервное копирование", + "rollbackHint": "Сколько предыдущих версий остаются доступными для восстановления на этом сервере и какие из них сохраняются в резервной копии перед развертыванием.", + "rollbackFirstDeploy": "Доступен для редактирования в настройках проекта после однократного развертывания этого проекта.", + "backupSummaryNone": "Политики резервного копирования пока нет", + "backupSummaryConfigured": "Политики резервного копирования {count} · предварительное развертывание: {preDeploy}", + "backupManage": "Управление резервными копиями", + "on": "на", + "off": "прочь" + }, + "summary": { + "buildAndDeploy": "Создание и развертывание:", + "build": "Строить:", + "deploy": "Развертывать:", + "static": "Статический", + "runtimeStatic": "Статический · обслуженный по краю", + "runtimeSandboxed": "Изолированный", + "runtimeDirectWarning": "Не помещен в песочницу", + "runtimeDirectHint": "Запускается непосредственно на хосте, а не в изолированной среде.", + "targetLocal": "Эта машина", + "targetServer": "Мой сервер", + "targetCloud": "Облако Openship", + "buildLocal": "Эта машина", + "buildRemote": "Дистанционный", + "rollbackOne": "Версия {count}", + "rollbackOther": "Версии {count}", + "rollbackAuto": "Откат: автоматический", + "rollbackSnapshotHint": "Копия каждой версии сохраняется, поэтому откат никогда не выполняется заново. Измените в разделе Дополнительно.", + "rollbackGitHint": "Сколько предыдущих версий можно восстановить. Измените в разделе Дополнительно." + }, + "power": { + "heading": "Сила", + "subtitle": "Выберите размер среды выполнения для Openship Cloud", + "ram": "ОЗУ", + "disk": "Диск", + "vcpu": "vCPU (центральный процессор)", + "custom": "Обычай", + "customDesc": "Подключите процессор, оперативную память и хранилище самостоятельно", + "tierMicroLabel": "Микро", + "tierMicroBestFor": "Побочные проекты, низкий трафик", + "tierLowLabel": "Низкий", + "tierLowBestFor": "Небольшие приложения, легкие API", + "tierMediumLabel": "Средний", + "tierMediumBestFor": "Большинство производственных приложений", + "tierHighLabel": "Высокий", + "tierHighBestFor": "Высокая рабочая нагрузка, быстрая сборка", + "modalTitle": "Пользовательская среда выполнения", + "modalSubtitle": "Выберите процессор, оперативную память и диск, с которыми должно выполняться это развертывание.", + "vcpuField": "vCPU (центральный процессор)", + "ramField": "ОПЕРАТИВНАЯ память (МБ)", + "diskField": "Диск (ГБ)", + "cancel": "Отменить", + "save": "Сохранить" + }, + "runtime": { + "heading": "Время выполнения", + "subtitle": "Насколько он изолирован", + "subtitleRam": "Как он изолирован · {ram} ГБ оперативной памяти", + "recommended": "Рекомендуемый", + "sandboxedLabel": "Изолированный", + "sandboxedDesc": "Изолированный контейнер. Крошечные накладные расходы.", + "directLabel": "Прямой", + "directDesc": "Выполняется на хосте. Минимальные накладные расходы.", + "caveatLowRam": "Объем оперативной памяти здесь ограничен — изолированная память добавляет ~50-80 МБ. Direct легче, изолированная память безопаснее.", + "caveat": "Прямой доступ означает полный доступ к хосту в случае взлома. Изолированная система добавляет ~1-2% ресурсов процессора для реальной изоляции." + }, + "serveMode": { + "heading": "Как его подают", + "subtitle": "Обслуживайте созданные файлы или запускайте их как живой серверный процесс.", + "staticLabel": "Служат в качестве статических файлов", + "staticDesc": "Выходные данные сборки обрабатываются непосредственно edge. Ничто не выполняется как процесс.", + "serverLabel": "Запускается как серверный процесс", + "serverDesc": "Запустите длительный процесс (требуется команда запуска и порт).", + "staticNote": "Создавался в изолированной песочнице Docker, а затем использовался в качестве статических файлов в edge.", + "startCommandLabel": "Команда запуска", + "startCommandPlaceholder": "запуск npm", + "startCommandHint": "Оставьте поле пустым, чтобы выходные данные сборки отображались в виде статических файлов из edge (ничего не запускается). Введите команду, чтобы запустить ее как текущий серверный процесс.", + "modeStatic": "Статический", + "modeProcess": "Серверный процесс", + "portLabel": "Порт" + }, + "mail": { + "title": "Развертывание веб-почты", + "subtitle": "Создайте автономную веб-почту на выбранном вами домене.", + "backToMail": "Вернуться к почте", + "missingServerTitle": "Отсутствующий почтовый сервер", + "missingServerBody": "Откройте эту страницу в разделе Обзор почты.", + "deployToTitle": "Развернуть для", + "deployToHint": "Веб-почта может храниться на этом почтовом сервере, на другом хосте, управляемом openship, или на Opshcloud.", + "loadingTargets": "Загрузка мишеней…", + "notAvailable": "Не доступен", + "domainTitle": "Домен", + "domainHintProxy": "Вашему почтовому серверу уже принадлежит это имя хоста - мы подключим его через ваш почтовый VPS к рабочей нагрузке Opshcloud. Изменения DNS не требуются.", + "domainHintCloud": "Укажите CNAME на *.opsh.io URL, который мы предоставляем (вы увидите его после развертывания).", + "domainHintDefault": "Операторы будут обращаться к URL-адресам. DNS должен указывать на цель развертывания.", + "summary": "Резюме", + "summaryTarget": "Цель", + "summaryDomain": "Домен", + "summaryMailServer": "Почтовый сервер", + "starting": "Начало…", + "deployButton": "Развертывание веб-почты", + "replaceButton": "Заменить веб-почту", + "legacyTitle": "Эта веб-почта появилась раньше приложения webmail", + "legacyBody": "Он был развернут более старой версией Openship, которая отправляла веб-почту в виде пакета, а не образа, поэтому его нельзя повторно развернуть. При развертывании сейчас все это - проект, контейнер и база данных сеансов - удаляется, а на его место устанавливается приложение webmail. Все, кто входил в систему, выходят из нее, и настройки веб-почты для каждого пользователя теряются.", + "legacyKept": "Почтовые ящики, почтовые данные и каждое сообщение остаются на почтовом сервере нетронутыми.", + "deployFailedTitle": "Не удалось выполнить развертывание", + "deployFailed": "Не удалось запустить развертывание" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/deployments.json b/apps/dashboard/src/i18n/locales/ru/deployments.json new file mode 100644 index 000000000..7eb3e239b --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/deployments.json @@ -0,0 +1,194 @@ +{ + "time": { + "secondsAgo": "{n}s назад", + "minutesAgo": "{n}м назад", + "hoursAgo": "{n}h назад", + "daysAgo": "{n} назад", + "monthsAgo": "{n}mo назад", + "yearsAgo": "{n}y назад" + }, + "header": { + "title": "Развертывания", + "loading": "Погрузка…", + "countProjectOne": "{count} развертывание", + "countProjectOther": "Развертывания {count}", + "countAllOne": "{deployments} итого по проекту {projects}", + "countAllOther": "{deployments} итого по проектам {projects}" + }, + "filters": { + "searchPlaceholder": "Поиск развертываний...", + "all": "Все", + "success": "Успех", + "failed": "Неудачный", + "building": "Здание", + "canceled": "Отмененный" + }, + "projectFilter": { + "allProjects": "Все проекты" + }, + "sidebar": { + "overview": { + "title": "Обзор", + "total": "Весь", + "successful": "Успешный", + "failed": "Неудачный", + "inProgress": "в процессе" + }, + "autoDeploy": { + "title": "Автоматическое развертывание", + "description": "Включите автоматическое развертывание, чтобы автоматически запускать развертывания при каждом обращении к вашей основной ветке.", + "cta": "Перейдите в настройки проекта" + }, + "getStarted": { + "title": "начать", + "description": "Импортируйте репозиторий Git или используйте шаблон для создания вашего первого развертывания.", + "cta": "Развертывание проекта" + }, + "recent": { + "title": "Недавний", + "empty": "Ваши развертывания появятся здесь", + "unknown": "Неизвестный" + } + }, + "stats": { + "total": "Весь", + "projectCountOne": "Проект {count}", + "projectCountOther": "Проекты {count}", + "success": "Успех", + "failed": "Неудачный", + "inProgress": "в процессе", + "buildingNow": "строим сейчас" + }, + "status": { + "deployed": "Развернутый", + "failed": "Неудачный", + "canceled": "Отмененный", + "building": "Здание", + "deploying": "Развертывание", + "partial": "Частичный", + "actionRequired": "Необходимые действия", + "rejected": "Отклоненный", + "verifying": "Подтверждающий", + "noChanges": "Никаких изменений", + "pending": "Ожидаемый" + }, + "serviceStatus": { + "deployed": "Развернутый", + "failed": "Неудачный", + "cancelled": "Отмененный", + "skipped": "Пропущенный", + "building": "Здание", + "deploying": "Развертывание", + "running": "Бегущий", + "removedOnHost": "Удалено на хосте", + "verifying": "Подтверждающий", + "pending": "Ожидаемый" + }, + "card": { + "unknownProject": "Неизвестный проект", + "versionTitle": "Версия {version}", + "active": "Активный", + "activeTitle": "Это развертывание, которое в настоящее время обслуживает проект", + "pinned": "Закрепленный", + "pinnedTitle": "Закрепленный — не подлежит удалению при удержании. Может быть восстановлен при откате на неопределенный срок.", + "snapshotted": "Моментальный снимок", + "snapshottedTitle": "Артефакт заархивирован — к этой версии можно вернуться", + "manualDeploy": "Ручное развертывание", + "serviceTitle": "{name}: {label}", + "serviceTitleReason": "{name}: {label} ({reason})" + }, + "empty": { + "filtered": { + "title": "Не найдено ни одного развертывания", + "description": "Попробуйте настроить свои фильтры или очистить поле поиска." + }, + "none": { + "title": "Развертываний пока нет", + "description": "Разверните свой первый проект, и он появится здесь со статусом сборки, подробной информацией о фиксации и показателями производительности.", + "deployButton": "Развертывание проекта", + "browseButton": "Просмотр шаблонов" + } + }, + "modal": { + "title": "Детали фиксации", + "project": "Проект", + "unknownProject": "Неизвестный проект", + "domain": "Домен", + "noDomain": "Нет домена", + "status": "Статус", + "environment": "Окружающая среда", + "statusName": { + "success": "Успех", + "failed": "Неудачный", + "building": "Здание", + "deploying": "Развертывание", + "canceled": "Отмененный", + "pending": "Ожидаемый" + }, + "changedFiles": "Измененные файлы ({count})", + "fileTypes": { + "added": "+ Добавлено", + "modified": "~ Измененный", + "removed": "- Удален" + }, + "viewOnGithub": "Посмотреть на GitHub", + "visitSite": "Посетить сайт", + "manual": { + "title": "Ручное развертывание", + "description": "Это развертывание было запущено вручную и не содержит информации о фиксации.", + "deploymentId": "Идентификатор развертывания", + "created": "Созданный", + "type": "Тип", + "typeManual": "Инструкция" + } + }, + "menu": { + "openDeployment": "Открытое развертывание", + "viewRepository": "Просмотр хранилища", + "copyDomainUrl": "Скопировать URL-адрес домена", + "copyBuildId": "Скопировать идентификатор сборки", + "cancelDeployment": "Отменить развертывание", + "rollback": "Откат к этой версии", + "rollbackTitle": { + "enabled": "Восстановите проект до этой версии (только код — данные не изменены)", + "active": "Это уже активная версия", + "pruned": "В этом развертывании нет сохраненного образа и нет фиксации для восстановления из него", + "notReady": "Можно выполнить откат только к готовым развертываниям.", + "rebuildOnly": "Восстановите эту версию, восстановив ее фиксацию (ее изображение было удалено)." + }, + "pin": "Пин-код", + "unpin": "Открепить", + "pinTitle": { + "pin": "Сохраняйте возможность отката и восстановления этого развертывания на неопределенный срок (ограничение: 10 закрепленных для каждого проекта).", + "unpin": "Разрешите сократить это развертывание при переполнении хранилища", + "pruned": "Невозможно закрепить — артефакт уже был удален" + }, + "deleteDeployment": "Удалить развертывание", + "rollbackFailed": "Откат не удался", + "pinFailed": "Не удалось закрепить развертывание", + "unpinFailed": "Не удалось открепить развертывание", + "rollbackModeInstant": "Мгновенное восстановление — повторно используется сохраненный образ этой версии, без перестройки.", + "rollbackModeRebuild": "Перестроить — образа этой версии больше нет на хосте, поэтому его фиксация создается заново.", + "rollbackModeMixed": "В основном службы instant — {count} потеряли свой имидж и будут восстановлены." + }, + "rollbackConfirm": { + "title": "Вернуться к этой версии?", + "dataUnchanged": "При этом восстанавливается только код приложения. База данных и объем данных не изменяются.", + "envHeading": "Переменные среды", + "envSummaryOverlay": "Изменение переменной(переменных) {count} — значения этого выпуска воспроизводятся поверх текущих.", + "envSummaryReplace": "Изменение переменных {count} — среда этого выпуска используется точно так же, как и в предыдущем случае.", + "envNoChanges": "Никакие переменные окружения не изменяются.", + "envUnchanged": "Существующий контейнер перезапускается, а не создается заново, поэтому его среда остается нетронутой.", + "envNoValues": "Значения здесь никогда не отображаются.", + "envTruncated": "Отображается {shown} вместо {total}.", + "dirFrozenWins": "возвращается к значению этого выпуска", + "dirRemovedSince": "возвращается — удалено с момента выпуска", + "dirAddedSinceKept": "сохранено в том виде, в каком оно есть сейчас — добавлено после этого выпуска", + "dirAddedSinceDropped": "удалено — добавлено с момента выпуска", + "scopeAmbiguous": "захватывается без привязки к области обслуживания, поэтому для каждой службы используется одно значение", + "untouchedHeading": "Сервисы, добавленные после этого выпуска", + "untouchedNote": "Они продолжают работать и не затрагиваются: {names}", + "confirm": "Откат назад", + "cancel": "Отменить" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/emails.json b/apps/dashboard/src/i18n/locales/ru/emails.json new file mode 100644 index 000000000..e43f5701a --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/emails.json @@ -0,0 +1,195 @@ +{ + "page": { + "title": "Сервер электронной почты", + "subtitle": "Настройте автономный почтовый сервер несколькими щелчками мыши", + "backToServers": "Вернуться к почтовым серверам", + "backToAdmin": "Вернуться к почтовому администратору", + "addServer": "Добавить почтовый сервер", + "removeModal": { + "title": "Удалить этот почтовый сервер?", + "description": "Удаляет {label} только из списка рассылки. Почтовый стек продолжает работать, и ничего не удаляется — повторно добавьте его в любое время, нажав \"Принять\" для существующей установки.", + "submit": "Удалить из списка", + "submitting": "Удаление…", + "body": "Поскольку установка на сервере остается неизменной, ее повторное использование позже восстанавливает полное управление без переустановки." + }, + "errors": { + "resetFailed": "Сбой сброса не удался", + "ackDns": "Не удалось подтвердить DNS", + "ackPtr": "Не удалось подтвердить PTR", + "selectServer": "Сначала выберите сервер", + "resolutionFailed": "Не удалось разрешить проблему" + } + }, + "adopt": { + "title": "Использование существующего почтового сервера", + "intro": "Вы уже настроили почтовый сервер с Openship на одном из своих серверов? Выберите его и просканируйте — если почтовый стек найден, он будет повторно загружен в панель управления без переустановки или изменения ваших данных.", + "scanning": "Сканирующий…", + "scan": "Сервер сканирования", + "detected": "Обнаружен почтовый сервер", + "domainLabel": "Домен:", + "unknown": "неизвестный", + "stats": "Запуск iRedMail: {iredmail} · Установка: {install} · Веб-почта: {webmail}", + "yes": "да", + "no": "нет", + "complete": "полный", + "inProgress": "в процессе", + "present": "подарок", + "notDeployed": "не развернут", + "cancel": "Отменить", + "adopt": "Принимать", + "noInstall": "На этом сервере не было обнаружено ни одного установленного почтового сервера.", + "scanFailed": "Ошибка сканирования — доступен ли сервер?", + "adoptFailed": "Принять не удалось" + }, + "dns": { + "heading": "Опубликуйте записи DNS, прежде чем продолжить", + "bodyBefore": "Без них доставка почты прерывается. Добавьте их у своего DNS-провайдера, затем нажмите ", + "action": "Я установил рекорды - продолжайте", + "bodyAfterResume": " ниже. Установка возобновляется с шага {resumeStep} (SSL-сертификат).", + "bodyAfter": " ниже.", + "autoConfigure": "Автоматическая настройка DNS", + "autoConfigureDesc": "Выберите провайдера, предоставляющего DNS для вашего домена. Мы отправим записи для вас, используя их API.", + "otherManual": "Другое / устанавливается вручную", + "otherManualDesc": "Скопируйте каждую запись с баннера и вставьте в пользовательский интерфейс вашего провайдера", + "pickAnother": "Выберите другого провайдера", + "comingSoon": "Интеграция {provider} - скоро будет", + "comingSoonBefore": "Прямая интеграция API с этим провайдером еще не реализована. На данный момент скопируйте каждую запись с баннера и вставьте ее в пользовательский интерфейс вашего DNS-провайдера. Как только это будет сделано, нажмите ", + "comingSoonAfter": ".", + "gotIt": "Понял", + "providers": { + "cloudflare": "Бесплатный DNS, быстрое распространение. Самый распространенный вариант.", + "hostinger": "Если вы купили домен через Hostinger.", + "route53": "Зоны DNS, размещенные на AWS.", + "digitalocean": "Зоны, управляемые DigitalOcean.", + "namecheap": "Список имен по умолчанию DNS.", + "google": "Зоны, управляемые Google." + } + }, + "recordCard": { + "priority": "Приоритет: {priority}", + "copyValue": "Значение для копирования" + }, + "progress": { + "liveLogs": "Живые журналы", + "lineOne": "Строка {count}", + "lineOther": "Строки {count}", + "cancel": "Отменить", + "resetTitle": "Удалите состояние установки на сервере и запустите все заново", + "confirmReset": "Нажмите еще раз для подтверждения", + "reset": "Сброс", + "waiting": "Ожидание вывода…", + "noBuffered": "Для этого запуска нет буферизованного вывода.", + "willStream": "Как только начнется настройка, сюда будут транслироваться логи.", + "jumpToLatest": "Перейти к последней версии", + "setupFailed": "Сбой настройки", + "retryFromStep": "Повторите попытку, начиная с шага {resumeStep}", + "resumePausedTitle": "Настройка приостановлена", + "stepLabel": "Шаг {step}", + "continueFromStep": "Продолжайте с шага {step}" + }, + "serverList": { + "title": "Почтовые серверы", + "addServer": "Добавить почтовый сервер", + "removeFromList": "Удалить из списка", + "removeAria": "Удалить {name} из списка рассылки", + "installing": "Установка", + "running": "Бегущий", + "incomplete": "Незавершенный", + "stoppedAt": "Остановлен · шаг {step}" + }, + "setup": { + "title": "Настройка почтового сервера", + "subtitle": "Разверните полный автономный почтовый стек на этом сервере", + "domainLabel": "Домен", + "domainPlaceholder": "example.com", + "willBeAtBefore": "Ваш почтовый сервер будет находиться по адресу ", + "adminPasswordLabel": "Пароль администратора", + "passwordPlaceholder": "Надежный пароль - или нажмите кнопку Сгенерировать", + "passwordHint": "Не менее 12 символов. Используется для входа в почтовый ящик после настройки — измените его позже в панели администратора ниже.", + "relay": { + "toggle": "Ретрансляция исходящих сообщений через поставщика услуг электронной почты", + "hint": "Рекомендуемый. Отправка осуществляется через надежные IP—адреса провайдера - IP-адреса новых серверов часто попадают в список заблокированных, и многие хосты блокируют исходящий порт 25. Получение остается на этом сервере.", + "region": "Регион", + "username": "Имя пользователя SMTP", + "password": "Пароль SMTP", + "perDomainNote": "Применяется ко всем доменам. Маршрутизация для каждого домена и записи DKIM / MAIL FROM провайдера каждого домена настраиваются после установки на вкладке \"Отправка\"." + }, + "startSetup": "Начать настройку", + "startFailed": "Не удалось запустить программу установки", + "startFailedFallback": "Не удалось запустить программу установки, и сервер не указал причину. Проверьте логи API.", + "adoptCta": "У вас уже есть почтовый сервер? Воспользуйтесь им", + "whatInstalled": "Что будет установлено", + "features": { + "stackLabel": "Стек почтовых серверов", + "stackDesc": "Postfix, Голубятня, защита от спама", + "sslLabel": "SSL-сертификат", + "sslDesc": "Давайте зашифруем auto-SSL", + "dnsLabel": "Конфигурация DNS", + "dnsDesc": "Записи DKIM, SPF, DMARC", + "adminLabel": "Панель администратора", + "adminDesc": "Управление почтовыми ящиками, доменами и псевдонимами" + }, + "prerequisites": "Предпосылки", + "prereq1": "Домен с доступом к DNS", + "prereq2": "Порт 25 не заблокирован вашим провайдером", + "prereq2Relay": "Порт 25 открыт для входящей почты (исходящая проходит через ваш ретранслятор)", + "prereq3": "Очистить сервер Ubuntu/Debian (рекомендуется)", + "hide": "Скрыть", + "reveal": "Раскрыть", + "generateTitle": "Сгенерируйте надежный случайный пароль", + "generate": "Генерировать" + }, + "sidebar": { + "portConflict": { + "title": "Обнаружен конфликт портов", + "subtitle": "Для работы почтового сервера необходимы порты 80/443", + "managed": "Управляемый", + "known": "Известная услуга", + "unknown": "Неизвестный", + "container": "Контейнер: {name}", + "killWarning": "Убедитесь, что этот процесс не требуется, прежде чем завершать его. Это действие невозможно отменить.", + "allResolved": "Все конфликты разрешены", + "rerun": "Повторно запустите проверку порта и продолжите настройку.", + "resumeStep3": "Продолжите с шага 3" + }, + "completion": { + "ready": "Почтовый сервер готов!", + "webmail": "Веб-почта", + "adminPanel": "Панель администратора" + }, + "dnsRef": { + "title": "Необходимые записи DNS", + "subtitle": "Ссылка - нажмите, чтобы просмотреть опубликованные вами записи" + }, + "steps": { + "title": "Все этапы", + "interrupted": "Установка была прервана перед выполнением шага {step}. Продолжите с того места, на котором она была прервана.", + "resume": "Возобновиться", + "retry": "Повторить попытку" + }, + "details": { + "title": "Подробные сведения о настройке", + "domain": "Домен", + "mailServer": "Почтовый сервер", + "started": "Начатый" + } + }, + "ptr": { + "heading": "Установите обратный DNS (PTR), прежде чем продолжить", + "bodyBefore": "PTRS настраиваются по вашему усмотрению. ", + "bodyStrongPanel": "Панель управления VPS-провайдера", + "bodyMid": " (Hostinger, DigitalOcean, AWS и др.), ", + "bodyStrongNot": "нет", + "bodyAfter": " у вашего DNS-провайдера. Если RDNS не совпадают, Gmail и Outlook отклоняют исходящую почту. Установка возобновляется с шага {resumeStep} (SSL).", + "recommended": "рекомендуемый", + "ipLabel": "ip", + "setTo": "Установлен в", + "copy": "Копировать", + "howTo": "Как это установить:", + "howToBody": " войдите в систему своего провайдера VPS, найдите настройки сети / DNS / rDNS сервера и установите для записи PTR для каждого IP значение ", + "howToAfter": " Размножение обычно занимает 5-15 минут.", + "verifyWith": "Проверьте с помощью:", + "shouldReturn": " должен вернуться ", + "action": "Я установил PTRs - продолжить" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/emailsAdmin.json b/apps/dashboard/src/i18n/locales/ru/emailsAdmin.json new file mode 100644 index 000000000..748e9e604 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/emailsAdmin.json @@ -0,0 +1,677 @@ +{ + "panel": { + "tabs": { + "overview": "Обзор", + "domains": "Домены", + "mailboxes": "Почтовые ящики", + "aliases": "Псевдонимы", + "dns": "DNS-сервер", + "health": "Здоровье", + "test": "Тест", + "backup": "Резервная копия", + "sending": "Отправка", + "advanced": "Передовой" + }, + "ariaLabel": "Разделы администрирования почты" + }, + "sending": { + "title": "Исходящая отправка", + "subtitle": "Получение остается на этом сервере. Выберите способ отправки исходящей почты.", + "modeDirectTitle": "Прямая поставка", + "modeDirectDesc": "Этот сервер сам доставляет исходящую почту. Просто, но свежо - IP—адреса VPS часто попадают в список заблокированных, и многие хосты блокируют исходящий порт 25 - почта может попасть в спам или выйти из строя.", + "modeRelayTitle": "Ретрансляция через провайдера", + "modeRelayDesc": "Отправляйте исходящую почту на smarthost — SES, SendGrid, Mailgun, Postmark, повторную отправку или на любой SMTP-сервер. Наилучшая скорость доставки. Ваш почтовый ящик и все принимающие DNS-адреса остаются в прежнем состоянии.", + "pathTitle": "Исходящий путь", + "setUpRelay": "Настройка ретранслятора", + "directActive": "Исходящая почта отправляется непосредственно с этого сервера. Настраивать ничего не нужно — выберите ретранслятор, указанный выше, если возникают проблемы с доставкой.", + "switchToDirect": "Переход на прямые поставки", + "switchToDirectHint": "Удаляет smarthost и сохраненные на нем учетные данные, а также удаляет SPF-код ретранслятора из вашего DNS. Исходящая почта снова поступает непосредственно на сервер каждого получателя.", + "statusOn": "Реле активировано", + "statusOff": "Прямая поставка (по умолчанию)", + "sendersTitle": "Какие отправители передают ретрансляцию?", + "scopeAll": "Все отправители", + "scopeSelected": "Выбранные отправители", + "scopeAllHint": "Каждый домен на этом сервере отправляет данные через ретранслятор.", + "scopeSelectedHint": "Ретранслируются только те отправители, которых вы выбираете; все остальное доставляется напрямую.", + "sendersDomains": "Целые домены", + "sendersAddresses": "Индивидуальные отправители", + "sendersAddressesHint": "Ретранслируйте один почтовый ящик без ретрансляции всего домена — contact@example.com здесь вы можете отправлять сообщения через своего провайдера, продолжая получать их по IMAP.", + "senderPlaceholder": "contact@example.com", + "addSender": "Добавь", + "removeSender": "Удалять", + "senderInvalid": "Введите один простой адрес, например contact@example.com — без отображаемого имени.", + "noSenders": "Выберите хотя бы один домен или адрес отправителя для ретрансляции.", + "noDomains": "На этом сервере пока не найдено ни одного домена.", + "credentialsTitle": "Поставщик услуг и учетные данные", + "provider": "Поставщик", + "regionFor": "Регион {provider}", + "host": "SMTP-хост", + "port": "Порт", + "username": "Имя пользователя SMTP", + "password": "Пароль SMTP", + "passwordKeep": "Оставьте поле пустым, чтобы сохранить текущий пароль", + "port465Blocked": "Порт 465 (неявный TLS) является общесерверной настройкой, поэтому его нельзя использовать, пока ретранслируются только некоторые отправители. Используйте STARTTLS—порт провайдера - обычно 587.", + "spfIncludeLabel": "SPF включает в себя", + "spfIncludeHint": "Вставьте в поле включить: механизм, который ваш провайдер рекомендует вам опубликовать. Если оставить поле пустым, мы не будем трогать вашу запись в SPF, но почта, переданная через хост, которого нет в списке SPF, не пройдет проверку SPF.", + "spfNone": "Никто", + "mailFromDomain": "Пользовательская ПОЧТА ИЗ домена", + "mailFromHint": "Необязательный. Такой поддомен, как bounce.example.com для выравнивания SPF/отказов. Настройте его также у поставщика.", + "identityTitle": "{provider} идентификатор для каждого домена", + "identityHint": "{provider} проверяет каждый отправляющий домен отдельно. Вставьте записи каждого ретранслируемого домена (необязательно — amavis уже подписывает, поэтому DMARC выравнивается без них, но провайдеру необходимо проверить домен перед отправкой).", + "identityPrimary": "Первичный", + "dkimRecords": "{provider} Записи DKIM", + "dkimRecordsHint": "Вставьте записи CNAME, которые показывает вам ваш провайдер (SES: console → Verified identities → ваш домен → DKIM). Мы отображаем + проверяем их на вкладке DNS.", + "dkimName": "CNAME имя", + "dkimValue": "Значение CNAME", + "summaryTitle": "Резюме", + "summaryTarget": "Умный хостинг", + "summarySenders": "Отправители", + "summaryUpdated": "Последний сохраненный", + "guidanceTitle": "Прежде чем это сработает", + "guidanceVerify": "Подтвердите свой домен в консоли Amazon SES.", + "guidanceSandbox": "Запрос производственного доступа — SES запускается в изолированной среде, которая отправляет запросы только на проверенные адреса.", + "guidanceCreds": "Используйте учетные данные SES SMTP (пользователя IAM SMTP), а не свои ключи доступа к AWS.", + "guidanceDns": "Опубликуйте записи DNS на вкладке DNS, затем повторите сканирование для подтверждения.", + "guidanceSystem": "Системная почта (сброс пароля, приглашения, уведомления) также отправляется через этот ретранслятор — если только вы не указали отдельного отправителя в разделе Настройки → Электронная почта.", + "save": "Включить ретрансляцию", + "update": "Сохранить изменения", + "disable": "Отключить реле", + "saved": "Обновлен исходящий ретранслятор.", + "disabled": "Ретранслятор отключен — возвращаемся к прямой доставке.", + "saveFailed": "Не удалось обновить ретранслятор.", + "disableFailed": "Не удалось отключить реле.", + "dnsHint": "Записи о пересылках от провайдера теперь отображаются на вкладке DNS. Опубликуйте + проверьте их на предмет полной доступности." + }, + "overview": { + "mailServer": "Почтовый сервер", + "protocolDetails": "Подробности протокола →", + "hostname": "Имя хоста", + "webmailAt": "Веб-почта по адресу", + "openWebmail": "Открыть веб-почту", + "deployWebmail": "Развертывание веб-почты", + "legacyWebmail": "Развернуто более старым приложением Openship — его можно заменить приложением webmail, которое обновляется в соответствии с вашими выпусками.", + "upgradeWebmail": "Заменить веб-почту", + "setupGuides": "Руководства по настройке", + "setupGuidesDesc": "Пошаговые инструкции по всем распространенным способам использования этого почтового ящика - от вашего телефона до вашей кодовой базы. Откроется в новой вкладке.", + "guides": { + "iosTitle": "Почта для iOS и macOS", + "iosSubtitle": "Добавить как IMAP на iPhone / iPad / Mac", + "androidTitle": "Приложение Gmail для Android", + "androidSubtitle": "Добавить в качестве сторонней учетной записи IMAP", + "desktopTitle": "Настольные клиенты", + "desktopSubtitle": "Thunderbird, Outlook, Spark, K-9", + "codeTitle": "Отправить с помощью кода", + "codeSubtitle": "Node.js , Python, везде, где работает SMTP" + }, + "mailStats": "Статистика по почте", + "statsFailed": "Сбой статистики", + "domains": "Домены", + "mailboxes": "Почтовые ящики", + "aliases": "Псевдонимы", + "storage": "Место хранения", + "messages": "Сообщения", + "totalSuffix": "{count} всего", + "quickActions": "Быстрые действия", + "addMailbox": "Добавить почтовый ящик", + "addDomain": "Добавить домен", + "reviewDns": "Просмотр записей DNS" + }, + "webmail": { + "title": "Веб-почта", + "subtitle": "Почтовый клиент, в который входят ваши пользователи.", + "opening": "Открытие проекта webmail…", + "noServerTitle": "Почтового сервера пока нет", + "noServerBody": "Веб—почта - это всего лишь клиент, для входа в который требуется почтовый сервер. Сначала настройте его, а затем вернитесь сюда, чтобы установить.", + "installTitle": "Веб-почта не установлена", + "installBody": "Разверните веб-почтовый клиент, чтобы ваши почтовые ящики можно было читать в браузере. Он устанавливается как обычный проект openship, поэтому вы управляете им в рамках проектов, как и всем остальным, что вы развертываете.", + "adoptTitle": "Веб-почта здесь не управляется", + "chooseTitle": "Какой почтовый сервер?", + "chooseBody": "У каждого почтового сервера есть своя собственная веб-почта. Выберите домен, который вы хотите открыть.", + "incompleteTitle": "Почтовый сервер еще не готов", + "incompleteBody": "{server} все еще настраивается. Webmail выполняет вход в систему, поэтому сначала завершите работу с почтовым сервером, а затем установите webmail отсюда.", + "incompleteAction": "Завершить настройку почты", + "runningNote": "Веб-почта уже запущена в {hostname}, но здесь ничто не управляет ею. При установке она включается в проект вместо того, чтобы создавать вторую." + }, + "domains": { + "heading": "Домены", + "description": "Каждая строка сопоставляется со строкой в файле vmail.domain на почтовом VPS. Дополнительные домены принимают почту, как только их MX-запись попадает сюда.", + "addDomain": "Добавить домен", + "editAction": "Редактировать", + "deleteAction": "Удалить", + "colDomain": "Домен", + "colMailboxes": "Почтовые ящики", + "colAliases": "Псевдонимы", + "colQuota": "Квота по умолчанию", + "colStatus": "Статус", + "active": "Активный", + "disabled": "Нетрудоспособный", + "primary": "Первичный", + "pendingTitle": "Публикация записей DNS для {domain}", + "pendingDescBefore": "Почта может поступать в ", + "pendingDescAfter": " как только они будут запущены. Запись MX указывает на ваш существующий почтовый сервер; DKIM был сгенерирован автоматически при добавлении домена. Добавьте их у своего поставщика DNS, затем нажмите ", + "pendingDescAction": "Я установил рекорды - продолжайте", + "pendingDescEnd": ".", + "emptyTitle": "Пока нет доменов", + "emptyDesc": "Добавьте домен, чтобы начать размещать почтовые ящики под ним. Убедитесь, что его MX-запись указывает на этот почтовый сервер.", + "acknowledgeFailed": "Не удалось подтвердить записи DNS", + "loadFailed": "Не удалось загрузить домены", + "create": { + "title": "Добавить домен", + "description": "Добавляет новую запись в vmail.domain на почтовом VPS. Убедитесь, что запись MX для этого домена указывает на почтовый сервер, прежде чем отправлять почту через него.", + "submit": "Создать домен", + "submitting": "Создание…", + "domainLabel": "Домен", + "domainHint": "например, acme.com - нет протокола, нет пути.", + "descLabel": "Описание", + "descHint": "Необязательно - отображается только на панели мониторинга.", + "descPlaceholder": "Маркетинг Acme Corp", + "quotaLabel": "Квота почтового ящика по умолчанию (ГБ)", + "quotaHint": "Необязательный. Значение по умолчанию для новых почтовых ящиков в этом домене; может быть изменено для каждого почтового ящика. Оставьте поле неограниченным." + }, + "editForm": { + "title": "Редактировать {domain}", + "submit": "Сохранить изменения", + "submitting": "Экономия…", + "descLabel": "Описание", + "quotaLabel": "Квота почтового ящика по умолчанию (ГБ)", + "quotaHint": "Оставьте пустым или равным 0 для неограниченного количества.", + "activeLabel": "Активный", + "activeDesc": "Если флажок снят, почта, адресованная в этот домен, отклоняется на шлюзе MX." + }, + "deleteForm": { + "title": "Удалить {domain}?", + "descDependents": "У этого домена все еще есть {parts}. Поставьте галочку ниже, чтобы удалить и их - файлы почтового ящика на диске будут удалены, и их невозможно будет восстановить.", + "descSimple": "Удаляет строку домена и все сопоставления с правами администратора. Почта, отправленная на этот домен, немедленно начнет отклоняться.", + "submitWithParts": "Удалить домен + {parts}", + "submit": "Удалить домен", + "submitting": "Удаление…", + "alsoDelete": "Также удалите {parts}", + "alsoDeleteDesc": "Безвозвратно удаляет все почтовые ящики в этом домене (строки базы данных и файлы Maildir на диске) вместе со всеми псевдонимами. Это невозможно отменить.", + "errorDependents": "У домена по-прежнему есть почтовый ящик {mailboxes} и псевдоним {aliases}. Отметьте \"Также удалить...\", чтобы удалить их, или сначала удалите их вручную.", + "mailboxOne": "Почтовый ящик {count}", + "mailboxOther": "Почтовые ящики {count}", + "aliasOne": "Псевдоним {count}", + "aliasOther": "Псевдонимы {count}", + "partsJoin": " и " + } + }, + "dns": { + "heading": "Записи DNS", + "description": "Записи, необходимые для доставки почты каждому домену, хранятся у вашего DNS-провайдера. Выберите домен, чтобы просмотреть его записи и убедиться, что они опубликованы.", + "domainLabel": "Домен", + "loading": "Погрузка…", + "primary": "первичный", + "recordsTitle": "Записи для публикации", + "recordsDesc": "Опубликуйте их у своего DNS-провайдера для {domain}.", + "recordsEmpty": "Мастер установки создает записи на этапе DKIM; дополнительные домены получают свои права при добавлении.", + "noRecordsFor": "В файле {domain} нет записей DNS.", + "checkTitle": "Проверка опубликованных записей", + "checkDesc": "Прямой поиск в общедоступном DNS для {domain} по сравнению с записями, приведенными выше.", + "rescan": "Повторное сканирование", + "verify": "Проверить", + "runLookupBefore": "Запустите поиск в реальном времени DNS для ", + "runLookupAfter": " и сравните это с записями выше.", + "noRecordsVerify": "В файле нет записей для проверки {domain}.", + "scanFailed": "Не удалось выполнить проверку DNS", + "expected": "Ожидаемый", + "actual": "Фактический", + "noRecord": "(нет записей)", + "pass": "Проходить", + "warning": "Предупреждение", + "fail": "Провал", + "unknown": "Неизвестный" + }, + "mailboxes": { + "heading": "Почтовые ящики", + "description": "Каждая строка представляет собой учетную запись IMAP/SMTP на почтовом сервере. Пароли хэшируются с помощью doveadm SSHA512 перед сохранением.", + "addMailbox": "Добавить почтовый ящик", + "domainLabel": "Домен", + "loading": "Погрузка…", + "activeCount": "{active} из {total} активных", + "colMailbox": "Почтовый ящик", + "colQuota": "Квота", + "colStatus": "Статус", + "unlimited": "Неограниченный", + "active": "Активный", + "disabled": "Нетрудоспособный", + "postmaster": "Почтмейстер", + "editAction": "Редактировать", + "deleteAction": "Удалить", + "loadDomainsFailed": "Не удалось загрузить домены", + "loadFailed": "Не удалось загрузить почтовые ящики", + "emptyTitle": "Почтовых ящиков пока нет", + "emptyDesc": "Создайте первый почтовый ящик для {domain}. Пароли хэшируются с помощью doveadm SSHA512 - на диске сохраняется только хэш.", + "create": { + "title": "Новый почтовый ящик · {domain}", + "description": "Создает учетную запись IMAP/SMTP на почтовом сервере. Пароль хэшируется с помощью doveadm SSHA512 на VPS - сохраняется только хэш.", + "submit": "Создать почтовый ящик", + "submitting": "Создание…", + "localPartLabel": "Локальная часть", + "localPartHint": "Часть перед @. Строчные, буквенно-цифровые.", + "fullNameLabel": "Полное имя", + "fullNameHint": "Отображаемое имя, отображаемое в почтовых клиентах. Необязательный.", + "passwordLabel": "Пароль", + "passwordHint": "Не менее 8 символов. Или создайте один из них.", + "generate": "Генерировать", + "quotaLabel": "Квота (ГБ)", + "quotaHint": "0 или пусто = неограниченно.", + "hide": "Скрыть", + "show": "Покажите", + "copy": "Копировать", + "copyPassword": "Скопировать пароль" + }, + "editForm": { + "title": "Редактировать {username}", + "submit": "Сохранить изменения", + "submitting": "Экономия…", + "fullNameLabel": "Полное имя", + "newPasswordLabel": "Новый пароль", + "newPasswordHint": "Оставьте поле пустым, чтобы сохранить текущее. Не менее 8 символов, если оно задано.", + "quotaLabel": "Квота (ГБ)", + "quotaHint": "0 или пусто = неограниченно.", + "activeLabel": "Активный", + "activeDesc": "Если флажок снят, вход в систему по протоколу IMAP завершается ошибкой, а входящая почта отскакивает." + }, + "deleteForm": { + "title": "Удалить {username}?", + "descHard": "Жесткое удаление: удаляет строки базы данных И почтовый каталог на диске. Отменить невозможно.", + "descSoft": "Мягкое удаление: задает значение active = 0 и вставляет строку в vmail.deleted_mailboxes. Программа очистки почтового сервера обнаружит ее позже. До тех пор файл Maildir остается на диске.", + "submitHard": "Жесткое удаление почтового ящика", + "submitSoft": "Автоматическое удаление почтового ящика", + "submitting": "Удаление…", + "hardDeleteLabel": "Жесткое удаление", + "hardDeleteDesc": "Немедленно удалите строки базы данных и файлы Maildir. Отменить невозможно.", + "postmasterNote": "Почтовый ящик postmaster защищен от жесткого удаления - доступно только мягкое удаление, поэтому учетная запись bootstrap почтового сервера остается неизменной." + } + }, + "aliases": { + "heading": "Псевдонимы", + "description": "Пересылайте почту с одного адреса на другой или перехватывайте все совпадающие адреса в домене. Живите моментом, который вы сохраняете, - перезагрузка не требуется.", + "addAlias": "Добавить псевдоним", + "domainLabel": "Домен", + "loading": "Погрузка…", + "activeCount": "{active} из {total} активных", + "colSource": "Источник", + "colDestination": "Пересылает в", + "colType": "Тип", + "colStatus": "Статус", + "typeAlias": "Псевдоним", + "typeCatchAll": "Всеобъемлющий подход", + "active": "Активный", + "disabled": "Нетрудоспособный", + "activateAction": "Активировать", + "deactivateAction": "Деактивировать", + "deleteAction": "Удалить", + "loadDomainsFailed": "Не удалось загрузить домены", + "loadFailed": "Не удалось загрузить псевдонимы", + "emptyTitle": "Псевдонимов пока нет", + "emptyDesc": "Переслать адрес или настроить общий доступ для {domain}.", + "create": { + "title": "Новый псевдоним · {domain}", + "description": "Создает строку в таблице пересылки почтового сервера. Postfix считывает ее в режиме реального времени - перезапуск не требуется.", + "submit": "Создать псевдоним", + "submitting": "Создание…", + "catchAllLabel": "Универсальный подход к этому домену", + "catchAllHint": "Перенаправляет все адреса в {domain}, которые не соответствуют реальному почтовому ящику или другому псевдониму. Заменяет все существующие универсальные адреса для этого домена.", + "localPartLabel": "Локальная часть", + "localPartHint": "Часть перед @. Строчные, буквенно-цифровые.", + "destinationLabel": "Пересылает в", + "destinationHint": "Любой действительный адрес электронной почты - почтовый ящик на этом сервере или внешний (например, Gmail)." + }, + "deleteForm": { + "title": "Удалить этот псевдоним?", + "sourceCatchAll": "Общая информация для {domain}", + "description": "Строка переадресации немедленно удаляется. Сообщение, отправленное на {source}, будет перенаправлено на следующее правило сопоставления, которое вступит в силу со следующим сообщением.", + "submit": "Удалить псевдоним", + "submitting": "Удаление…" + }, + "toast": { + "mailboxConflict": "{address} - это реальный почтовый ящик, поэтому при создании псевдонима его почта будет перенаправляться. Вместо этого отредактируйте или удалите почтовый ящик.", + "alreadyExists": "Такой точный форвард уже существует." + } + }, + "health": { + "heading": "Здоровье", + "description": "Текущий статус демона + проверка DNS. Демоны обновляются в ходе 10-секундного опроса; проверка DNS выполняется один раз при открытии и повторяется всякий раз, когда вы нажимаете \"Повторить проверку\".", + "healthCheckFailed": "Не удалось выполнить проверку работоспособности", + "scanFailed": "Не удалось выполнить проверку DNS", + "daemonsTitle": "Демоны", + "daemonsDesc": "Процессы почтового сервера управляются systemd на VPS.", + "updated": "обновленный {time}", + "dnsScanTitle": "Сканирование DNS", + "dnsScanDescFor": "Оперативная проверка общедоступного DNS каждой записи, которую мы ожидаем для {domain}.", + "dnsScanDesc": "Оперативная проверка всех записей, ожидаемых этим сервером, с помощью общедоступного DNS.", + "rescan": "Повторное сканирование", + "dnsEmpty": "В файле пока нет записей DNS. Завершите работу мастера установки, чтобы завершить проверку.", + "delivery": { + "title": "Исходящая доставка", + "desc": "Куда этот сервер отправляет почту и не застряло ли что-нибудь на выходе.", + "sendPath": "Путь отправки", + "direct": "Непосредственно получателям", + "directHint": "Сообщения отправляются непосредственно с этого сервера на почтовый сервер каждого получателя.", + "relay": "Ретрансляция через {host}", + "relayAll": "Каждый отправитель на этом сервере отправляет данные через ретранслятор.", + "relaySelected": "Ретранслируются только выбранные отправители: {domains}", + "queue": "Очередь", + "queueEmpty": "Пусто - ничто не ждет, чтобы погаснуть.", + "queueOne": "Сообщение {count} ожидает отправки.", + "queueOther": "Сообщения {count} ожидают отправки.", + "sampled": "Очередь больше, чем окно, которое мы читаем, поэтому приведенные ниже причины являются самыми последними.", + "reasons": "Почему почта откладывается", + "affectedOne": "Сообщение {count}", + "affectedOther": "Сообщения {count}", + "kind": { + "auth": "Аутентификация отклонена", + "tls": "Сбой шифрования", + "network": "Не удалось подключиться", + "rejected": "Отказано получателем", + "other": "Отсроченный" + }, + "hint": { + "authRelay": "Ваш ретранслятор отклонил эти учетные данные. Повторно введите имя пользователя и пароль SMTP на вкладке \"Отправка\".", + "auth": "При следующем переходе аутентификация была отклонена.", + "tls": "Не удалось согласовать TLS со следующим переходом.", + "network": "Этому серверу не удалось достичь следующего перехода. Проверьте, открыты ли исходящие порты 25 и 587.", + "rejected": "Получатель пока отклонил сообщение. Postfix продолжит повторную отправку.", + "other": "Postfix повторит попытку по своему собственному расписанию." + }, + "status": { + "ok": "Отправка", + "warn": "Отложенный", + "fail": "Не отправляет", + "unknown": "Неизвестный" + } + }, + "logs": "Бревна", + "openLogs": "Открытые журналы", + "up": "Вверх по {time}", + "menu": { + "restart": "Перезапуск", + "restarting": "Повторный запуск…", + "stop": "Остановка", + "stopping": "Остановка…", + "start": "Начать", + "starting": "Начало…" + }, + "toast": { + "started": "Запущен {label}", + "stopped": "{label} остановлен", + "restarted": "{label} перезапущен", + "startFailed": "сбой запуска", + "stopFailed": "остановка не удалась", + "restartFailed": "не удалось выполнить перезагрузку", + "startFailedTitle": "Не удалось запустить {label}", + "stopFailedTitle": "Не удалось выполнить остановку {label}", + "restartFailedTitle": "Не удалось перезапустить {label}" + }, + "daemonStatus": { + "running": "Бегущий", + "starting": "Начало", + "stopping": "Остановка", + "stopped": "Остановился", + "failed": "Неудачный", + "missing": "Недостающий", + "unknown": "Неизвестный" + }, + "dnsStatus": { + "pass": "Проходить", + "warning": "Предупреждение", + "fail": "Провал", + "unknown": "Неизвестный" + }, + "expected": "Ожидаемый", + "actual": "Фактический", + "noRecord": "(нет записей)", + "summary": { + "allGoodLabel": "Все системы в рабочем состоянии", + "allGoodSub": "Демоны запущены, и каждая запись DNS публикуется корректно.", + "almostLabel": "Почти на месте", + "almostSubOne": "Необязательная DNS-запись {count} может быть улучшена - см. раздел Проверка DNS ниже.", + "almostSubOther": "Дополнительные записи DNS {count} могут быть улучшены - смотрите раздел \"Сканирование DNS\" ниже.", + "notInstalledLabel": "{names} не установлен", + "notInstalledSubOne": "Почта по-прежнему работает без него; устанавливайте только в том случае, если вам действительно нужен этот компонент.", + "notInstalledSubOther": "Mail по-прежнему работает без них; устанавливайте только в том случае, если вам действительно нужны эти компоненты.", + "issuesLabel": "Проблемы требуют внимания", + "partDown": "{names} вниз", + "partNotInstalled": "{names} не установлен", + "partDnsOne": "Отсутствует запись DNS {count}", + "partDnsOther": "Отсутствуют записи DNS {count}", + "partDelivery": "исходящая почта не доставляется", + "almostSubQueueOne": "Сообщение {count} ожидает отправки - смотрите раздел \"Исходящая доставка\" ниже.", + "almostSubQueueOther": "Сообщения {count} ожидают отправки - смотрите раздел \"Исходящая доставка\" ниже." + }, + "time": { + "secondsAgo": "{n}s назад", + "minutesAgo": "{n}м назад", + "hoursAgo": "{n}h назад", + "daysAgo": "{n} назад" + } + }, + "backup": { + "heading": "Резервная копия", + "description": "Сделайте снимок этого почтового сервера в одном из пунктов назначения резервной копии. Чтобы переместить сервер, создайте его резервную копию здесь, настройте целевой сервер с помощью мастера установки, а затем восстановите на нем эту резервную копию.", + "schedules": { + "manual": "Только вручную", + "daily": "Ежедневный", + "weekly": "Еженедельно", + "monthly": "Ежемесячно", + "custom": "Пользовательский (cron)" + }, + "whatTitle": "Что нужно создать для резервного копирования", + "whatDesc": "Учетные записи и авторизация всегда включены; данные сообщения и ключи необязательны.", + "accountsTitle": "Учетные записи, домены и псевдонимы", + "accountsDesc": "Почтовые ящики (с хэшами паролей), домены и псевдонимы — база данных vmail.", + "messageTitle": "Данные о сообщениях почтового ящика", + "messageDesc": "Каждое сохраненное электронное письмо (почтовые папки /var/vmail). Может быть большим.", + "keysTitle": "Ключи и секреты DKIM", + "keysDesc": "Ключи DKIM + config + mail-state.json. При восстановлении DKIM остается действительным, но в архиве сохраняются закрытые ключи и секреты.", + "keysWarning": "Резервная копия будет содержать хэши паролей, закрытые ключи DKIM и секретные данные в виде открытого текста. Сохраняйте место назначения в тайне.", + "destTitle": "Пункт назначения и расписание", + "destDesc": "Резервные копии передаются в пункт назначения, которым вы управляете на странице резервных копий.", + "noDest": "Пока нет адресатов для резервных копий. Добавьте один из них (например, существующий сервер) на странице резервных копий.", + "destinationLabel": "Место назначения", + "autoLabel": "Автоматическое резервное копирование", + "timeLabel": "Время", + "timeHint": "Серверное время", + "weekdayLabel": "День недели", + "dayOfMonthLabel": "День месяца", + "cronLabel": "Выражение Cron", + "cronHint": "Пять полей, оцениваемых в часовом поясе сервера.", + "scheduleJobHint": "Автоматическое резервное копирование выполняется по расписанию.", + "manageDest": "Управлять", + "retentionTitle": "Удержание", + "retentionDesc": "Какой объем истории следует хранить в месте назначения. Старые резервные копии удаляются в ходе ежедневной очистки, включая файлы и все остальное.", + "keepCountLabel": "Оставайся последним", + "keepCountUnit": "резервные копии", + "keepDaysLabel": "Удалить после", + "keepDaysUnit": "дни", + "retentionNoLimit": "Никаких ограничений", + "retentionUnlimitedWarning": "Ничто никогда не удаляется — это место назначения будет постоянно расширяться.", + "weekdays": { + "sun": "Воскресенье", + "mon": "Понедельник", + "tue": "Вторник", + "wed": "Среда", + "thu": "Четверг", + "fri": "Пятница", + "sat": "Суббота" + }, + "saveSettings": "Сохранение настроек", + "backupNow": "А теперь отойди назад", + "recentTitle": "Последние резервные копии", + "noBackups": "Резервных копий пока нет.", + "restore": "Восстанавливать", + "migrate": "Мигрировать", + "toastTitle": "Резервная копия", + "pickDest": "Сначала выберите место назначения для резервного копирования.", + "scheduleIncomplete": "Выберите время для этого расписания или верните его в режим ручного управления.", + "saved": "Настройки резервной копии сохранены.", + "saveFailed": "Не удалось сохранить настройки резервной копии", + "started": "Начато резервное копирование. Оно будет отображаться ниже по мере выполнения.", + "startFailed": "Не удалось запустить резервное копирование" + }, + "advanced": { + "resetTitle": "Сбросить состояние на сервере?", + "resetDesc": "Удаляет отслеживание openship этой установки: файл состояния на сервере (/root/.openship/mail-state.json) И строку реестра почтового сервера. Запущенный почтовый стек не затрагивается - каждый почтовый ящик, сообщение и очередь остаются нетронутыми, - но вам нужно будет повторно запустить мастер настройки, чтобы снова управлять им (при удалении сохраняется файл состояния, так что вы можете просто повторно использовать его).", + "resetSubmit": "Состояние сброса", + "resetSubmitting": "Сброс настроек…", + "resetFailed": "Сбой сброса не удался", + "resetBox": "После этого на странице /emails снова появится мастер установки для этого сервера. Затем вы можете либо повторно запустить программу, начав с шага 1, либо продолжить с определенного шага.", + "forgetTitle": "Удалить этот почтовый сервер?", + "forgetDesc": "Удаляет этот сервер только из списка рассылки openship. Почтовый стек продолжает работать, и ничего не удаляется - ни почтовые ящики, ни сообщения, ни DNS не затрагиваются. Повторно добавьте его в любое время, проверив существующую установку.", + "forgetSubmit": "Удалить из списка", + "forgetSubmitting": "Удаление…", + "forgetFailed": "Удалить не удалось", + "forgetBox": "Используйте это, чтобы удалить устаревшую или помеченную неправильно запись. Поскольку установка на сервере осталась без изменений, ее повторное использование позже восстановит полное управление без переустановки.", + "protocolTitle": "Настройки протокола", + "protocolDesc": "Хост, порт и шифрование для входящих (IMAP) и исходящих (SMTP) сообщений. Используйте их при настройке почтового клиента вручную - большинство клиентов также могут обнаружить их по одному только адресу электронной почты.", + "incoming": "Входящий · IMAP", + "outgoing": "Исходящий · SMTP", + "host": "Хозяин", + "port": "Порт", + "security": "Безопасность", + "protocolNote": { + "p1": "Имя пользователя на обоих серверах - ваше ", + "emailAddress": "полный адрес электронной почты", + "p2": " - например. ", + "p3": ". Установите пароль от ", + "credPath": "Обзор → Учетные данные почтмейстера → Смена пароля", + "p4": "; openship никогда не сохраняет открытый текст, поэтому используйте менеджер (1Password, Bitwarden и т.д.), чтобы сохранить его." + }, + "dangerTitle": "Опасная зона", + "dangerDesc": "Эти действия могут нарушить работу почтового сервера или привести к сбою в отслеживании важных данных. Прежде чем нажимать на каждую карточку, прочтите описание.", + "rerunTitle": "Повторно запустите мастер настройки", + "rerunDesc": "Открывает мастер установки, указанный на этом сервере. Полезно после изменения DNS, переименования домена или для повторной попытки выполнить неудачный шаг. Мастер обнаруживает существующую установку и предлагает выполнить повторную попытку для каждого шага, а не удалять состояние.", + "openWizard": "Открыть мастер", + "resetCardTitle": "Сброс состояния на сервере", + "resetCardDesc": "Удаляет отслеживание openship этой установки - файл состояния на сервере (/root/.openship/mail-state.json) и строку реестра. Не удаляет почтовый ящик и не затрагивает почтовые ящики; сервер продолжает работать, но вы повторно запустите мастер настройки, чтобы снова управлять им. Используйте после ручной очистки или повторного создания образа, когда отслеживание отклонилось от реальности.", + "resetStateBtn": "Состояние сброса", + "removeTitle": "Удалить почтовый сервер", + "removeDesc": "Прекращает управление этим сервером - удаляет его только из списка /emails. Почтовый стек продолжает работать, а файл состояния на сервере остается нетронутым, поэтому вы можете повторно использовать его позже, проверив существующую установку. Используется для удаления устаревшей или неправильно помеченной записи.", + "remove": "Удалять", + "metaTitle": "Установка метаданных", + "metaServerId": "Идентификатор сервера", + "metaPrimaryDomain": "Основной домен", + "metaStartedAt": "Началось с", + "metaFinishedAt": "Законченный в", + "toolsTitle": "Инструменты для работы с почтовым пакетом", + "toolsDesc": "Действия по восстановлению, которые затрагивают запущенный стек без изменения состояния. Безопасно запускать в любое время; поток почты прерывается на несколько секунд.", + "restartCardTitle": "Перезапустить почтовый стек", + "restartCardDesc": "Запускает работу каждого почтового демона одновременно. Самое быстрое решение, если что-то пошло не так после развертывания - сбой входа в систему, остановка очереди и т.д.", + "restartStack": "Перезапуск стека", + "restartConfirmTitle": "Перезапустить почтовый стек?", + "restartConfirmDesc": "Запускает каждый запущенный почтовый демон (получатель очереди, служба IMAP, конвейер рассылки спама, fail2ban и PostgreSQL). Поток почты приостанавливается на несколько секунд, пока не будут восстановлены отправленные сообщения. Почтовые ящики, очереди и DNS остаются нетронутыми.", + "restartSubmitting": "Повторный запуск…", + "restartBox": "Используйте это, когда что-то не так сразу после развертывания или изменения конфигурации - большинство временных сбоев устраняются с помощью цикла.", + "restartedToast": "Перезапущены почтовые демоны {count}.", + "restartedTitle": "Почтовый стек перезапущен", + "partialToast": "Сбой {failed} из {total}: {units}", + "partialTitle": "Частичный перезапуск", + "restartFailed": "Не удалось выполнить перезагрузку", + "restartFailedTitle": "Не удалось перезапустить почтовый стек" + }, + "test": { + "title": "Тестовая отправка", + "description": "Отправьте настоящее тестовое электронное письмо через этот почтовый сервер, чтобы подтвердить доставку, DKIM и SPF.", + "sendButton": "Отправить тестовое электронное письмо" + }, + "reputation": { + "titlePrefix": "Репутационная разминка для ", + "body": "У новых доменов-отправителей еще нет репутации, поэтому провайдеры могут отправлять ранние письма в спам в течение первых 24-48 часов. Это нормально. Помечайте сообщения как \"не спам\" в своем тестовом почтовом ящике, и качество доставки быстро улучшится. ", + "dismissLink": "Я знаю, спрячь это", + "dismiss": "Увольнять" + }, + "engine": { + "downTitle": "Почтовый движок на этом сервере не запущен", + "downBody": "Пока он остановлен, почта не доставляется и не принимается, а это необходимо для каждой вкладки. При повторном запуске ничего не переустанавливается и конфигурация не переписывается.", + "legacyNote": "На этом сервере запущен устаревший движок host-native engine (systemd Postfix/Dovecot), поэтому нет контейнера для проверки.", + "start": "Завести двигатель", + "missingTitle": "На этом сервере нет почтового движка", + "missingBody": "Openship не может найти здесь почтовый движок — ни контейнер движка, ни модули Postfix/Dovecot. Повторно запустите программу установки почты, чтобы переустановить ее.", + "rerunSetup": "Повторно запустите программу настройки почты", + "cardBlocked": "Недоступен до тех пор, пока не будет запущен почтовый движок." + }, + "welcome": { + "invalidEmail": "Введите действительный адрес электронной почты", + "sendFailed": "Не удалось отправить", + "dismiss": "Увольнять", + "liveTitle": "Ваш почтовый сервер работает в режиме реального времени.", + "liveDescAfter": " принимает почту. Отправьте себе тест, чтобы подтвердить это.", + "sendToLabel": "Отправьте тест по адресу", + "skip": "Пропускать", + "sending": "Отправка", + "sendTest": "Отправить тест", + "sentTitle": "Уже в пути.", + "sentBefore": "Тест от ", + "sentMiddle": " направляется в ", + "sentAfter": ". Если оно придет в течение минуты - проверьте свой почтовый ящик и папку со спамом.", + "gotIt": "Понял" + }, + "restore": { + "titleMigrate": "Перенос на другой сервер", + "titleRestore": "Восстановить резервную копию", + "startFailed": "Не удалось запустить восстановление", + "applyFailed": "Не удалось применить восстановление", + "reviewBefore": "Восстановление резервной копии из ", + "reviewOntoFork": " на другой почтовый сервер.", + "reviewOntoInPlace": " на этот почтовый сервер.", + "targetServer": "Целевой сервер", + "noTargetsBefore": "Других почтовых серверов не установлено. Сначала настройте целевой сервер с помощью мастера установки (тот же домен, ", + "noTargetsAfter": "), затем он появится здесь.", + "selectServer": "Выберите сервер…", + "warnMain": "Это удалит учетные записи, домены и псевдонимы сервера {which}, а затем загрузит резервную копию.", + "warnWhichTarget": "цель", + "warnWhichCurrent": "текущий", + "warnForkExtra": "Целевой сервер должен быть настроен с тем же доменом. После миграции повторно укажите MX/A DNS + PTR на новом сервере.", + "confirmBefore": "Тип ", + "confirmAfter": " подтверждать", + "close": "Закрывать", + "cancel": "Отменить", + "migrate": "Мигрировать", + "restore": "Восстанавливать", + "progressComplete": "Восстановление завершено", + "progressFailed": "Восстановить {status}", + "startingFallback": "начало", + "subDone": "{domain} восстановлен. Почтовые демоны перезагружены.", + "subFailed": "Смотрите ошибку выше.", + "subRunning": "Перемещение учетных записей, доменов и данных сообщений. Это может занять некоторое время." + }, + "sendTest": { + "openGmail": "Откройте Gmail", + "openOutlook": "Открытый внешний вид", + "openYahoo": "Откройте Yahoo Mail", + "openIcloud": "Откройте почту iCloud", + "openProton": "Откройте протонную почту", + "openAol": "Открыть почту AOL", + "loadDomainsFailed": "Не удалось загрузить домены", + "sentToast": "Отправлено тестовое письмо. Проверьте почтовый ящик на наличие спама.", + "toastTitle": "Тестовое электронное письмо", + "sendFailed": "Не удалось отправить тестовое электронное письмо", + "close": "Закрывать", + "title": "Отправьте тестовое электронное письмо", + "sendsFromBefore": "Отправляет из ", + "sendsFromAfter": " — почтовый ящик подготавливается по запросу для этого домена и подписывается DKIM-ключом домена.", + "sendToLabel": "Отправить по адресу", + "fromDomainLabel": "Из домена", + "loadingDomains": "Загрузка доменов…", + "noActiveDomains": "Нет активных доменов", + "fromHint": "Выберите домен для аутентификации в качестве. Полезно для проверки недавно добавленного домена после распространения его записей DNS.", + "cancel": "Отменить", + "sending": "Отправка…", + "sendTest": "Отправить тест", + "sentTitle": "Отправлено тестовое электронное письмо.", + "sentCheckBefore": "Проверьте почтовый ящик на наличие спама по адресу ", + "sentCheckMiddle": ". Отправлено из ", + "sentCheckAfter": "." + }, + "shared": { + "cancel": "Отменить", + "actionFailed": "Действие не удалось", + "logsTitle": "Журналы {label}", + "reload": "Перезагрузить", + "close": "Закрывать", + "logsLoadFailed": "Не удалось загрузить журналы", + "loadingLogs": "Загрузка журналов…", + "noJournal": "Для этого устройства нет записей в журнале." + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/importProject.json b/apps/dashboard/src/i18n/locales/ru/importProject.json new file mode 100644 index 000000000..13dc7e47f --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/importProject.json @@ -0,0 +1,432 @@ +{ + "counts": { + "portOne": "Порт {count}", + "portOther": "Порты {count}", + "volumeOne": "Объем {count}", + "volumeOther": "Объемы {count}", + "serviceOne": "Сервис {count}", + "serviceOther": "Сервисы {count}", + "depOne": "{count} деп", + "depOther": "Значения {count}", + "variableOne": "Переменная {count}", + "variableOther": "Переменные {count}" + }, + "categories": { + "frontend": "Внешний интерфейс", + "backend": "Бэкэнд", + "fullstack": "Полный набор", + "static": "Статический", + "docker": "Докер", + "services": "Услуги", + "generic": "Общий" + }, + "serviceStatus": { + "running": "Бегущий", + "built": "Построенный", + "building": "Здание", + "deploying": "Развертывание", + "failed": "Неудачный", + "pending": "Ожидаемый" + }, + "buildSkeleton": { + "loading": "Загружается сеанс сборки..." + }, + "dockerSettings": { + "title": "Обнаружен файл Dockerfile", + "subtitle": "Ваш проект будет создан и развернут с использованием его файла Dockerfile", + "infoCard": "Настройки сборки не требуются - ваш файл Dockerfile определяет процесс сборки. Просто настройте порт, который прослушивает ваше приложение.", + "exposedPort": "Открытый порт", + "portHint": "Порт, который предоставляет ваш контейнер (из EXPOSE или CMD)" + }, + "buildSettings": { + "installCommandLabel": "Команда установки", + "installCommandDesc": "Команда для установки зависимостей", + "buildCommandLabel": "Команда построения", + "buildCommandDesc": "Команда для создания вашего проекта", + "outputDirectoryLabel": "Выходной каталог", + "outputDirectoryDesc": "Каталог с выводом сборки", + "sourceFolderLabel": "Исходная папка", + "sourceFolderDesc": "Создайте файл из подкаталога внутри репозитория или локального проекта.", + "composePath": { + "title": "Создать файл", + "subtitle": "Обнаруживается автоматически в корневом каталоге проекта", + "label": "Путь к вашему файлу compose", + "description": "Для репозиториев, которые хранят compose вне корневого каталога, укажите файл (deploy/stack.yml) или папку, в которой он находится (deploy/docker—compose). Повторно сканируйте репозиторий и развертывайте службы, которые в нем объявлены.", + "apply": "Сканировать", + "scanning": "Сканирующий…", + "scanFailed": "Не удалось отсканировать этот путь к компоновке.", + "subtitleOptIn": "Развертывание с помощью Docker Compose? Укажите на файл." + }, + "healthCheck": { + "title": "Проверки работоспособности", + "subtitle": "Выкл. — развертывание завершается, как только ваше приложение запускается.", + "subtitleOn": "В процессе развертывания ваше приложение ожидает запуска в эксплуатацию—", + "description": "Openship не ожидает запуска вашего приложения после его запуска, поэтому медленная загрузка никогда не задерживает развертывание и не приводит к сбою. Как только оно запущено, порт все равно проверяется и сообщается о нем, ничего не блокируя. Включайте это только в том случае, если вы хотите, чтобы само развертывание не запускалось.", + "probeLabel": "Дождитесь ответа от приложения", + "probeDesc": "После запуска контейнера наберите порт приложения и дождитесь, пока оно примет соединение.", + "pathLabel": "HTTP-путь", + "pathPlaceholder": "/здоровье", + "pathDesc": "Для ответа на запрос ниже 500 требуется получить ответ здесь. Оставьте поле пустым, чтобы принять любое TCP-соединение, которое также работает для служб, отличных от HTTP.", + "timeoutLabel": "Сдавайтесь через (секунды)", + "stabilizationLabel": "Следите за циклами перезапуска", + "stabilizationDesc": "Следите за контейнером после его запуска и сообщайте о сбое цикла. Считывает данные из среды выполнения, так что это работает и на удаленных серверах.", + "stabilizationWindowLabel": "Наблюдайте в течение (секунд)", + "onFailureLabel": "Если проверка завершится неудачей", + "onFailureWarn": "Продолжайте развертывание в режиме реального времени и отметьте его для проверки", + "onFailureFail": "Завершите развертывание с ошибкой и сохраните работоспособность предыдущей версии" + }, + "buildImageLabel": "Создание имиджа", + "buildImageDesc": "Образ контейнера Builder для облачных или серверных сборок. Переопределите его, если обнаруженный базовый образ неверен.", + "productionPathsLabel": "Производственные пути", + "productionPathsDesc": "Развертывайте эти файлы/каталоги только после того, как сборка скроет исходный код из среды выполнения. Оставьте поле пустым для запуска на месте.", + "startCommandLabel": "Команда запуска", + "startCommandDesc": "Команда для запуска вашего приложения", + "productionPortDesc": "Производственный порт для вашего приложения", + "productionPort": "Производственный порт", + "portForPrefix": "Порт для", + "pathForPrefix": "Путь для", + "enterPort": "Вход в порт", + "optional": "(опционально)", + "save": "Сохранить", + "cancel": "Отменить", + "deployConfig": "Развертывание конфигурации", + "defaultsApplied": "Применены значения {framework} по умолчанию", + "configureOptions": "Настройка параметров сборки", + "build": "Строить", + "installBuildIn": "Установка и сборка в {image}", + "installBuildCommands": "Команды установки и сборки", + "deploySourceDirectly": "Непосредственное развертывание исходного кода", + "advanced": "Передовой", + "start": "Начать", + "serverOnPort": "Сервер на порту {port}", + "serverPortNotSet": "Порт сервера не задан", + "staticFromEdge": "Статические помехи с края", + "staticPathHint": "Обрабатываются как статические файлы с самого начала — ничто не запускается как процесс.", + "modeServer": "Сервер", + "modeWorker": "Работник", + "modeStatic": "Статический", + "workerModeDesc": "Выполняется непрерывно без использования порта или общедоступного URL— адреса - пользователя очереди, cron или бота.", + "buildSettingsTitle": "Настройки сборки" + }, + "projectSettings": { + "framework": "Рамки", + "detected": "Обнаруженный", + "change": "Изменить", + "useDetected": "Обнаруженное использование", + "selectHint": "Выберите свой фреймворк для автоматической настройки параметров сборки" + }, + "routingSection": { + "title": "Маршрутизация", + "descDetected": "Перезаписи, перенаправления и заголовки — обслуживаются в одном домене." + }, + "environmentVariables": { + "title": "Переменные среды", + "noneSet": "Не установлено", + "pasteEnv": "Вставить .env", + "uploadEnv": "Загрузить .env", + "edit": "Редактировать", + "cancel": "Отменить", + "saving": "Экономия...", + "saveChanges": "сохранить изменения", + "collapse": "Свернуть переменные среды", + "expand": "Разверните переменные среды", + "valuePlaceholder": "ценность", + "dropHere": "Сбросьте файл .env сюда", + "noneTitle": "Нет переменных окружения", + "emptyHintEditing": "Нажмите \"Добавить переменную\", используйте \"Вставить .env\", загрузите файл или вставьте в любое место внутри этого поля", + "emptyHintReadonly": "Нажмите \"Изменить\", чтобы управлять переменными среды", + "pasteHint": "Вставьте полный блок .env в любое место внутри этого поля.", + "addVariable": "Добавить переменную", + "delete": "Удалить", + "resolution": { + "needsValue": "Нуждается в ценности", + "fallbackDefault": "Резервный вариант по умолчанию", + "loadedFromEnv": "Загружается из файла .env", + "interpolated": "Интерполированный" + }, + "toast": { + "title": "Переменные среды", + "added": "Добавлен {count}", + "updated": "{count} обновлен", + "pastedOne": "Вставленный {count} переменный{detail}", + "pastedOther": "Вставленные {count} переменные {detail}", + "portSet": "Порт времени выполнения установлен в {port} из порта", + "clipboardUnavailable": "Доступ к буферу обмена здесь недоступен. Щелкните в поле \"Среда\" и вставьте с помощью Cmd/Ctrl+V.", + "clipboardEmpty": "Буфер обмена пуст", + "clipboardInvalid": "Буфер обмена не содержит допустимых переменных окружения KEY=VALUE", + "clipboardBlocked": "Доступ к буферу обмена был заблокирован. Щелкните в поле \"Среда\" и вставьте с помощью Cmd/Ctrl+V." + }, + "reveal": { + "show": "Показывать значения", + "hide": "Скрывать значения", + "error": "Не удалось выявить значения" + } + }, + "composeServices": { + "domain": { + "internalService": "Внутренняя служба", + "noPublicPorts": "Общедоступных портов не обнаружено", + "publicDomain": "Общественное достояние", + "internetEnabled": "Включен интернет-трафик", + "privateByDefault": "Закрытый по умолчанию", + "exposedPort": "Открытый порт", + "portOption": "Порт {port}", + "domainLabel": "Домен", + "free": "Свободный", + "custom": "Обычай", + "routingTrafficPrefix": "Маршрутизация трафика в порт", + "duplicateTitle": "Дублирующийся домен", + "duplicateDescription": "Два маршрута ведут в один и тот же домен — измените один из них, чтобы у каждого маршрута был свой собственный:" + }, + "shared": { + "title": "Общая среда", + "rootEnvFound": "Найден Root .env", + "optionalVars": "Необязательные переменные, применяемые к каждой службе", + "sharedVariableOne": "{count} общая переменная", + "sharedVariableOther": "{count} общие переменные", + "overrideNote": "· служебные ценности переопределяют общие ценности.", + "importEnv": "Импорт .env", + "manage": "Управлять", + "modalSubtitle": "Применяется ко всем сервисам. Служебные переменные выигрывают в конфликте.", + "close": "Тесная общая среда", + "importFromRootOne": "Импорт переменной {count} из root .env", + "importFromRootOther": "Импорт переменных {count} из root .env" + }, + "config": { + "title": "Конфигурация", + "summary": "{ports} · {volumes}", + "ports": "Порты", + "containerLabel": "Контейнер", + "publishedLabel": "Опубликованный", + "equalsInsideService": "= внутри сервиса ·", + "equalsReachableHost": "= доступен на хосте.", + "cloudPortIgnored": "В облаке опубликованный порт игнорируется — маршрутизируется только порт контейнера.", + "naOnCloud": "n/a в облаке", + "publicBadge": "общественный", + "removePort": "Удалить порт", + "addPort": "Добавить порт", + "volumes": "Тома", + "statefulWarnPart1": "Служба с отслеживанием состояния в облаке: данные хранятся на постоянном диске рабочей области (после перезагрузки), но сохраняются ", + "statefulWarnBold": "не переносится при перестроении", + "statefulWarnPart2": " если не включено резервное копирование. Подключение томов Docker не применяется.", + "volumeHint": "Путь к именованному тому или хосту → путь к контейнеру.", + "volumeCloudNote": "В облаке эти подключения неприменимы — данные сохраняются на диске рабочей области (не при восстановлении без резервного копирования).", + "sourcePlaceholder": "Источник", + "containerPathPlaceholder": "Путь к контейнеру", + "readOnlyMount": "Монтирование только для чтения", + "removeVolume": "Уменьшите громкость", + "addVolume": "Добавьте громкости", + "command": "Команда", + "imageDefault": "(изображение по умолчанию)", + "restartPolicy": "Политика перезапуска", + "restartDefault": "По умолчанию (если только-не остановлено)" + }, + "status": { + "public": "Общественный", + "private": "Частный", + "internal": "Внутренний" + }, + "card": { + "buildLabel": "Сборка: {value}", + "edit": "Редактировать", + "delete": "Удалить", + "envVars": "Переменные среды", + "noneConfigured": "Ничего не настроено", + "variablesConfiguredOne": "Настроенная переменная {count}", + "variablesConfiguredOther": "Сконфигурированные переменные {count}", + "missingSuffix": "· {count} отсутствует", + "manage": "Управлять", + "variableSuffixOne": "· Переменная {count}", + "variableSuffixOther": "· Переменные {count}", + "closeEnv": "Близкие переменные окружения", + "needsValueOne": "Требуется значение переменной окружения {count}", + "needsValueOther": "Переменные среды {count} должны иметь значение" + }, + "main": { + "deployingServices": "Развертывание в качестве служб", + "deployingSingle": "Развертывание как единого приложения", + "buildCountSuffix": "· Сборка {count}", + "exposedCountSuffix": "· {count} открытый", + "infoPart1": "Внутренние службы могут связываться друг с другом по названию службы. Включить ", + "infoBold": "Общественное достояние", + "infoPart2": " только для сервисов, которые должны получать интернет-трафик.", + "singleAppNote": "Обработанные сервисы compose сохраняются на более поздний срок, но при этом развертывании будет использоваться обычная сборка из одного приложения, команда запуска, параметры среды и домена.", + "modeServicesLabel": "Стек сервисов", + "modeServicesDesc": "Разверните каждую службу compose с ее собственной средой выполнения и доменом.", + "modeSingleLabel": "Одно приложение", + "modeSingleDesc": "Используйте обычный поток команд сборки и запуска для одного приложения.", + "deploymentMode": "Режим развертывания", + "deploymentModeDesc": "{mode} · Переключение между стеком сервисов и обработкой одного приложения." + } + }, + "monorepo": { + "workspace": { + "title": "Рабочее место", + "subtitle": "Запускается один раз в корневом каталоге репозитория перед каждой сборкой приложения — установкой, codegen, синхронизацией схемы и т.д.", + "packageManager": "Менеджер пакетов", + "prepareCommand": "Команда подготовки", + "chainPrefix": "Цепь с", + "chainSuffix": "для codegen, синхронизации схем и т.д." + }, + "app": { + "collapse": "Коллапс", + "expand": "Расширять", + "portSuffix": "· порт {port}", + "deployAria": "Разверните это вспомогательное приложение", + "deploy": "Развертывать" + }, + "header": { + "title": "Обнаружены приложения Monorepo - {count}", + "singleDesc": "Развертывание как единое приложение - один контейнер, один набор команд, доступны все порты.", + "multiDesc": "Выбран {selected} вместо {total}. Каждое приложение развертывается на своем собственном порту и домене, используя одно рабочее пространство для установки в корневом хранилище." + }, + "singleNote": "Определения вложенных приложений будут сохранены на более поздний срок. В этом развертывании используются обычные команды сборки и запуска для одного приложения, приведенные ниже - порт каждого включенного вложенного приложения доступен из одной и той же среды выполнения.", + "modes": { + "servicesLabel": "Среда выполнения для каждого приложения", + "servicesDesc": "Разверните каждое дополнительное приложение с его собственной средой выполнения, портом и доменом.", + "singleLabel": "Одно приложение", + "singleDesc": "Продвигайте команду build + start для одного вложенного приложения, предоставляйте доступ к портам каждого приложения из одной среды выполнения." + }, + "deploymentMode": "Режим развертывания", + "deploymentModeDesc": "{mode} · Переключение между временем выполнения каждого приложения и обработкой в одном приложении." + }, + "deploymentProcessing": { + "targetOpenshipCloud": "Облако Openship", + "targetServerNamed": "Сервер · {name}", + "targetServer": "Сервер", + "targetLocal": "Локальный компьютер", + "strategyLocal": "Локальная сборка", + "strategyCloud": "Построение облака", + "strategyServer": "Сборка сервера", + "strategyHost": "Сборка хоста", + "promptDetails": { + "port": "Порт", + "process": "Процесс", + "unitDescription": "Описание устройства", + "openshipDeployment": "Развертывание Openship", + "sites": { + "lead": "Сайты {count} в настоящее время обслуживаются существующим прокси-сервером. При переносе они импортируются в Openship, прежде чем будут использованы порты 80/443:", + "tlsBadge": "TLS (Протокол TLS)", + "staticLabel": "статический:", + "warningsTitle": "Не удалось перенести автоматически — повторно добавьте их вручную:" + } + }, + "portAdvisory": { + "title": "Это правильный порт?", + "bannerTitle": "Возможно, порт настроен неправильно", + "review": "Обзор", + "note": "Маршрутизация указывает на этот порт — если он неверен, запросы будут завершаться ошибкой с 502.", + "body": "Порт {port} ничего не ответил. Если ваше приложение прослушивает другой порт, укажите правильный здесь.", + "bodyService": "Служба \"{service}\": порт {port} не отвечает. Если он прослушивает другой порт, укажите правильный здесь.", + "newPortLabel": "Правильный порт", + "changePort": "Изменить порт", + "skip": "Пропускать", + "applied": "Маршрутизация обновлена до порта {port}.", + "changeError": "Не удалось обновить порт. Пожалуйста, попробуйте снова." + }, + "title": { + "cancelled": "Развертывание отменено", + "failed": "Не удалось выполнить развертывание", + "readyWarnings": "Готовность к развертыванию С Предупреждениями", + "successful": "Успешное развертывание", + "deploying": "Развертывание..." + }, + "visitSite": "Посетите сайт", + "warningTitle": "Развертывание завершено, но некоторые службы по-прежнему требуют внимания.", + "productionLogs": "Производственные журналы", + "buildTerminal": "Построить терминал", + "seeLogs": "Подробные сведения о проблеме см. в журналах", + "redeploying": "Повторное развертывание…", + "stopping": "Остановка…", + "stopDeployment": "Остановить развертывание", + "redeploy": "Повторно развернуть", + "goToProject": "Перейти к проекту", + "openDashboard": "Открыть панель управления", + "edit": "Редактировать", + "status": { + "cancelled": "Отмененный", + "failed": "Неудачный", + "readyWarnings": "Будьте готовы к предупреждениям", + "ready": "Готов", + "building": "Здание" + }, + "detailsTitle": "Подробные сведения о развертывании", + "detailStatus": "Статус", + "detailInstance": "Пример", + "detailBuild": "Строить", + "detailBuildTime": "Время создания", + "detailFramework": "Рамки", + "detailBranch": "Ветка", + "detailDomains": "Домены", + "detailDomain": "Домен" + }, + "composeDeployment": { + "title": { + "cancelled": "Развертывание отменено", + "failed": "Не удалось выполнить развертывание", + "actionRequired": "Необходимые действия", + "warnings": "Развертывается с Предупреждениями", + "successful": "Успешное развертывание", + "deploying": "Развертывание служб…" + }, + "running": "бегущий", + "buildingSuffix": "· Здание {count}", + "failedSuffix": "· Ошибка {count}", + "decisionBannerTitle": "Требуется действие — сбой в работе некоторых служб", + "decisionBannerDefaultMsg": "Это развертывание завершилось сбоем в работе служб. Сохраните его и исправьте позже или отклоните, чтобы восстановить предыдущую версию.", + "review": "Обзор", + "warningTitle": "Некоторые службы требуют особого внимания", + "redeploying": "Повторное развертывание…", + "stopping": "Остановка…", + "stopDeployment": "Остановить развертывание", + "redeploy": "Повторно развернуть", + "openDashboard": "Открыть панель управления", + "editConfiguration": "Редактировать конфигурацию", + "logsTitle": "Журналы развертывания", + "logsSubtitle": "Прямая трансляция для каждой службы", + "prepareTab": "Подготовить", + "noLogsFor": "Для {service} не было записано никаких логов.", + "waitingFor": "Ждем логи {service}...", + "noPrepareLogs": "Журналы подготовки не регистрировались.", + "preparingContext": "Клонирование исходного кода и подготовка контекста сборки...", + "preparingServiceLogs": "Подготовка служебных журналов...", + "toast": { + "keptMsg": "Развертывание сохранено", + "keptTitle": "Держал", + "rejectedMsg": "Отклонено частичное развертывание", + "rejectedTitle": "Отменено развертывание", + "retryFailMsg": "Не удалось запустить повторную попытку", + "retryTitle": "Повторить попытку" + }, + "partial": { + "title": "Развертывание завершено со сбоем в работе служб", + "body": "Службы {failed} или {total} завершились сбоем, но остальная часть стека была успешно развернута. Вы можете сохранить это развертывание и исправить сбойные службы позже или отклонить его и восстановить предыдущее развертывание.", + "warning": "Предупреждение", + "rejectNote": "Отклонение приводит к удалению контейнеров этого частичного развертывания и, если существует предыдущее развертывание, восстанавливает его. Запись о развертывании и журналы его сборки сохраняются в вашей истории, чтобы вы могли просмотреть, что не удалось выполнить.", + "keep": "Сохраните И Исправьте Позже", + "rejecting": "Отвергающий...", + "reject": "Отклонить развертывание", + "retrying": "Повторяем попытку...", + "retryOne": "Повторите попытку сбоя службы {count}", + "retryOther": "Повторите попытку {count} Сбойных служб" + } + }, + "composeSidebar": { + "status": { + "cancelled": "Отмененный", + "failed": "Неудачный", + "warnings": "Предупреждения", + "ready": "Готов", + "deploying": "Развертывание" + }, + "detailsTitle": "Подробные сведения о развертывании", + "rowStatus": "Статус", + "rowBuildTime": "время создания", + "rowServices": "Услуги", + "rowProject": "Проект", + "rowType": "Тип", + "running": "бегущий", + "buildingSuffix": "· Здание {count}", + "failedSuffix": "· Ошибка {count}" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/issues.json b/apps/dashboard/src/i18n/locales/ru/issues.json new file mode 100644 index 000000000..979abcd6c --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/issues.json @@ -0,0 +1,92 @@ +{ + "title": "Проблемы", + "subtitle": "Все, что Openship обнаружил неправильного в ваших проектах, серверах и доменах.", + "tabs": { + "open": "Открыть", + "resolved": "Решенный" + }, + "resolvedNote": "История охватывает инциденты с контейнерами и серверами — другие проверки сообщают о текущем состоянии, поэтому фиксированный сертификат или развертывание просто перестают отображаться здесь.", + "rescan": "Повторное сканирование", + "rescanning": "Сканирующий", + "filters": { + "searchPlaceholder": "Проблемы с поиском", + "all": "Все", + "outage": "Перерыв в работе", + "action_required": "Необходимые действия", + "advisory": "Консультативный", + "clear": "Очистить фильтры" + }, + "scopes": { + "platform": "XBRANDОТКРЫТИЕ X", + "server": "Серверы", + "project": "Проекты", + "domain": "Домены" + }, + "scopeSubtitles": { + "platform": "Сама эта установка", + "server": "Машины, на которых выполняются ваши рабочие нагрузки", + "project": "Развернутые проекты и их контейнеры", + "domain": "Пользовательские имена хостов и сертификаты" + }, + "kinds": { + "deploy_blocked": "Развертывание заблокировано", + "prompt": "В ожидании решения", + "partial_decision": "Частичное освобождение", + "routing_unsynced": "Маршрутизация не синхронизирована", + "domain_unverified": "Домен не подтвержден", + "ssl_error": "Проблема с сертификатом", + "port_advisory": "Консультирование по портам", + "workload_unhealthy": "Неудачные проверки работоспособности", + "workload_crash_loop": "Аварийное зацикливание", + "workload_down": "Контейнер опущен", + "server_unreachable": "Сервер недоступен", + "edge_down": "Край вниз", + "edge_absent": "Кромка не установлена", + "mail_down": "Почтовый движок отключен", + "update_available": "Доступно обновление", + "component_behind": "Доступно обновление компонентов" + }, + "since": "Запущен {when}", + "resolvedWhen": "Разрешенный {when}", + "expiresIn": "Прерывается в {n} мин", + "view": "Смотреть", + "fix": "Чинить", + "install": "Устанавливать", + "update": "Обновление", + "mailSetup": "Настройка почты", + "selfUpdateNote": "Эта установка обновляется самостоятельно из командной строки.", + "empty": { + "openTitle": "Ничто не требует внимания", + "openBody": "Никаких заблокированных или ожидающих развертываний, никаких проблем с сертификатами или доменом, ничего не задерживается и не используется на неправильном порту. Проверки продолжаются в фоновом режиме.", + "resolvedTitle": "Ни один инцидент не был разрешен", + "resolvedBody": "Инциденты с контейнерами и серверами отображаются здесь после их восстановления и сохраняются в течение 30 дней.", + "filteredTitle": "Спичек нет", + "filteredBody": "Некоторые вопросы остаются открытыми — ни один из них не соответствует этому фильтру." + }, + "summary": { + "title": "Обзор", + "subtitle": "Здоровье с первого взгляда", + "totalOpen": "открывать", + "totalResolved": "решенный", + "bySeverity": "По степени тяжести", + "byArea": "По площади" + }, + "home": { + "attentionTitle": "Нуждается во внимании", + "attentionSubtitle": "Что-то сломано или ждет вас", + "updatesTitle": "Доступные обновления", + "updatesSubtitle": "Новые версии, готовые к применению", + "more": "{n} еще", + "hide": "Прячься, пока что-нибудь не изменится" + }, + "loadFailed": "Не удалось загрузить проблемы", + "toast": { + "title": "Проблемы", + "rescanned": "Повторное сканирование завершено", + "rescanPartial": "Повторное сканирование завершено, проверка {n} не выполнена", + "rescanFailed": "Повторное сканирование завершилось неудачей", + "resolved": "Сделано", + "resolveFailed": "Не удалось применить это исправление", + "confirmDestructive": "У этого есть побочный эффект, который нельзя устранить. Продолжить?" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/jobs.json b/apps/dashboard/src/i18n/locales/ru/jobs.json new file mode 100644 index 000000000..fa80f83f6 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/jobs.json @@ -0,0 +1,186 @@ +{ + "backups": { + "section": "Расписания резервного копирования", + "sectionDesc": "Автоматическое резервное копирование, запланированное для каждого проекта или службы. Управление осуществляется на вкладке Резервные копии каждого проекта.", + "projectDefault": "Проект по умолчанию", + "mailServer": "Почтовый сервер", + "manage": "Управление резервными копиями", + "badge": "Резервная копия", + "never": "Никогда не убегай", + "status": { + "succeeded": "Преуспевший", + "failed": "Неудачный", + "cancelled": "Отмененный", + "running": "Бегущий" + } + }, + "title": "Работы", + "subtitle": "Встроенные функции обслуживания и пользовательские команды, выполняемые на ваших серверах.", + "empty": "Запланированных заданий пока нет.", + "searchPlaceholder": "Поиск работы…", + "noResults": "Ни одна работа не соответствует вашим фильтрам.", + "overview": { + "title": "На первый взгляд", + "subtitle": "Задания в этом экземпляре", + "all": "Все задания", + "running": "Бегущий", + "failed": "Неудачный", + "scheduled": "Планируемый", + "disabled": "Нетрудоспособный" + }, + "loadFailed": "Не удалось загрузить задания.", + "kind": { + "system": "Система", + "custom": "Обычай" + }, + "fields": { + "schedule": "График", + "nextRun": "Следующий запуск", + "lastRun": "Последний заход", + "never": "Никогда не убегай", + "notScheduled": "Не запланировано" + }, + "status": { + "success": "Успех", + "failed": "Неудачный", + "running": "Бегущий" + }, + "actions": { + "run": "Беги сейчас же", + "running": "Бегущий…", + "edit": "Редактировать расписание", + "save": "Сохранить", + "cancel": "Отменить", + "enable": "Включить", + "disable": "Отключать", + "viewLogs": "Бревна" + }, + "cronHint": "Стандартный 5-полевой хронометр (минута, час, день недели, месяц), UTC.", + "toast": { + "ran": "Запущен {label}.", + "ranFailed": "Не удалось запустить {label}.", + "saved": "Расписание обновлено для {label}.", + "saved2": "Задание обновлено.", + "saveFailed": "Не удалось обновить {label}.", + "enabled": "Включен {label}.", + "disabled": "{label} отключен.", + "toggleFailed": "Не удалось обновить {label}.", + "title": "Работы", + "created": "Работа создана.", + "createFailed": "Не удалось создать задание.", + "deleted": "Задание удалено.", + "deleteFailed": "Не удалось удалить задание." + }, + "newJob": "Новая работа", + "sections": { + "system": "Системные задания", + "systemDesc": "Встроенное обслуживание в этом экземпляре.", + "custom": "Пользовательские задания", + "customDesc": "Команды, которые вы запускаете на своих серверах по расписанию." + }, + "customEmpty": { + "title": "Пока нет пользовательских заданий", + "desc": "Запустите команду на одном из ваших серверов — по расписанию, один раз или по событию — с повторными попытками, секретами, оперативными журналами и уведомлениями.", + "cta": "Создать задание", + "docs": "Доктора" + }, + "create": { + "title": "Новая работа", + "name": "Имя", + "namePlaceholder": "Ночной вакуум DB", + "server": "Сервер", + "servers": "Серверы", + "noServers": "Серверы еще не подключены — сначала добавьте один.", + "command": "Команда", + "commandPlaceholder": "pg_dump ... > /резервные копии/db.sql", + "commandHint": "Запускается по SSH на выбранных серверах. Команда `docker run --rm image cmd` также работает.", + "scheduleType": "Когда нужно бежать", + "scheduleTypes": { + "recurring": "По расписанию", + "once": "Однажды", + "manual": "Инструкция" + }, + "sections": { + "basics": "Основы", + "schedule": "График", + "servers": "Целевые серверы", + "reliability": "Надежность", + "environment": "Окружающая среда", + "triggers": "Зависимости и триггеры", + "notifications": "Уведомления" + }, + "schedule": "Расписание (cron)", + "runAt": "Бежать по", + "manualHint": "Запускается только при запуске — выполнить сейчас, зависимости или событии.", + "timeout": "Тайм-аут (ы)", + "retryAttempts": "Максимальное количество попыток", + "retryBackoff": "Отсрочка (ы)", + "advanced": "Передовой", + "env": "Переменные среды", + "addVar": "Добавить переменную", + "secrets": "Секреты", + "addSecret": "Добавить секрет", + "replaceSecrets": "Замените секреты", + "secretsSet": "набор секретов", + "noSecrets": "Никаких секретов не установлено.", + "dependencies": "Бегать за", + "dependenciesHint": "Это задание выполняется после успешного выполнения выбранных заданий.", + "triggers": "Триггеры событий", + "notifications": "Уведомления", + "noChannels": "Каналов уведомлений пока нет — добавьте их в меню Настройки → Уведомления.", + "notificationsHint": "Переопределяет глобальные настройки уведомлений для этого задания.", + "submit": "Создать задание", + "creating": "Экономия…", + "cancel": "Отменить", + "needServer": "Сначала подключите сервер", + "pasteEnv": "Вставить .env", + "uploadEnv": "Загрузить .env", + "envPasteEmpty": "Переменные не найдены", + "comingSoon": "Скоро", + "setupChannel": "Настройка канала", + "customTriggerSoon": "Пользовательский триггер", + "docsLink": "Узнайте больше о рабочих местах", + "docsBody": "Расписания, повторные попытки, секреты и уведомления", + "summary": { + "title": "Резюме", + "command": "Команда", + "schedule": "График", + "targets": "Цели", + "retry": "Повторить попытку", + "timeout": "Перерыв", + "notify": "Уведомления", + "none": "—", + "retryOff": "Никто" + } + }, + "edit": { + "title": "Редактировать задание", + "action": "Редактировать", + "save": "Сохранить изменения" + }, + "detail": { + "back": "Вернуться к работе", + "tabs": { + "overview": "Обзор", + "runs": "Бежит" + }, + "servers": "Серверы", + "retry": "Повторить попытку", + "retryValue": "Попытки {n}, отказ {s}s", + "notifyValue": "Каналы {c} на {s}", + "onceAt": "Однажды в", + "noRuns": "Пока никаких пробежек." + }, + "delete": { + "action": "Удалить", + "confirm": "Удалить это задание?", + "deleting": "Удаление…" + }, + "logs": { + "title": "Запуск журналов", + "streaming": "Потоковый…", + "empty": "Результатов пока нет.", + "close": "Закрывать", + "exit": "Код выхода {code}" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/library.json b/apps/dashboard/src/i18n/locales/ru/library.json new file mode 100644 index 000000000..76ce6e759 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/library.json @@ -0,0 +1,187 @@ +{ + "ghCliConsent": { + "title": "Читали ваши репозитории?", + "body": "OpenShip может перечислить ваши репозитории на GitHub, используя gh CLI, в который вы уже вошли.", + "bodyWithLogin": "OpenShip может перечислить ваши репозитории на GitHub, используя gh CLI, в который вы вошли как @{login}.", + "pointNoCloud": "Ничего не отправляется в облако — список никогда не покидает этот компьютер.", + "pointDesktopOnly": "Запускается только в настольном приложении, используя ваш локальный gh auth.", + "pointReadOnly": "Доступно только для чтения: в нем перечислены хранилища, чтобы вы могли выбрать одно из них для развертывания.", + "allow": "Позволять" + }, + "page": { + "title": "Новый проект", + "subtitle": "Импортируйте репозиторий, вставьте URL-адрес или начните с шаблона", + "tabs": { + "folder": "Папка", + "github": "ГитХаб", + "url": "URL-АДРЕС Git", + "template": "Шаблон" + } + }, + "connect": { + "connectGithub": "Подключите GitHub", + "manageInSettings": "Другие способы подключения", + "terminal": { + "title": "Подключите GitHub", + "checkConnection": "Проверьте подключение", + "afterLogin": "После входа в систему нажмите \"Проверить подключение\", чтобы продолжить." + }, + "deviceFlow": { + "title": "Войдите на GitHub", + "goToPrefix": "Идти к", + "goToSuffix": "Введите этот код на GitHub, чтобы завершить вход в систему.", + "waiting": "Ожидание авторизации…", + "openGithub": "Откройте GitHub", + "copyCode": "Нажмите, чтобы скопировать" + }, + "default": { + "title": "Подключите GitHub для развертывания", + "descSelfHosted": "Выберите способ доступа Openship к вашим репозиториям.", + "descSaas": "Привяжите свою учетную запись на GitHub, чтобы просматривать репозитории и развертывать их при каждом нажатии.", + "recommended": "Рекомендуемый", + "cloudApp": "Облачное приложение Openship на GitHub", + "cloudAppDesc": "Управляемое приложение GitHub — развертывается на удаленных серверах с помощью токенов с коротким сроком службы.", + "connectCloud": "Подключите облако Openship", + "manual": "Ручное подключение к GitHub", + "manualDesc": "Настройте в настройках — ваше собственное приложение на GitHub /OAuth или gh CLI этого экземпляра. Нет учетной записи Openship.", + "manualCta": "Настроить в настройках", + "localBuilds": "Локальные сборки", + "ghCli": "Войдите в систему с помощью GitHub", + "ghCliDesc": "Войдите в систему через браузер с помощью кода устройства. Нет настройки приложения, нет SSH, нет учетной записи Openship.", + "useGhCli": "Регистрироваться", + "connecting": "Связывающий…", + "byoc": "SSH-ключ или токен доступа", + "byocDesc": "Предоставьте свои собственные учетные данные — ключ развертывания для каждого сервера или токен. Вход не требуется.", + "byocCta": "Устанавливать" + }, + "token": { + "title": "Подключитесь с помощью токена GitHub", + "connect": "Подключить", + "create": "Создайте токен на GitHub", + "failed": "Не удалось сохранить токен." + } + }, + "folderUpload": { + "emptyFolder": "Эта папка выглядит пустой (или все было проигнорировано). Выберите папку проекта.", + "uploadError": "Не удалось загрузить папку", + "stackTitle": "Что вы внедряете?", + "stackDesc": "Выберите стек для своей папки — это задаст среду сборки. Затем вы загрузите его.", + "backToStack": "Вернуться к выбору стека", + "uploadTitle": "Загрузите свою папку {stack}", + "uploadSubtitle": "Упаковано в вашем браузере — node_modules, .git и выходные данные сборки пропущены", + "dropTitle": "Выберите папку вашего проекта или нажмите для просмотра", + "dropSubtitle": "Вся папка загружается и создается как приложение {stack}", + "filesSingular": "Файл {count}", + "filesPlural": "Файлы {count}", + "clearSelection": "Четкий выбор", + "packing": "Упаковочная папка…", + "uploading": "Загрузка…", + "continue": "Продолжать" + }, + "localProjects": { + "title": "Местные проекты", + "loading": "Загрузка...", + "projectCountSingular": "Проект {count}", + "projectCountPlural": "Проекты {count}", + "import": "Импорт", + "empty": { + "title": "Пока нет местных проектов", + "description": "Импортируйте папку проекта с вашего компьютера, чтобы отсканировать, создать и развернуть ее локально", + "importProject": "Импорт проекта", + "howItWorks": "Как это работает", + "dropTitle": "Отбрасывать или просматривать", + "dropDesc": "Выберите любую папку проекта", + "autoDetectTitle": "Автоматическое обнаружение", + "autoDetectDesc": "Найден фреймворк и конфигурация", + "deployTitle": "Развертывание локально", + "deployDesc": "Сборка и запуск на вашем компьютере" + }, + "form": { + "title": "Импорт из папки", + "scanErrorDefault": "Не удалось просканировать каталог", + "dropTitle": "Выберите папку здесь или нажмите для просмотра", + "dropSubtitle": "Выберите папку вашего проекта для автоматического определения фреймворка", + "folderViaBrowser": "Папка, выбранная через браузер - пожалуйста, введите полный абсолютный путь и нажмите Сканировать", + "folderDropped": "Удалена папка - пожалуйста, введите полный абсолютный путь и нажмите Сканировать", + "pathPlaceholder": "/путь/к/вашему/проекту", + "browse": "Просматривать", + "scan": "Сканировать", + "importError": "Не удалось импортировать проект", + "projectName": "Название проекта", + "detected": "Обнаруженный", + "build": "Строить:", + "install": "Устанавливать:", + "output": "Выход:", + "start": "Начать:", + "importing": "Импорт...", + "importProject": "Импорт проекта" + } + }, + "repositoryList": { + "searchPlaceholder": "Ищите в репозиториях...", + "visibility": { + "all": "Все", + "public": "Общественный", + "private": "Частный" + }, + "sort": { + "recent": "Недавний", + "name": "Имя", + "stars": "Звезды" + }, + "addAccount": "Добавить учетную запись на GitHub", + "installTitle": "Установите приложение GitHub", + "installDesc": "Установите приложение GitHub в своей учетной записи или организации, чтобы предоставить доступ к своим репозиториям.", + "installButton": "Установите приложение GitHub", + "noMatching": "Нет подходящих репозиториев", + "noRepos": "Не найдено ни одного репозитория", + "noMatchingDesc": "Попробуйте другой поисковый запрос или измените свои фильтры", + "noReposDesc": "У этой учетной записи пока нет никаких репозиториев", + "privateBadge": "Частный", + "localOnly": "Только местный", + "localOnlyTooltip": "Приложение Openship не установлено на {owner}. Только локальные сборки — установите приложение на этого владельца, чтобы включить удаленное развертывание.", + "repoCountSingular": "Хранилище {count}", + "repoCountPlural": "Хранилища {count}", + "matching": "соответствующий \"{query}\"", + "pagination": { + "previous": "Предыдущий", + "next": "Следующий", + "pageOf": "Страница {page} из {total}" + }, + "time": { + "justNow": "прямо сейчас", + "minutesAgo": "{n}м назад", + "hoursAgo": "{n}h назад", + "daysAgo": "{n} назад", + "monthsAgo": "{n}mo назад" + } + }, + "sidebar": { + "overview": "Обзор", + "total": "Весь", + "public": "Общественный", + "private": "Частный", + "quickTip": "Краткий совет", + "quickTipDesc": "Выберите любой репозиторий, чтобы мгновенно развернуть его. Настройте автоматическое развертывание при каждом нажатии.", + "connection": "Соединение", + "openshipGithubApp": "Приложение Openship на GitHub", + "connected": "Связанный", + "notConnected": "Не подключен", + "ghCli": "gh CLI", + "runGhAuth": "Запустите \"gh auth login\".", + "openshipCloudApp": "Облачное приложение Openship", + "checking": "Проверка…", + "notConnectedManage": "Не подключен — управление в настройках", + "optional": "Необязательный", + "footnote": "Локальная библиотека через gh CLI; при удаленном развертывании используются токены с коротким сроком службы —", + "manageGithubSettings": "управляйте GitHub в настройках", + "methodToken": "Токен GitHub", + "methodDevice": "Вход на GitHub" + }, + "urlImport": { + "invalidUrl": "Введите действительный URL-адрес репозитория GitHub", + "title": "Импорт из Git URL", + "description": "Вставьте URL-адрес публичного репозитория для импорта. Подключение к GitHub не требуется.", + "importButton": "Импорт репозитория" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/migration.json b/apps/dashboard/src/i18n/locales/ru/migration.json new file mode 100644 index 000000000..3abd183b2 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/migration.json @@ -0,0 +1,259 @@ +{ + "wizard": { + "title": "Миграция приложений", + "intro": "Проверьте запущенные приложения на этом сервере и внедрите их в Openship. Приложение доступно только для чтения - на сервере ничего не меняется до тех пор, пока вы не выполните развертывание.", + "selectServer": "Выберите сервер", + "scan": "Сервер сканирования", + "scanning": "Сканирующий…", + "rescan": "Повторное сканирование", + "flatDocker": "Плоский листинг", + "flatDockerHint": "Игнорируйте ярлыки Openship — принимайте все (включая Контейнеры, управляемые Openship) как обычный Docker.", + "flatDockerShort": "Используйте также контейнеры, управляемые Openship.", + "cancel": "Отменить", + "close": "Закрывать", + "projectName": "Название проекта", + "projectNamePlaceholder": "мое приложение", + "create": "Создать проект", + "creating": "Создание…", + "createdToast": "Проект, созданный на основе сервиса(ов) {count}", + "migrate": "Мигрировать", + "migrateN": "Перенос проектов {n}", + "migrating": "Мигрирующий…", + "addProject": "Добавить проект", + "removeProject": "Удалить проект", + "targetLabel": "Целевой сервер", + "sameServer": "Тот же сервер (повторное использование томов на месте)", + "crossServerBuiltInfo": "Локально созданные изображения передаются целевому устройству в виде данных (без регистрации, без перестроения). Для создания больших изображений требуется больше времени — на индикаторе выполнения отображается процесс передачи.", + "killOriginals": "Остановите и удалите старые контейнеры после подтверждения нового развертывания", + "transfer": { + "label": "Перемещение", + "default": "Прямая связь с сервером (самая быстрая)", + "auto": "Авто", + "stream": "Ретрансляция через управляющий узел (резервный вариант)", + "direct": "Прямой", + "rsync": "повторная синхронизация" + }, + "plan": { + "title": "План перевода", + "total": "весь", + "volume": "об", + "bind": "режиссер", + "image": "изображение", + "path": "путь", + "unknown": "размер неизвестен", + "empty": "Передавать нечего.", + "compress": "Сжатие (rsync -z)", + "sslTitle": "SSL-сертификаты", + "sslReuse": "сертификат найден, будет использован повторно", + "sslIssue": "сертификат не выдан при публикации", + "pathsTitle": "Дополнительные пути", + "pathAdd": "Добавь", + "pathRemove": "Удалить путь", + "pathSrcPlaceholder": "/исходный код/путь на старом сервере", + "pathDestPlaceholder": "/dest/путь к новому серверу", + "conflictTitle": "У цели уже есть данные", + "conflictDesc": "Объемы этих сервисов уже существуют на целевом сервере. Выберите, что делать с каждым из них.:", + "conflictOverride": "Переопределение", + "conflictOverrideHint": "Перезаписать с помощью исходного кода", + "conflictClone": "Клон", + "conflictCloneHint": "Новый том, сохраните старый", + "conflictKeep": "Держи", + "conflictKeepHint": "Использовать существующие данные", + "measuring": "Измерение размера передаваемого сигнала…" + }, + "steps": { + "select": "Выбрать", + "source": "Источник", + "domains": "Конфигурировать", + "next": "Следующий", + "back": "Назад", + "sourceHint": "При необходимости свяжите репозиторий и сопоставьте свои контейнеры с его сервисами compose services — запущенный образ все равно будет использоваться повторно.", + "linkRepo": "Привязать репозиторий", + "linkRepoDesc": "Свяжите репозиторий, чтобы Openship знал источник каждой службы (автоматическое развертывание + перестройка позже). В этой миграции по—прежнему используется запущенный образ - перестройка теперь не требуется.", + "repoOptional": "необязательный", + "connectGithub": "Подключите GitHub", + "selectRepo": "Выберите репозиторий", + "repoUrlPlaceholder": "или вставить github.com/owner/repo", + "repoUrlInvalid": "Введите репозиторий на GitHub в качестве владельца/репозитория или github.com URL.", + "repoUrlAdd": "Добавь", + "branch": "Ветка", + "unlinkRepo": "Удалять", + "mapTitle": "Сопоставьте контейнеры для создания сервисов", + "mapHint": "Укажите каждому обнаруженному контейнеру его службу в compose репозитория. Путь сборки соответствующей службы становится ее источником.", + "mapToService": "Выберите услугу", + "notInRepo": "Не в репозитории", + "composeServicesTitle": "Услуги репо", + "noComposeFound": "В этом репозитории не найден docker-compose — ссылки на репозитории находятся на уровне проекта.", + "mapNoRepo": "Свяжите репозиторий на шаге выбора, чтобы сопоставить ваши контейнеры с его сервисами compose services (необязательно).", + "mapSkipHint": "Связывание репозитория необязательно — пропустите, чтобы продолжить (запущенный образ используется повторно как есть).", + "mapField": "Услуга репо", + "repoConnectHint": "Подключите GitHub на панели, чтобы просматривать свои репозитории, или вставьте URL—адрес репозитория.", + "repoPasteHint": "Или вставьте URL-адрес хранилища.", + "repoOnSourceHint": "Свяжите репозиторий Git на следующем шаге (исходный код) — необязательно.", + "parsingCompose": "Синтаксический анализ compose…", + "envTitle": "Переменные среды", + "publishDomains": "Публиковать домены", + "routeTitle": "Маршрут", + "routeKeep": "Держи", + "routeFree": "Поддомен", + "routeCustom": "Обычай", + "routeNone": "Никто", + "sslOn": "Протокол SSL", + "sslOff": "Нет протокола SSL", + "internalOnly": "Только для внутреннего пользования — не выставляется на всеобщее обозрение.", + "serviceNewBadge": "Новое", + "deployActionReuse": "Повторное использование изображения", + "deployActionBuild": "Будет строить", + "deployActionPull": "Будет тянуть" + } + }, + "run": { + "title": "Перенос вашего стека", + "queued": "Поставленный в очередь…", + "adopting": "Создание проекта Openship…", + "moving_data": "Перемещение данных об объеме в целевой объект…", + "deploying": "Развертывание на целевом сервере…", + "verifying": "Проверка нового развертывания…", + "awaiting_cutover": "Новое развертывание запущено в режиме реального времени — проверьте его, а затем завершите", + "cutover": "Извлечение оригинальных контейнеров…", + "succeeded": "Миграция завершена", + "allSucceeded": "Перенесены проекты {n}", + "queueHeader": "Проект {index} из {total} · {name}", + "failed": "Не удалось выполнить миграцию", + "rolled_back": "Откат — ваши исходные контейнеры были перезапущены", + "openProject": "Открытый проект", + "addDomains": "Добавление доменов", + "viewDeployLogs": "Просмотр журналов развертывания", + "deployDetail": "Развертывание журналов", + "routeHint": "Ваши сервисы импортированы, но еще не общедоступны. Добавьте домен для каждого сервиса на вкладке Домены — Openship автоматически выполнит развертывание для установки своего edge (OpenResty) и, если ваш старый прокси-сервер по-прежнему поддерживает 80/443, предложит использовать его.", + "downtimeNote": "Исходные контейнеры останавливаются во время перемещения; ожидайте кратковременного простоя, пока не будет запущено новое развертывание.", + "movingImage": "изображение", + "movingVolume": "объем", + "partial": "Частичный — некоторые пути не сдвинулись с места" + }, + "cutover": { + "title": "Завершить миграцию", + "warning": "Новое развертывание запущено на целевом сервере. Вы можете остановить и удалить исходные контейнеры сейчас или сохранить их в качестве подстраховки и удалить позже — на другом целевом сервере они перезапускаются в режиме реального времени в режиме ожидания; на том же сервере они остаются остановленными (теперь их порты хранятся в новом стеке).", + "stopRemove": "Остановка и удаление оригиналов", + "keep": "Храните оригиналы", + "working": "Работающий…" + }, + "discover": { + "buildBlocked": "Создан из исходного кода — пока не удается перенести (сначала опубликуйте изображение)", + "proxyExcluded": "Обратный прокси—сервер ({ports}) - не импортирован; его заменяет edge от Openship.", + "edgePortReserved": "Порты {ports} зарезервированы для edge от Openship; не опубликованы.", + "nothing": "На этом сервере не было найдено доступных контейнеров Docker.", + "servicesTitle": "Услуги", + "volumesTitle": "Тома", + "networksTitle": "Сети", + "warningsTitle": "Перед миграцией", + "composeProjects": "Создавайте проекты", + "composeGroup": "Составить", + "standaloneGroup": "Автономные контейнеры", + "standalone": "автономный", + "selectAll": "Выбрать все", + "selectedCount": "Выбран {n} из {total}", + "claimedIn": "в {project}", + "otherComposeHint": "Часть {group} — добавьте отдельный проект для ее импорта", + "emptyProject": "Услуги еще не выбраны — выберите слева.", + "running": "бегущий", + "stopped": "остановился", + "image": "Изображение", + "build": "Строить", + "ports": "Порты", + "env": "Env", + "volumes": "Тома", + "dependsOn": "Зависит от", + "inUseBy": "используется", + "reused": "повторно используется на месте", + "volumeReuse": "Перенимать", + "volumeCopy": "Копировать", + "volumeCopyHint": "Take over повторно использует существующий том на месте. При копировании он дублируется в новый том Openship, а исходный том остается нетронутым (используется дополнительный диск).", + "bind": "путь к хосту", + "nVolumes": "Объемы {n}", + "nEnv": "{n} env переменные", + "envFromImage": "Переменные {n} берутся из изображения", + "envFromImageHint": "Не импортированы в качестве конфигурации — образ предоставляет их во время выполнения. Импортируйте их, чтобы закрепить значения перед восстановлением из исходного кода.", + "envFromImageImport": "Импортировать в любом случае", + "alreadyManaged": "Контейнеры {count}, уже управляемые Openship, были пропущены." + }, + "reimport": { + "title": "Найдены проекты Openship", + "intro": "Эти проекты Openship запущены на этом сервере, но не в данном экземпляре (сброшенная база данных или сервер с другого Openship). Повторный импорт для их восстановления - исходный идентификатор сохраняется, поэтому активные контейнеры подключаются повторно.", + "services": "Служба(ы) {n}", + "lastSeen": "Последний развернутый {when}", + "fullRestore": "Полное восстановление", + "bestEffort": "Восстановление с максимальными усилиями", + "action": "Реимпорт", + "working": "Повторный импорт…", + "reimported": "Реимпортированный", + "openProject": "Открытый проект", + "alreadyManaged": "Этот экземпляр уже управляет контейнерами {n}.", + "finalizeNote": "Повторный импорт восстанавливает проект и повторно подключает запущенные контейнеры в реальном времени - повторное развертывание не требуется. Повторное развертывание выполняется только для изменения сборки.", + "failed": "Не удалось выполнить повторный импорт" + }, + "scanFailed": "Проверка Docker завершилась неудачей", + "adoptFailed": "Не удалось создать проект", + "entry": { + "cardTitle": "Существующие сервисы", + "cardDesc": "Перенесите запущенное развертывание Docker или Compose в Openship.", + "action": "Миграция приложений", + "tab": "Существующий сервер", + "comingSoon": "Скоро начнется миграция Docker" + }, + "view": { + "tabView": "Просмотр сервисов", + "tabMigrate": "Мигрировать", + "adoptedGroup": "Управляется {project}", + "openProject": "Открытый проект", + "migrateToManage": "Перейти к управлению", + "back": "Вернуться к услугам" + }, + "tab": { + "new": "Новая миграция", + "empty": "Миграций пока нет", + "emptyDesc": "Переместите запущенный Docker или Compose stack с этого сервера в Openship или перенесите его с другого сервера.", + "close": "Закрывать", + "sessionLog": "Журнал сеанса", + "noLogs": "Выходных данных журнала пока нет.", + "detailTitle": "Миграция", + "inPlace": "На месте", + "crossServer": "Кросс-сервер", + "servicesCount": "Сервисы {n}", + "cancelRun": "Отменить миграцию", + "confirmCancel": "Отменить перенос? Перенос останавливается, и все изменения в целевом объекте отменяются.", + "inFlight": "В процессе", + "status": { + "queued": "Поставленный в очередь", + "adopting": "Принятие", + "moving_data": "Перемещение данных", + "deploying": "Развертывание", + "verifying": "Подтверждающий", + "awaiting_cutover": "Ожидание переключения", + "cutover": "Перерезая", + "succeeded": "Преуспевший", + "failed": "Неудачный", + "rolled_back": "Откатился назад", + "partial": "Частичный" + }, + "delete": "Удалить запись", + "confirmDelete": "Удалите эту запись о переносе? Журнал удален — ваш проект и его данные не затронуты.", + "back": "Вернемся к миграциям", + "pendingTitle": "Пути, которые не двигались", + "pendingMissing": "не найдено в источнике", + "pendingError": "не удалось выполнить передачу", + "editPath": "Редактировать исходный путь", + "overridePlaceholder": "Новый исходный путь (пустой = повторить попытку как есть)", + "skip": "Пропускать", + "undoSkip": "Держи", + "resume": "Возобновить миграцию", + "resuming": "Возобновление…", + "editRetry": "Редактировать и повторять попытку", + "safetyTitle": "Неразрушающий и обратимый.", + "safetyBody": "Данные копируются, но никогда не перемещаются — работа вашего источника приостанавливается лишь на короткое время, и ничего не удаляется, если вы явно не отключите его.", + "cleanupTarget": "Удалить скопированные данные из целевого файла" + }, + "plan": { + "missing": "не найдено" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/misc.json b/apps/dashboard/src/i18n/locales/ru/misc.json new file mode 100644 index 000000000..bfa63a00d --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/misc.json @@ -0,0 +1,370 @@ +{ + "authorize": { + "invalidRequest": "Недопустимый запрос", + "missingParams": "Отсутствуют параметры авторизации.", + "title": "Авторизовать {app}", + "wantsToConnect": "{app} хочет подключиться к вашей учетной записи.", + "wantsToConnectOnMachine": "{app} на {machine} хочет подключиться к вашей учетной записи.", + "signedInAs": "Вошел в систему как", + "willAllow": "Это позволит:", + "permDeploy": "Развертывание приложений и управление ими", + "permAccess": "Получите доступ к своим проектам и настройкам", + "authorize": "Авторизовать", + "cancel": "Отменить" + }, + "mcpAuthorize": { + "title": "Авторизация клиента MCP", + "subtitle": "Клиент MCP хочет подключиться к вашей учетной записи Openship.", + "signedInAs": "Вошел в систему как", + "client": "Клиент", + "organization": "Организация", + "orgScopeNote": "Клиент может действовать только в рамках этой организации.", + "switchOrgError": "Не смог сменить организацию. Пожалуйста, попробуйте снова.", + "thisOrganization": "эта организация", + "missingClientId": "Отсутствует идентификатор клиента — эта ссылка для авторизации недействительна.", + "signInRequiredTitle": "Войдите в систему, чтобы продолжить", + "signInRequiredBody": "Мы не смогли подтвердить вашу сессию на этой странице, поэтому клиент не был авторизован. Войдите в систему еще раз, и запрос возобновится.", + "signInAction": "Регистрироваться", + "templatesHeading": "Выберите, что может сделать этот клиент", + "templatesNote": "Вы можете предоставить доступ только к тому, что у вас уже есть.", + "recommendedBadge": "Рекомендуемый", + "broadBadge": "Широкий", + "editedBadge": "Отредактированный", + "resetTemplate": "Сброс", + "tplAgentTitle": "Кодирующий агент", + "tplAgentDesc": "Создает и развертывает новые проекты. Не удается увидеть ничего из того, что уже существует.", + "tplExistingTitle": "Существующие проекты", + "tplExistingDesc": "Развертывайте, перезапускайте и считывайте журналы для выбранных вами проектов. Ничего больше.", + "tplReadOnlyTitle": "Доступен только для чтения", + "tplReadOnlyDesc": "Считывает все, что можно, в {org}. Любая запись блокируется.", + "tplFullTitle": "Полный доступ к учетной записи", + "tplFullDesc": "Действуйте как вы в {org} — в каждом проекте, сервере и инструменте. Только полное доверие.", + "tplCustomTitle": "Обычай", + "tplCustomDesc": "Ваша собственная комбинация ресурсов.", + "editorHeading": "Точная настройка доступа", + "editorNote": "Изменения немедленно отображаются в сводке.", + "capabilitiesHeading": "Возможности", + "createProjectsTitle": "Создавайте новые проекты", + "createProjectsDesc": "Клиент может создавать проекты и полностью управлять ими, включая их удаление. Он не может видеть проекты, которые не создавал.", + "resourcesHeading": "Ресурсы", + "advancedNote": "Они не разблокируют инструменты MCP, но к ним все еще можно получить доступ с помощью той же авторизации через REST API.", + "summaryHeading": "Что получит этот клиент", + "summaryEmptyTitle": "Пока ничего не предоставлено", + "summaryEmptyBody": "Выберите ресурсы слева или выберите шаблон выше.", + "summaryUnscopedTitle": "Все, к чему вы можете получить доступ в {org}", + "summaryUnscopedBody": "Клиент действует в соответствии с вашей собственной ролью. Она никогда не может быть более узкой, чем ваша.", + "summaryReadOnlyTitle": "Доступен только для чтения в {org}", + "summaryReadOnlyBody": "Клиент может прочитать все, что можете прочитать вы, и ничего не записать.", + "capabilityRowTitle": "Создавайте новые проекты", + "capabilityRowDesc": "и полностью управлять теми, кого он создает", + "levelView": "Смотреть", + "levelManage": "Развертывание и управление", + "levelFull": "Полный контроль", + "removeGrant": "Удалять", + "wildcardTag": "Все", + "grantCountOne": "Ресурс {count}", + "grantCountOther": "Ресурсы {count}", + "canHeading": "Будет в состоянии", + "cannotHeading": "Не сможет", + "dgCreateProjects": "Создавайте новые проекты в {org}", + "dgManageOwnProjects": "Полностью управляйте создаваемыми им проектами, включая их удаление", + "dgOperatePickedProjects": "Развертывайте, перезапускайте и изменяйте проекты, перечисленные выше", + "dgViewPickedProjects": "Ознакомьтесь с перечисленными выше проектами — конфигурацией, журналами и статусом", + "dgReadGithub": "Просмотрите свои репозитории на GitHub и узнайте, как их создавать", + "dgWriteGithub": "Просматривайте и изменяйте свои репозитории на GitHub", + "dgServers": "Подключитесь к серверам, перечисленным выше, через API", + "dgBackups": "Доберитесь до пунктов назначения резервных копий, перечисленных выше", + "dgEverything": "Делайте все, что вы можете сделать в {org}", + "dgReadEverything": "Прочитайте все, что вы можете прочитать в {org}", + "dgNotExistingProjects": "Просмотрите или измените любой проект, который он не создавал", + "dgNotEnumerateProjects": "Перечислите свои проекты — это может касаться только тех, которые указаны выше", + "dgNotServers": "Коснитесь настроек своих серверов, почты или организации", + "dgNotDelete": "Удалить что-либо", + "dgNoWrites": "Развертывайте, изменяйте или удаляйте что-либо", + "readOnly": "Доступен только для чтения", + "readOnlyDesc": "Блокируйте каждую запись, независимо от того, что указано выше.", + "readOnlySecretsNote": "Доступный только для чтения, он по-прежнему раскрывает секреты, доступные клиенту, включая значения переменных среды и строки подключения.", + "readOnlyConflictCreate": "Доступ только для чтения блокирует создание проектов, поэтому “Создать новые проекты” ничего не даст.", + "readOnlyConflictWritesOne": "Запись блокируется только для чтения, поэтому доступ на запись к ресурсу {count} ничего не даст.", + "readOnlyConflictWritesOther": "Запись блокируется только для чтения, поэтому доступ на запись к ресурсам {count} ничего не даст.", + "turnOffReadOnly": "Отключите доступ только для чтения", + "blockedNoResources": "Это вообще ничего не даст. Выберите хотя бы один ресурс или выберите шаблон.", + "blockedNoPermissions": "Доступ к каждому ресурсу был закрыт. Установите уровень или удалите строку.", + "authorizeError": "Не удалось завершить авторизацию. Пожалуйста, попробуйте снова.", + "grantRejectedTitle": "Ваша учетная запись не может этого предоставить", + "grantRejected": "{resource} был удален, поскольку ваш собственный доступ на него не распространяется. Просмотрите краткое описание и авторизуйтесь еще раз.", + "deny": "Отрицать", + "authorize": "Авторизовать", + "dgReadSource": "Считайте содержимое файла по указанным вами путям", + "dgNotReadSource": "Прочитайте содержимое любого файла из ваших репозиториев", + "levelViewHint": "Доступно только для чтения: настройки, журналы и метаданные. Без изменений.", + "levelManageHint": "Разверните, перезапустите и измените настройки. Не удается удалить.", + "levelFullHint": "Все, включая удаление самого ресурса." + }, + "acceptInvite": { + "invalidInvitation": "Недействительное приглашение", + "invitationStatus": "Это приглашение называется {status}.", + "wrongAccount": "Это приглашение предназначено для {email}. Вы зарегистрированы как {currentEmail}.", + "loadFailed": "Не удалось загрузить приглашение", + "acceptFailed": "Не удалось принять приглашение", + "theOrganization": "организация", + "invitedTitle": "Вы приглашены", + "needsLoginPre": "Присоединяйтесь ", + "needsLoginMid": " на Openship. Войдите в систему или создайте учетную запись с помощью ", + "needsLoginPost": " принять.", + "signIn": "Регистрироваться", + "createAccount": "Создать аккаунт", + "joinTitle": "Присоединяйтесь к {org}", + "readyPre": "Вас пригласили присоединиться ", + "readyMid": " как ", + "readyPost": ".", + "decline": "Снижение", + "accept": "Принимать", + "joining": "Вступление в организацию...", + "acceptedTitle": "Ты в деле", + "acceptedRedirect": "Перенаправление на панель управления...", + "errorTitle": "Не могу принять это приглашение", + "backToDashboard": "Вернуться к панели управления" + }, + "cloudAuthorize": { + "missingRedirect": "Отсутствует параметр перенаправления.", + "missingState": "Отсутствует параметр состояния.", + "missingCodeChallenge": "Отсутствует параметр code_challenge.", + "invalidState": "Недопустимый параметр состояния.", + "invalidCodeChallenge": "Недопустимый параметр code_challenge.", + "invalidRedirectUrl": "Неверный URL-адрес для перенаправления.", + "redirectProtocol": "Для перенаправления должен использоваться http или https.", + "redirectHttps": "При перенаправлении с нелокального хостинга должен использоваться протокол HTTPS.", + "redirectUserinfo": "URL-адрес перенаправления не должен содержать userinfo.", + "authorizeError": "Не удалось авторизовать это подключение.", + "invalidTitle": "Неверный запрос на авторизацию", + "title": "Авторизовать устройство", + "instancePre": "Экземпляр Openship в ", + "instancePost": " хочет подключиться к вашей облачной учетной записи Openship.", + "signedInAs": "Вошел в систему как", + "authorizing": "Разрешающий…", + "authorize": "Авторизовать", + "cancel": "Отменить", + "deviceDoneTitle": "Подключен к облаку Openship", + "deviceDoneBody": "Вы можете закрыть эту вкладку и вернуться к своему терминалу — настройка продолжится автоматически." + }, + "cloudConnect": { + "noCode": "Аутентификационный код предоставлен не был. Пожалуйста, попробуйте снова.", + "stateExpired": "Срок действия соединения истек. Пожалуйста, попробуйте снова.", + "verifyError": "Не удалось выполнить проверку с помощью Openship Cloud.", + "finalizingTitle": "Завершение подключения…", + "finalizingSubtitle": "Всего на минутку.", + "successTitle": "Подключен к облаку Openship", + "successDescription": "Теперь ваш экземпляр связан. Вы можете закрыть это окно.", + "failedTitle": "Не удалось установить соединение" + }, + "iconPicker": { + "chooseIcon": "Выберите значок", + "searchPlaceholder": "Поиск значков...", + "count": "{offset} из {total}", + "startSearching": "Начните поиск", + "startSearchingHint": "Введите ключевое слово, чтобы найти значки", + "searching": "Поиск значков...", + "noIconsFound": "Значки не найдены", + "noIconsHint": "Попробуйте ввести другой поисковый запрос", + "loadingMore": "Загружаю еще...", + "noMoreResults": "Больше никаких результатов", + "cancel": "Отменить", + "selectIcon": "Выберите значок", + "chooseAnIcon": "Выберите значок" + }, + "restoreWizard": { + "startFailed": "Не удалось запустить восстановление", + "typeToConfirm": "Введите точное название службы для подтверждения", + "applyFailed": "Не удалось применить восстановление", + "title": "Восстановить резервную копию", + "serviceLabel": "Сервис: {name}", + "serviceRestore": "Восстановление службы", + "stepReview": "Обзор", + "stepPrepare": "Подготовить", + "stepConfirm": "Подтверждать", + "stepApply": "Применять", + "stepDone": "Сделано", + "reviewPre": "Вы собираетесь выполнить восстановление из резервной копии, созданной на ", + "reviewPost": ".", + "sizeArtifacts": "Размер: {size} · Артефакты: {count}", + "overwriteWarning": "Это приведет к перезаписи текущих данных.", + "overwriteHint": "На следующем шаге (Подготовка) будет проверена возможность загрузки резервной копии. Ничего разрушительного не произойдет, пока вы не подтвердите это на шаге \"Применить\".", + "protectLabel": "Защитите последнюю резервную копию от удаления при хранении", + "protectHint": "Сохраняет последнюю успешную резервную копию от автоматического удаления, так что вы можете вернуться к режиму \"непосредственно перед восстановлением\", если что-то пойдет не так.", + "cancel": "Отменить", + "starting": "Начало…", + "continuePrepare": "Продолжить → Подготовить", + "verifying": "Проверка резервной копии…", + "verifyingHint": "Проверка наличия артефакта и целостности в пункте назначения. Служба по-прежнему работает в обычном режиме.", + "cancelRestore": "Отменить восстановление", + "verified": "Резервная копия проверена и готова к применению.", + "preparedInfo": "{size} подготовлен. Во время выполнения восстановления служба ненадолго остановится.", + "confirmPre": "Текущие данные об объеме будут ", + "confirmStrong": "постоянно заменяемый", + "confirmMid": ". Введите ", + "confirmPost": " подтверждать.", + "applying": "Обратившийся…", + "applyRestore": "Применить восстановление", + "restoringData": "Восстановление данных…", + "restoringHint": "Остановка службы → обмен данными → перезапуск. Не закрывайте это окно.", + "cancelFailed": "Не удалось отменить восстановление", + "cancelPending": "Требуется отмена. Восстановление завершается в следующей безопасной точке — в этом окне будет показан результат.", + "destructiveNotYet": "Пока ничего не написано, так что отменять заказ сейчас безопасно.", + "destructiveNow": "Выполняется запись данных. При отмене теперь сохраняются частичные данные.", + "abortRestore": "Прервать восстановление", + "abortTitle": "Прервать это восстановление?", + "abortBodyClean": "При восстановлении пока ничего не записано. При отмене ваши данные остаются в прежнем виде; служба перезапускается, если мы ее остановили.", + "abortBodyDestructive": "Восстановление уже началось. При прерывании в целевом объекте сохраняются неполные данные, а служба намеренно остается остановленной — повторно запустите это восстановление (или более новое) до завершения, прежде чем запускать его.", + "abortKeepGoing": "Продолжайте восстанавливать", + "abortConfirm": "Да, прервать", + "partialDataNotice": "Объект восстановления содержит неполные данные, и служба была намеренно остановлена. Перед запуском повторно запустите это восстановление (или более новое) до завершения.", + "restoreComplete": "Восстановление завершено.", + "restoreStatus": "Восстановить {status}", + "failed": "провалившийся", + "close": "Закрывать" + }, + "terminalTabs": { + "shell": "Оболочка {n}", + "close": "Закрыть {label}", + "serverLimit": "Ограничение сервера: {max} одновременных оболочек.", + "newShell": "Новая оболочка", + "noTerminals": "Никаких открытых терминалов.", + "expand": "Расширять", + "collapse": "Коллапс" + }, + "buildPage": { + "thisRepo": "это репозиторий", + "notFoundTitle": "Развертывание не найдено", + "notFoundDescription": "Это развертывание не существует или у вас нет к нему доступа. Возможно, оно было удалено или ссылка неверна.", + "viewDeployments": "Просмотр развертываний", + "goHome": "пойти домой" + }, + "backups": { + "usedBy": "Используется", + "usedByDesc": "Проекты и услуги, которые создают резервные копии для этого пункта назначения", + "noUsageTitle": "Здесь пока ничего не подтверждено", + "noUsageDesc": "Когда проект или служба создают резервную копию в этом месте назначения, она отображается здесь.", + "scheduleManual": "Инструкция", + "projectDefault": "Проект по умолчанию", + "mailServer": "Почтовый сервер", + "openInProject": "Открыто в проекте", + "notFound": "Пункт назначения не найден", + "summaryTitle": "Место хранения", + "summaryStored": "Общее количество хранимых", + "summaryBackups": "Резервные копии", + "summaryDestinations": "Назначения", + "statsStored": "хранящийся", + "statsBackups": "резервные копии", + "statsNoRuns": "Резервных копий пока нет", + "statsLast": "последний", + "title": "Резервные копии", + "subtitle": "Целевые объекты внешнего хранилища для резервного копирования проектов и сервисов", + "addDestination": "Добавить пункт назначения", + "kindS3": "Совместимость с S3", + "kindSftp": "SFTP-протокол", + "kindServer": "Существующий сервер", + "kindLocal": "Локальный диск", + "kindHttp": "Загрузка по протоколу HTTP", + "verifiedSuccess": "\"{name}\" успешно проверен.", + "verificationFailedMsg": "Проверка не удалась.", + "verificationFailedTitle": "Не удалось выполнить проверку", + "setDefaultSuccess": "\"{name}\" теперь является пунктом назначения по умолчанию.", + "setDefaultFailed": "Не удалось установить значение по умолчанию", + "deletedSuccess": "\"{name}\" удален.", + "deleteFailed": "Удалить не удалось", + "updated": "Пункт назначения обновлен.", + "created": "Пункт назначения создан.", + "verifyConnection": "Проверьте подключение", + "verifyingBadge": "Подтверждающий…", + "verifiedBadge": "Проверенный", + "failedBadge": "Неудачный", + "notVerifiedBadge": "Не проверено", + "defaultBadge": "По умолчанию", + "defaultTitle": "Пункт назначения по умолчанию", + "lastVerified": "Последний подтвержденный {date}", + "editAction": "Редактировать", + "setDefaultAction": "Установлен по умолчанию", + "deleteAction": "Удалить", + "emptyTitle": "Резервных пунктов назначения пока нет", + "emptyDescription": "Подключите пакет, совместимый с S3, к узлу SFTP, существующему серверу openship или локальному диску - тогда службы смогут создавать на нем резервные копии.", + "addFirst": "Добавьте свой первый пункт назначения", + "supportedTitle": "Поддерживаемые пункты назначения", + "cardS3Sub": "AWS · R2 · B2 · МинИО", + "cardSftpSub": "Любой SSH-хост", + "cardServerSub": "Повторное использование SSH-кодов", + "cardLocalSub": "Только для самостоятельного размещения", + "deleteTitle": "Удалить пункт назначения", + "deletePre": "Удалить ", + "deletePost": "? Это невозможно отменить. Адресат, который все еще используется политикой резервного копирования, не может быть удален.", + "cancel": "Отменить", + "credAccessKeyStored": "Сохраненный ключ доступа", + "credPrivateKeyStored": "Сохраненный закрытый ключ", + "credPasswordStored": "Сохраненный пароль", + "credNone": "Никаких верительных грамот", + "credReusesServer": "Повторно использует учетные данные сервера", + "credNoneNeeded": "Никаких учетных данных не требуется", + "serverPrefix": "сервер ", + "s3Desc": "Любое хранилище с использованием S3-API — AWS S3, Cloudflare R2, Backblaze B2, Wasabi, MinIO.", + "s3Examples": "Самый популярный · работает в любом месте", + "sftpDesc": "Отправляйте резервные копии по SSH на произвольный хост с новыми учетными данными.", + "sftpExamples": "Выделенный блок резервного копирования · NAS", + "serverDesc": "Повторно используйте учетные данные SSH с сервера, который вы уже добавили в Openship.", + "serverExamples": "Повторное использование учетных данных /серверов", + "localDesc": "Запись в каталог на хосте API. Отключен в облачном режиме.", + "localExamples": "Только для самостоятельного размещения", + "modalEditTitle": "Редактировать {name}", + "modalAddTitle": "Добавить пункт назначения резервной копии", + "modalNewTitle": "Новый {name}", + "destinationFallback": "место назначения", + "modalPickSubtitle": "Выберите, где будут храниться ваши резервные копии.", + "modalConfigureSubtitle": "Учетные данные шифруются в состоянии покоя и никогда не отображаются обратно.", + "encryptedAtRest": "Зашифрованный в состоянии покоя", + "backToPicker": "Вернемся к доброму сборщику", + "secretStoredPlaceholder": "•••••• сохранено — оставьте поле для сохранения", + "updateFailed": "Не удалось обновить пункт назначения", + "createFailed": "Не удалось создать пункт назначения", + "fieldName": "Имя", + "providerLabel": "Поставщик", + "providerAws": "AWS S3", + "providerR2": "Облачная вспышка R2", + "providerB2": "Обратная вспышка B2", + "providerWasabi": "Васаби", + "providerDo": "Цифровые океанские пространства", + "providerMinio": "Мини / Изготовленный на заказ", + "fieldAccountId": "Идентификатор учетной записи", + "hintAccountId": "Ваш идентификатор учетной записи Cloudflare — используется для создания конечной точки R2.", + "hintEndpointMinio": "Полный URL-адрес конечной точки S3, например https://minio.example.com:9000", + "testConnection": "Тестовое подключение", + "testing": "Тестовое соединение…", + "testOk": "Подключено — корзина доступна и доступна для записи.", + "fieldEndpoint": "Конечная точка", + "hintEndpoint": "Пусто = AWS S3. R2: https://<учетная запись>.r2.cloudflarestorage.com", + "fieldRegion": "Регион", + "fieldBucket": "Ведро", + "fieldPathPrefix": "Префикс пути", + "hintPathPrefix": "Дополнительный подпутевой путь внутри корзины", + "fieldAccessKeyId": "Идентификатор ключа доступа", + "fieldSecretAccessKey": "Секретный ключ доступа", + "fieldHost": "Хозяин", + "fieldPort": "Порт", + "fieldUser": "Пользователь", + "fieldPassword": "Пароль", + "hintPassword": "Оставьте поле пустым, если вы используете закрытый ключ", + "fieldPrivateKey": "Закрытый ключ (PEM)", + "hintPrivateKey": "Используется, когда пароль не указан", + "fieldServer": "Сервер", + "hintServer": "Повторно использует учетные данные SSH, уже сохраненные в /servers", + "selectServer": "— выберите сервер —", + "noServersPre": "Серверы еще не настроены. Добавьте один из них в разделе ", + "noServersLink": "Серверы", + "noServersPost": " первый.", + "fieldRemotePath": "Удаленный путь", + "hintRemotePath": "Абсолютный каталог на сервере (например, /backups/openship)", + "fieldAbsolutePath": "Абсолютный путь", + "hintAbsolutePath": "Путь к файловой системе на хосте API. Отключен в облачном режиме.", + "saving": "Экономия…", + "saveChanges": "Сохранить изменения", + "saveDestination": "Сохранить пункт назначения" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/onboarding.json b/apps/dashboard/src/i18n/locales/ru/onboarding.json new file mode 100644 index 000000000..62e84ec2d --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/onboarding.json @@ -0,0 +1,149 @@ +{ + "common": { + "goBack": "Возвращаться", + "continue": "Продолжать", + "back": "Назад", + "optional": "(опционально)" + }, + "topBar": { + "website": "Вебсайт", + "github": "ГитХаб", + "theme": "Переключение темы", + "language": "Язык" + }, + "choose": { + "title": "Добро пожаловать в Openship", + "subtitle": "Выберите, как вы хотите запускать Openship. Оба варианта предоставляют вам все возможности, и вы можете переключаться в любое время.", + "cloud": { + "name": "Облако Openship", + "desc": "Мы занимаемся инфраструктурой, обновлениями и резервным копированием. Просто войдите в систему и начните развертывание.", + "perk1": "Сервер не нужен", + "perk2": "Бесплатный уровень включен в стоимость", + "perk3": "Управляемый и всегда актуальный", + "cta": "Продолжайте работу с облаком" + }, + "or": "или", + "selfhost": { + "name": "Самодостаточный", + "desc": "Запустите Openship на своем собственном оборудовании. Подключите удаленный сервер или используйте этот компьютер.", + "perk1": "Полное владение данными", + "perk2": "Удаленный сервер или этот Mac", + "perk3": "Мы позаботимся обо всем остальном", + "cta": "Настроил Свой Сервер" + }, + "migrateNote": "Переключайтесь между облачным сервисом и автономным хостингом в любое время одним щелчком мыши - никакой привязки никогда не будет.", + "skip": "Пропусти пока" + }, + "selfhost": { + "title": "Где должен запускаться Openship?", + "subtitleLine1": "Выберите, где установить платформу Openship.", + "subtitleLine2": "Оба варианта дают вам полный контроль и владение данными.", + "local": { + "title": "Эта машина", + "badge": "Бета", + "desc": "Установите Openship прямо здесь - никакого SSH, никакой удаленной настройки не требуется", + "comingSoon": "Скоро будет", + "comingSoonDesc": "Запуск Openship непосредственно на этом компьютере еще не готов — пока подключите сервер." + }, + "remote": { + "title": "Другой сервер", + "desc": "Подключитесь к удаленному серверу, VPS или любому компьютеру в вашей сети по SSH" + } + }, + "ssh": { + "title": "Подключитесь к своему серверу", + "subtitleLine1": "Введите данные вашего сервера и выберите способ авторизации.", + "subtitleLine2": "Мы установим и настроим все автоматически.", + "serverNameLabel": "Имя сервера", + "serverNamePlaceholder": "Производство, постановка, разработка...", + "serverIpLabel": "IP-адрес сервера", + "usernameLabel": "Имя пользователя", + "methodPassword": "Пароль", + "methodKey": "SSH-ключ", + "methodAgent": "Агент", + "agentHint": "Подключается с помощью SSH—агента, подобного VSCode, пароль или ключ не требуются. Хост, на котором запущен Openship, должен уже иметь доступ к этому серверу (ключ загружен в его ssh-агент).", + "passwordLabel": "Пароль", + "passwordPlaceholder": "Пароль сервера", + "keyPathLabel": "Ключевой путь", + "browse": "Просматривать", + "passphraseLabel": "Ключевая фраза", + "passphrasePlaceholder": "Оставьте поле пустым, если его нет", + "advanced": "Передовой", + "sshPortLabel": "SSH-порт", + "jumpHostLabel": "Ведущий прыжка", + "extraArgsLabel": "Дополнительные аргументы SSH", + "submit": "Сохранить и продолжить", + "tutorial": "Пошаговое руководство по настройке", + "testConnection": "Тестовое подключение", + "testing": "Тестирование…", + "connected": "Связанный", + "testFailed": "Не удалось установить соединение", + "testHint": "Прежде чем продолжить, убедитесь, что сервер доступен." + }, + "tunnel": { + "title": "Доступ в Интернет", + "subtitle": "Ваш сервер должен быть доступен из Интернета для веб-подключений, SSL и общедоступного доступа.", + "providers": { + "edge": { + "title": "Край Openship", + "desc": "Нулевая настройка. Автоматический протокол SSL, высокая доступность и защита от DDoS-атак - все это встроено.", + "badge": "Рекомендуемый" + }, + "cloudflare": { + "title": "Туннель Cloudflare", + "desc": "Используйте свою собственную учетную запись Cloudflare. Доступен бесплатный уровень." + }, + "ngrok": { + "title": "нгрок", + "desc": "Предоставляйте доступ к сервисам с помощью вашего токена аутентификации ngrok." + } + }, + "cloudflareTokenLabel": "Туннельный токен Cloudflare", + "ngrokTokenLabel": "токен аутентификации ngrok", + "cloudflarePlaceholder": "Вставьте свой туннельный жетон", + "ngrokPlaceholder": "Вставьте свой токен авторизации ngrok", + "edgeHint": "Для работы с Openship Edge требуется учетная запись Openship. Для продолжения вам необходимо войти в систему.", + "signInContinue": "Войдите в систему и продолжайте" + }, + "preferences": { + "title": "Настройки построения", + "subtitleLine1": "Выберите способ построения ваших проектов при развертывании.", + "subtitleLine2": "Вы можете изменить это позже в разделе \"Настройки\".", + "options": { + "auto": { + "title": "Авто", + "desc": "Мы подбираем оптимальный вариант для каждого фреймворка" + }, + "server": { + "title": "Дистанционный", + "desc": "Сборка непосредственно на сервере развертывания" + }, + "local": { + "title": "Местный", + "desc": "Создайте на этом компьютере Mac, затем отправьте на сервер" + } + }, + "hint": "Push-развертывания Git всегда создаются на сервере - это относится только к ручным развертываниям." + }, + "loading": { + "connecting": "Связывающий…", + "verifying": "Проверка вашего сервера", + "retry": "Повторить попытку", + "openingCloud": "Открытие облака Openship…", + "waitingAuth": "Ожидание завершения проверки подлинности", + "couldNotStartAuthTitle": "Не удалось запустить облачную аутентификацию", + "authFailedTitle": "Не удалось выполнить проверку подлинности в облаке", + "couldNotStartAuthMsg": "Не удалось запустить процесс авторизации на рабочем столе.", + "authFailedMsg": "Пожалуйста, повторите попытку и завершите вход в систему в вашем браузере.", + "completingSignIn": "Завершение входа в систему…", + "returningToOpenship": "Возвращаясь к Openship", + "redirectingCloud": "Перенаправление на Openship Cloud…", + "newTabSignIn": "Вы завершите вход в систему на новой вкладке", + "couldNotSaveTitle": "Не удалось сохранить конфигурацию", + "couldNotSaveMsg": "API не ответил. Убедитесь, что службы запущены.", + "savingConfig": "Сохранение конфигурации…", + "almostThere": "Почти на месте", + "settingUpAccount": "Настройка вашей учетной записи…", + "creatingSession": "Создание вашего сеанса" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/overview.json b/apps/dashboard/src/i18n/locales/ru/overview.json new file mode 100644 index 000000000..6d48f30eb --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/overview.json @@ -0,0 +1,144 @@ +{ + "activity": { + "title": "Деятельность", + "thisWeek": "на этой неделе", + "deploymentSingular": "{count} развертывание", + "deploymentPlural": "Развертывания {count}" + }, + "apiRequests": { + "title": "Запросы к API", + "last7Days": "Последние 7 дней", + "totalRequests": "Общее количество запросов", + "requestsTooltip": "Запросы {count}" + }, + "credits": { + "title": "Баланс кредитов", + "availableToUse": "Доступный для использования", + "spentThisMonth": "Провел этот месяц", + "add": "Добавь" + }, + "deployments": { + "title": "Развертывания", + "lastNDays": "последние {period} дней", + "deploymentSingular": "{count} развертывание", + "deploymentPlural": "Развертывания {count}" + }, + "homeTip": { + "quickTip": "Краткий совет", + "connectText": "Подключите свой репозиторий на GitHub для автоматического развертывания при каждом нажатии.", + "connectLabel": "Подключите GitHub", + "createText": "Создайте свой первый проект для начала развертывания.", + "createLabel": "Новый проект", + "settingsText": "Настройте переменные среды и пользовательские домены в настройках проекта.", + "settingsLabel": "Настройки проекта", + "connected": "Связанный", + "tips": { + "envVars": { + "text": "Добавляйте зашифрованные переменные среды и секретные данные в любой проект.", + "label": "Открытые проекты" + }, + "customDomain": { + "text": "Укажите пользовательский домен для проекта — HTTPS будет предоставлен автоматически.", + "label": "Открытые проекты" + }, + "autoDeploy": { + "text": "Подключите GitHub для автоматического развертывания при каждом нажатии, без необходимости подключения CI.", + "label": "Откройте настройки Git" + }, + "rollback": { + "text": "Выполните откат к любому предыдущему развертыванию одним щелчком мыши.", + "label": "Просмотр развертываний" + }, + "apps": { + "text": "Устанавливайте автономные приложения, такие как Gitea, n8n и Metabase, в один клик.", + "label": "Просматривайте приложения" + }, + "servers": { + "text": "Подключайте свои собственные серверы по SSH и выполняйте развертывание на них прямо отсюда.", + "label": "Управление серверами" + }, + "jobs": { + "text": "Планируйте команды с помощью заданий cron, включая повторные попытки, оперативные журналы и историю.", + "label": "Открытые вакансии" + }, + "backups": { + "text": "Настройте автоматическое резервное копирование ваших баз данных и томов.", + "label": "Настройка резервных копий" + }, + "mail": { + "text": "Запустите свой собственный почтовый сервер и веб-почту, полностью автономные.", + "label": "Настройка почты" + }, + "team": { + "text": "Пригласите товарищей по команде и распределите их доступ по каждому проекту.", + "label": "Управлять командой" + } + } + }, + "welcome": { + "title": "Запустите свой первый проект", + "subtitle": "Подключите репозиторий или начните с шаблона — Openship создает его, отправляет и выдает вам URL-адрес в реальном времени за считанные минуты.", + "createProject": "Создать проект", + "importGithub": "Импорт с GitHub", + "tipPrefix": "Совет: нажмите", + "tipSuffix": "прыгать куда угодно" + }, + "header": { + "goodMorning": "Доброе утро", + "goodAfternoon": "Добрый день", + "goodEvening": "Добрый вечер", + "greetingWithName": "{greeting}, {name}", + "overview": "Обзор", + "subtitle": "Контролируйте использование вашей платформы и управляйте ресурсами", + "creditsBalance": "Баланс кредитов", + "topUp": "пополнять" + }, + "hero": { + "title": "Активность на платформе", + "subtitle": "Использование токенов и запросы API", + "tokens": "Жетоны", + "requests": "Запросы", + "lastNDays": "Последние {period} дней", + "agents": "Агенты", + "environments": "Окружающая среда", + "total": "Весь", + "production": "Производство", + "testing": "Тестирование", + "prodCount": "{count} прод", + "testCount": "Тест {count}" + }, + "projects": { + "title": "Проекты", + "activeDeployments": "Активные развертывания", + "total": "Весь", + "live": "Жить", + "building": "Здание", + "needAttentionSingular": "Проект {count} нуждается во внимании", + "needAttentionPlural": "Проекты {count} требуют внимания" + }, + "sandboxes": { + "title": "Песочницы", + "developmentEnvironments": "Среды разработки", + "totalSandboxes": "Всего песочниц", + "active": "Активный", + "runningCount": "{count} запущен", + "stoppedCount": "{count} остановлен" + }, + "stats": { + "creditsBalance": "Баланс кредитов", + "tokenUsage": "Использование токена", + "thisMonth": "В этом месяце", + "apiRequests": "Запросы к API", + "last7Days": "Последние 7 дней", + "deployments": "Развертывания", + "successfulCount": "{count} прошел успешно", + "activeProjects": "Активные проекты", + "sandboxes": "Песочницы", + "activeCount": "{count} активен" + }, + "tokenUsage": { + "title": "Использование токена", + "lastNDays": "последние {period} дней", + "tokensTooltip": "Токены {count}" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/projectDetail.json b/apps/dashboard/src/i18n/locales/ru/projectDetail.json new file mode 100644 index 000000000..3b361b4fe --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/projectDetail.json @@ -0,0 +1,276 @@ +{ + "general": { + "productionUrl": { + "title": "URL-адрес производства", + "notConfigured": "Не настроен" + }, + "identity": { + "title": "Идентичность проекта", + "nameLabel": "Название проекта", + "namePlaceholder": "мой-потрясающий-проект", + "unnamed": "Неназванный проект", + "descriptionLabel": "Описание", + "descriptionPlaceholder": "Современное веб-приложение, созданное с помощью...", + "noDescription": "Описание не приводится", + "save": "Сохранить", + "cancel": "Отменить", + "updateNameFailed": "Не удалось обновить название проекта", + "updateDescriptionFailed": "Не удалось обновить описание проекта" + }, + "info": { + "title": "Информация о проекте", + "projectId": "Идентификатор проекта", + "branch": "Ветка", + "lastDeploy": "Последнее развертывание", + "framework": "Рамки", + "unknown": "Неизвестный", + "aiTitle": "Помощник с искусственным интеллектом", + "aiPoweredBy": "Работает на размытых изображениях", + "aiEdit": "Редактирование с размытием", + "aiComingSoonTitle": "скоро будет", + "aiComingSoonBody": "Редактирование с размытием пока недоступно" + }, + "topPaths": { + "title": "Верхние пути", + "showLess": "Показывать меньше", + "requestsShort": "запросы" + }, + "traffic": { + "title": "Обзор трафика", + "last24Hours": "Последние 24 часа", + "bar": "Бар", + "area": "Область", + "loading": "Загружаем аналитику...", + "noDataTitle": "Данных о дорожном движении пока нет", + "noDataBody": "Эта диаграмма будет заполнена после того, как приложение получит запросы." + } + }, + "logs": { + "actions": { + "copied": "Скопированный", + "copy": "Копировать", + "download": "Скачать", + "clear": "Четкий" + }, + "server": { + "title": "Журналы HTTP-запросов", + "live": "Жить", + "errorHint": "Убедитесь, что на сервере развернуты аналитические скрипты", + "waiting": "Ожидание входящих запросов…", + "streamError": "Ошибка потока", + "connectionLost": "Потеряно подключение к потоку журналов", + "connectFailed": "Не удалось подключиться к потоку журналов", + "noDomain": "Добавьте домен, чтобы просматривать журналы запросов", + "noDomainHint": "Журналы HTTP—запросов собираются для каждого домена - сначала добавьте домен в этот проект." + }, + "terminal": { + "fallbackName": "Терминал", + "searchPlaceholder": "Поиск в журналах...", + "previousMatch": "Предыдущее совпадение (Shift+Enter)", + "nextMatch": "Следующий матч (Ввод)", + "lines": "Строки {count}", + "stop": "Остановка", + "start": "Начать", + "waitingForLogs": "Ожидание получения журналов…", + "pressStart": "Нажмите кнопку Пуск, чтобы начать потоковую передачу журналов", + "copiedToClipboard": "Скопировано в буфер обмена", + "logsErrorTitle": "Ошибка в журналах", + "containerStoppedTitle": "Контейнер остановился", + "containerExited": "Выход из контейнера с кодом {code}", + "connectFailedTitle": "Не удалось подключиться к журналам терминала", + "connectFailed": "Не удалось подключиться к журналам терминала, убедитесь, что ваш проект запущен" + } + }, + "services": { + "addModal": { + "addTitle": "Добавьте приложение или сервис", + "configureTitle": "Настроить {name}", + "fallbackService": "апп", + "pickSubtitle": "Выбирайте из каталога или используйте пользовательское изображение.", + "configureSubtitle": "Задайте название, окружение и экспозицию.", + "backToCatalog": "Вернуться к каталогу", + "close": "Закрывать", + "browse": "Просматривать", + "allServices": "Все услуги", + "customImage": "Пользовательское изображение", + "services": "Услуги", + "serviceCountOne": "Сервис {count}", + "serviceCountOther": "Сервисы {count}", + "searchPlaceholder": "Поиск по названию, изображению или тегу…", + "cloudConnectHint": "Подключите Openship Cloud для просмотра каталога облачных сервисов. Вы по-прежнему можете добавить любое изображение вручную.", + "cloudConnectTitle": "Подключите облако Openship", + "cloudConnectBody": "Свяжите этот экземпляр с Openship Cloud для просмотра и добавления управляемых облачных изображений. Вы по-прежнему можете добавить любое изображение вручную из локальных изображений.", + "cloudConnectButton": "Подключитесь к облаку Openship", + "noMatchesTitle": "Спичек нет", + "noMatchesBody": "Попробуйте другую категорию или поисковый запрос - или выберите пользовательское изображение из списка.", + "localImages": "Локальные изображения", + "openshipCloud": "Облако Openship", + "localDocker": "Местный докер", + "customEntryName": "Пользовательское изображение", + "customEntryDescription": "Извлеките любое общедоступное или частное изображение Docker по тегу.", + "unnamed": "Безымянный", + "serviceName": "Имя", + "ports": "Порты", + "image": "Изображение", + "persistentVolumes": "Постоянные тома", + "preSeeded": "Предварительно отобранные для этой услуги", + "optional": "Необязательный", + "removeVolume": "Уменьшите громкость", + "addVolume": "Добавьте громкости", + "volumesHint": "Тома сохраняют данные при перезапуске. Название слева, путь к контейнеру справа.", + "environmentVariables": "Переменные среды", + "cancel": "Отменить", + "addService": "Добавь", + "serviceNameRequired": "Требуется указать имя.", + "imageRequired": "Требуется изображение.", + "addServiceFailed": "Не удалось добавить службу", + "categories": { + "database": "Базы данных", + "cache": "Тайники", + "search": "Поиск", + "vector": "Вектор и искусственный интеллект", + "queue": "Очереди и потоки", + "storage": "Хранилище объектов", + "auth": "Аутентификация и идентичность", + "mail": "Почта и SMTP", + "runtime": "Время выполнения", + "other": "Другой" + } + }, + "detail": { + "tabs": { + "overview": "Обзор", + "terminal": "Терминал", + "logs": "Бревна", + "env": "Окружающая среда", + "settings": "Настройки", + "backup": "Резервная копия" + }, + "status": { + "running": "Бегущий", + "stopped": "Остановился", + "disabled": "Нетрудоспособный", + "failed": "Неудачный", + "starting": "Начало", + "restarting": "Повторный запуск", + "unknown": "Неизвестный" + }, + "network": "Сеть", + "configuration": "Конфигурация", + "volumes": "Тома", + "terminal": "Терминал", + "backup": "Резервная копия", + "ports": "Порты", + "hostPort": "Порт хоста", + "containerIp": "IP-адрес контейнера", + "internalAddress": "Внутренний адрес", + "internalAddressHint": "По этому адресу можно получить доступ к другим службам.", + "currentIp": "Текущий IP-адрес", + "currentIpHint": "Изменения при перезапуске — вместо этого используйте внутренний адрес, указанный выше.", + "workspaceId": "Идентификатор рабочей области", + "containerId": "Идентификатор контейнера", + "restartPolicy": "Политика перезапуска", + "command": "Команда", + "dependsOn": "зависит от", + "startShellHint": "Запустите службу, чтобы открыть оболочку.", + "saveEnvironment": "Сохранение окружающей среды", + "stop": "Остановка", + "restart": "Перезапуск", + "start": "Начать", + "starting": "Начало…", + "enableAndStart": "Включить и запустить", + "redeploying": "Повторное развертывание…", + "redeploy": "Повторно развернуть", + "disableService": "Отключить службу", + "enableService": "Включить службу", + "delete": "Удалить", + "backupSubtitle": { + "manualOnly": "только вручную", + "cron": "cron {expr}", + "preDeploy": "предварительное развертывание", + "webhook": "веб-крючок", + "none": "Для этой службы нет политики резервного копирования" + }, + "backupNow": "Сделайте резервную копию сейчас", + "editPolicy": "Редактировать политику", + "createPolicy": "Создать политику", + "deleteTitle": "Удалить службу", + "deleteBody": "Это удалит \"{name}\" из проекта и очистит его активный контейнер и маршрут.", + "deleteCancel": "Отменить", + "deleteConfirm": "Удалить службу", + "toast": { + "envUpdated": "Обновленная среда", + "envSaveFailed": "Не удалось сохранить окружающую среду", + "deployFirstStart": "Сначала разверните проект, затем запустится эта служба", + "deployFailed": "Не удалось выполнить развертывание", + "serviceStarting": "{name} запускается", + "serviceTitle": "Услуга", + "deployFirstRedeploy": "Сначала разверните проект, затем вы сможете повторно развернуть эту службу", + "enableBeforeRedeploy": "Включите службу перед ее повторным развертыванием", + "redeployFailed": "Не удалось выполнить повторное развертывание", + "stillStarting": "Все еще запускается - проверьте логи на предмет прогресса", + "serviceUpdated": "Обновлен сервис", + "updateFailed": "Не удалось обновить службу", + "serviceDeleted": "Служба удалена", + "deleteFailed": "Не удалось удалить службу", + "backupRunFailed": "Не удалось выполнить резервное копирование" + }, + "duplicateContainers": "Другой контейнер также соответствует этому сервису: {names}", + "editInSettings": "Редактировать в настройках" + }, + "settingsForm": { + "name": "Имя", + "rootDirectory": "Корневой каталог", + "framework": "Рамки", + "packageManager": "Менеджер пакетов", + "buildImage": "Создание имиджа", + "installCommand": "Команда установки", + "buildCommand": "Команда построения", + "startCommand": "Команда запуска", + "outputDirectory": "Выходной каталог", + "image": "Изображение", + "dockerfile": "Файл Dockerfile", + "buildContext": "Создание контекста", + "ports": "Порты", + "dependsOn": "Зависит от", + "command": "Команда", + "restartPolicy": "Политика перезапуска", + "volumes": "Тома", + "healthcheck": "Проверка состояния здоровья", + "healthcheckHint": "Команда проверки (форма оболочки). Оставьте поле пустым, чтобы использовать проверку изображения по умолчанию.", + "enabled": "Включенный", + "enabledHint": "Включенные службы развертываются вместе с проектом.", + "saveChanges": "Сохранить изменения", + "errors": { + "nameRequired": "Требуется указать название службы.", + "imageOrDockerfile": "Добавьте имя изображения или контекст сборки / Dockerfile.", + "buildContextOrDockerfile": "Добавьте контекст сборки или путь к файлу Dockerfile.", + "rootDirectory": "Добавьте корневой каталог (например, apps/web).", + "buildOrStart": "Добавьте хотя бы команду сборки или запуска.", + "saveFailed": "Не удалось сохранить сервис." + }, + "alias": "Сетевой псевдоним", + "aliasHint": "Дополнительное DNS-имя, которое другие службы могут использовать для доступа к этой службе, наряду с ее именем службы. Оставьте значение по умолчанию пустым.", + "portsHint": "Порт контейнера или хост:container. Нажмите Enter, чтобы добавить каждый из них.", + "volumesHint": "Путь к именованному тому или хосту, сопоставленный с путем к контейнеру. Нажмите Enter, чтобы добавить каждый из них.", + "dependsOnHint": "Службы, которые должны быть запущены раньше этой.", + "dependsOnEmpty": "Других сервисов в этом проекте пока нет.", + "removeTag": "Удалять", + "sections": { + "general": "Общие", + "generalHint": "Имя и то, развертывается ли эта служба вместе с проектом.", + "source": "Источник", + "sourceHint": "Извлеките предварительно созданный образ или создайте его из файла Dockerfile в вашем репозитории.", + "sourceMonorepoHint": "Как устанавливается, компонуется и запускается это приложение.", + "networking": "Сетевой", + "networkingHint": "Порты, внутренний псевдоним DNS и порядок запуска.", + "runtime": "Время выполнения", + "runtimeHint": "Запустите команду, перезапустите политику и подключенные тома.", + "health": "Здоровье и готовность", + "healthHint": "Проверка работоспособности и контроль готовности к развертыванию." + }, + "orBuildFromSource": "или создавать из исходного кода", + "imageHint": "Оставьте поле пустым, чтобы создать его из приведенного ниже файла Dockerfile." + } + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/projectSettings.json b/apps/dashboard/src/i18n/locales/ru/projectSettings.json new file mode 100644 index 000000000..228719fab --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/projectSettings.json @@ -0,0 +1,970 @@ +{ + "settingSection": { + "edit": "Редактировать", + "save": "Сохранить", + "cancel": "Отменить" + }, + "appSource": { + "title": "Источник", + "description": "Это приложение развертывается из выпуска — здесь нет репозитория, на который можно было бы перейти; обновления отправляются в виде новых версий.", + "sourceType": "Источник", + "kindRelease": "Выпускать", + "kindImage": "Изображение контейнера", + "current": "Текущая версия", + "latest": "Последняя версия", + "repository": "Хранилище", + "notChecked": "Еще не проверено", + "upToDate": "До настоящего времени", + "updateAvailable": "Доступно обновление", + "checkForUpdates": "Проверяйте наличие обновлений", + "checkFailed": "Не удалось проверить наличие обновлений", + "update": "Обновление", + "updateTo": "Обновить до {version}", + "updating": "Обновление…", + "updateFailed": "Не удалось выполнить обновление", + "toastTitle": "Источник", + "cliManaged": "Это панель управления Openship — она обновляется сама по себе. Запустите \"openship update\" на хосте, чтобы обновить ее; здесь ничего не нужно менять." + }, + "appSettings": { + "modeApp": "Настройки приложения", + "modeDeployment": "Развертывание", + "saveChanges": "Сохранить изменения", + "saving": "Экономия…", + "saved": "Настройки сохранены", + "saveHint": "Сохраните, чтобы сохранить эти изменения — они применятся при следующем развертывании приложения.", + "applyNow": "Подайте заявку прямо сейчас", + "applying": "Обратившийся…", + "applied": "Применение изменений", + "restartNote": "Примените это сейчас, чтобы перезапустить приложение с новыми настройками, или они вступят в силу при следующем развертывании.", + "redeployNote": "Применение этих изменений приводит к воссозданию приложения — после этого вам может потребоваться повторно аутентифицировать его панель мониторинга или интерфейс командной строки.", + "advancedShow": "Показать продвинутый", + "advancedHide": "Скрыть расширенный", + "secretSet": "Установить — оставить пустым, чтобы сохранить текущее значение", + "loadError": "Не удалось загрузить настройки приложения.", + "saveFailed": "Не удалось сохранить настройки.", + "applyFailed": "Не удалось применить изменения.", + "unmanaged": "Это приложение пока не имеет настраиваемых настроек." + }, + "appInstall": { + "install": "Устанавливать", + "installing": "Установка…", + "advanced": "Расширенные возможности развертывания", + "nameLabel": "Имя", + "nameHint": "Как это приложение отображается в Openship.", + "domainTitle": "Где он должен жить?", + "domainFree": "Свободный поддомен", + "domainFreeHint": "Бесплатный поддомен на {domain}", + "domainCustom": "Ваш собственный домен", + "domainCustomPlaceholder": "app.example.com", + "domainNone": "Нет общедоступного URL-адреса", + "domainNoneHint": "Только для внутренних целей — без публичного адреса.", + "customRequired": "Введите свой домен или выберите другой вариант.", + "progressPreparing": "Подготовка…", + "progressDeploying": "Развертывание…", + "progressLive": "Ваше приложение работает в режиме реального времени", + "openApp": "Открыть приложение", + "goToApp": "Перейти к приложению", + "installFailed": "Не удалось выполнить установку", + "viewDetails": "Просмотр технических подробностей", + "showLogs": "Показывать журналы", + "hideLogs": "Скрывать журналы", + "deployLogs": "развертывание журналов", + "back": "Назад", + "phaseImages": "Подготовка изображений", + "phaseServices": "Запуск служб", + "phaseAppSetup": "Завершающая настройка", + "phaseReady": "Жить", + "phaseQueued": "Поставленный в очередь…", + "stepperTitle": "Этапы установки", + "firstLoginTitle": "Первый вход в систему", + "firstLoginUser": "Имя пользователя", + "firstLoginPassword": "Пароль", + "destinationTitle": "Где установить", + "destinationHint": "Выберите сервер или облако, на котором работает это приложение.", + "descMore": "Больше", + "descLess": "Менее", + "needsTitle": "Что ему нужно", + "needsMemory": "ОПЕРАТИВНАЯ память {value}", + "needsCpu": "{value} ХVARX", + "hostFitTitle": "Этот сервер меньше, чем нужно {app}", + "hostFitMemory": "Требуется {needed} оперативной памяти — у этого есть {available}", + "hostFitCpu": "Нужен {needed} — у этого есть {available}", + "hostFitHint": "Установите его на более крупную машину или выберите другое место назначения.", + "routePortLabel": "Только порт (без домена)", + "routePortDesc": "Доступен по адресу хоста и порту — домен или облако не требуются.", + "routeFreeLabel": "Свободный поддомен", + "routeFreeDesc": "Бесплатный поддомен на {domain}, маршрутизируемый с помощью Openship Cloud.", + "routeFreeNeedsCloud": "Подключите Openship Cloud, чтобы использовать бесплатный поддомен.", + "routeCustomLabel": "Ваш собственный домен", + "routeCustomDesc": "Укажите свой собственный домен в этом приложении.", + "routeDomainLabel": "Домен", + "routeDomainDesc": "Найдите его на домене — бесплатном поддомене или на своем собственном.", + "exposeTitle": "Воздействие", + "httpBadge": "Сеть", + "tcpBadge": "База данных", + "tcpPublishLabel": "Опубликовать порт", + "tcpPublishDesc": "Опубликуйте его на хостинге, чтобы можно было подключать внешние инструменты.", + "tcpInternalLabel": "Только внутренний", + "tcpInternalDesc": "Только другие службы в этом приложении могут получить доступ к нему.", + "tcpFirewallNote": "Откройте порт {port} на брандмауэре вашего сервера для подключения извне.", + "desktopReachNote": "На рабочем столе вы можете открыть его на локальном хостинге — или перенаправить порт из меню Серверы → Порты для удаленного сервера.", + "statusInstalling": "Установка", + "statusLive": "Жить", + "statusCancelled": "Отмененный", + "statusFailed": "Неудачный", + "stopInstall": "Остановить установку", + "stopping": "Остановка…", + "installCancelled": "Установка отменена", + "startOver": "Начать сначала", + "breadcrumbApps": "Приложения", + "appEyebrow": "Апп", + "stopFailed": "Не удалось остановить установку", + "mail": { + "title": "Настройка почты", + "subtitle": "Разверните веб-почту в своем собственном домене или подключите существующий почтовый ящик.", + "chooseSelf": "Самостоятельное размещение почтового сервера", + "chooseSelfDesc": "Полный протокол SMTP/IMAP + веб—почта (iRedMail) на вашем сервере - мы предоставляем все необходимое.", + "chooseConnect": "Подключение существующего почтового ящика", + "chooseConnectDesc": "Разверните только пользовательский интерфейс веб—почты, подключенный к любому внешнему поставщику SMTP/IMAP - Amazon SES, Oracle Cloud, Gmail, Fastmail и многим другим.", + "provider": "Поставщик", + "presets": { + "custom": "Обычай", + "ses": "Амазонка СЭС", + "gmail": "Gmail", + "fastmail": "Быстрая почта" + }, + "sendOnlyNote": "{provider} отправляет только почту — в нем нет почтовых ящиков. IMAP должен указывать на то, где на самом деле хранится ваша почта.", + "sendOnlyNoInbox": "Еще нет почтового ящика? Настройте почтовый сервер здесь, затем ретранслируйте отправку через {provider} →", + "imapOnOurServer": "Почтовые ящики считываются с {host} — собственного почтового сервера этого экземпляра. Только отправка осуществляется через {provider}.", + "relayNote": "На этом экземпляре уже запущен почтовый сервер. Если на нем установлены почтовые ящики, вместо этого повторите отправку с его вкладки \"Доставка\" → \"Отправка\": IMAP остается локальным, и отправка осуществляется только на {provider} для каждого домена или адреса, а его собственная веб-почта продолжает работать.", + "relayCta": "Вместо этого настройте ретранслятор →", + "hostname": "Адрес веб-почты", + "hostnameHint": "Общедоступный URL-адрес, который люди открывают для чтения своей почты, например mail.example.com.", + "imapHost": "Узел IMAP", + "imapPort": "Порт IMAP", + "smtpHost": "SMTP-хост", + "smtpPort": "SMTP-порт", + "deploy": "Развертывание веб-почты", + "deploying": "Развертывание…", + "hostnameRequired": "Введите адрес веб-почты.", + "hostsRequired": "Введите как IMAP-узел, так и SMTP-узел." + } + }, + "advanced": { + "projectInfo": { + "title": "Информация о проекте", + "description": "Краткое описание текущей конфигурации" + }, + "metric": { + "status": "Статус", + "project": "Проект", + "hostedOn": "Размещенный на" + }, + "projectMenu": { + "rename": "Переименовать проект", + "copyId": "Скопировать идентификатор проекта", + "idCopied": "Скопирован идентификатор проекта", + "copyFailed": "Не удалось скопировать в буфер обмена", + "pause": "Приостановить проект", + "resume": "Возобновить проект", + "delete": "Удалить проект" + }, + "rename": { + "title": "Переименовать проект", + "description": "Изменяет отображаемое имя. Ничего не перемещается.", + "label": "Название проекта", + "placeholder": "Мой проект", + "identityNote": "Проект сохраняет идентификатор “{slug}” — его URL, названия контейнеров и объемы не меняются. Чтобы изменить URL, отредактируйте домен в разделе Домены и маршруты.", + "save": "Сохранить", + "cancel": "Отменить", + "toast": { + "renamed": "Переименовано в {name}", + "failed": "Не удалось переименовать проект" + } + }, + "statusActive": "Активный", + "statusDisabled": "Нетрудоспособный", + "hostedCloud": "Облако Openship", + "hostedServer": "Сервер", + "hostedLocal": "Местный", + "projectStatus": { + "title": "Статус проекта", + "description": "Контролируйте, запущен ли проект в режиме реального времени или приостановлен", + "active": "Активный проект", + "disabled": "Проект отключен", + "liveAccessible": "Живой и доступный", + "pausedInaccessible": "Приостановлен и недоступен", + "disable": "Отключать", + "enable": "Включить" + }, + "cache": { + "title": "Кэш", + "description": "Очистка кэшированных артефактов сборки и установок зависимостей", + "clearInstall": "Очистите установочный кэш", + "clearInstallDesc": "Удалить кэшированные node_modules", + "clearBuild": "Очистить кэш сборки", + "clearBuildDesc": "Удалить кэшированные выходные данные сборки" + }, + "transfer": { + "title": "Перенос и клонирование", + "description": "Переместите или продублируйте этот проект в другую среду", + "current": "Текущий", + "transfer": "Перемещение", + "clone": "Клон", + "anotherServer": "Другой сервер", + "targetLocal": "Локальный компьютер", + "targetServer": "Автономный сервер", + "targetCloud": "Облако Openship" + }, + "danger": { + "title": "Опасная зона", + "description": "Необратимые действия в рамках этого проекта", + "body": "Удаление этого проекта приведет к необратимому удалению всех развертываний, пользовательских доменов, переменных среды и аналитических данных.", + "delete": "Удалить проект" + }, + "toast": { + "toggleFailed": "Не удалось переключить проект", + "clearInstallFailed": "Не удалось очистить установочный кэш", + "clearBuildFailed": "Не удалось очистить кэш сборки" + }, + "routing": { + "title": "Маршрутизация", + "description": "Как преимущество достигает восходящего потока этого приложения", + "intro": "Выберите, как edge обращается к контейнеру этого проекта.", + "note": "Рекомендуется использовать порт обратной связи: частный порт хоста 127.0.0.1, стабильный при перезапуске и не зависящий от сети. Расширен IP-адрес контейнера (обмен данными с нулевым временем простоя; требуется преимущество на Docker bridge; не поддерживается на Docker Desktop).", + "modes": { + "auto": { + "label": "Авто", + "desc": "Рекомендуется (порт обратной связи)" + }, + "loopbackPort": { + "label": "Петлевой порт", + "desc": "Частный порт хоста 127.0.0.1" + }, + "containerIp": { + "label": "IP-адрес контейнера", + "desc": "Расширенный IP—адрес моста" + } + }, + "toast": { + "saved": "Маршрутизация установлена на {mode}", + "failed": "Не удалось обновить маршрутизацию" + } + }, + "internalAlias": { + "title": "Внутреннее имя хоста", + "description": "Пользовательское имя, используемое другими службами для доступа к этому приложению в частном порядке", + "intro": "Задайте дополнительное DNS-имя для этого приложения в частной сети project. Оно будет использоваться вместе с именем по умолчанию (project slug) — другие связанные службы могут использовать любое из них. Общий доступ остается неизменным; при этом никогда не указывается порт.", + "label": "Псевдоним имени хоста", + "hint": "Только буквы, цифры и тире. Оставьте поле пустым, чтобы использовать project slug.", + "save": "Сохранить", + "toast": { + "saved": "Обновлено внутреннее имя хоста", + "failed": "Не удалось обновить внутреннее имя хоста", + "invalid": "Введите хотя бы одну букву или цифру" + } + } + }, + "routeRules": { + "title": "Правила маршрута", + "description": "Правила ограничения скорости, запрета и разрешения/запрещения, применяемые на границе, применяются мгновенно, без повторного развертывания.", + "loading": "Правила загрузки…", + "empty": "Правил маршрута пока нет. Добавьте их ниже.", + "allHosts": "Все имена хостов", + "allPaths": "Все пути", + "addTitle": "Добавьте правило", + "pathLabel": "Префикс пути (необязательно)", + "rps": "Количество запросов в секунду", + "burst": "Взрыв", + "methods": "Разрешать только методы", + "banIps": "Запретить IP-адреса / CIDR", + "banCountries": "Страны, в которых действует запрет (ISO)", + "allowCountries": "Разрешить только странам (ISO)", + "denyCidrs": "Запрещать CIDR", + "allowReferers": "Горячая ссылка: разрешить использование ссылок", + "banUserAgents": "Запретить пользовательские агенты (подстрока)", + "blockEmptyUa": "Заблокировать пустой пользовательский агент", + "blockStatus": "Блокируйте код ответа", + "add": "Добавить правило", + "remove": "Удалять", + "enabled": "Включенный", + "disabled": "Нетрудоспособный", + "saved": "Правило сохранено", + "saveFailed": "Не удалось сохранить правило", + "loadFailed": "Не удалось загрузить правила" + }, + "backup": { + "live": { + "title": "Оперативное резервное копирование", + "description": "Отслеживание прогресса в режиме реального времени для запуска, который вы только что запустили. Обновление страницы сохраняется.", + "dismiss": "Увольнять" + }, + "destinations": { + "title": "Пункты назначения для резервного копирования", + "description": "Целевые хранилища для каждого пользователя. Добавьте сегменты, совместимые с S3, серверы SFTP или локальные диски.", + "manage": "Управлять", + "loading": "Погрузка…", + "emptyPrefix": "Пунктов назначения пока нет. ", + "emptyLink": "Создайте один из них", + "emptySuffix": " чтобы начать резервное копирование.", + "verified": "Проверенный", + "failed": "Неудачный" + }, + "services": { + "title": "Услуги + политика", + "description": "У каждой службы может быть своя политика резервного копирования (расписание + пункт назначения). Настройки по умолчанию на уровне проекта указаны в разделе 2.", + "refresh": "Освежить", + "empty": "В этом проекте пока нет служб. Резервные копии сервисного уровня появятся здесь, как только вы их добавите.", + "policyLabel": "Политика:", + "manualOnly": "только вручную", + "preDeploy": "предварительное развертывание", + "webhook": "веб-крючок", + "noPolicy": "Никакой политики", + "backupNow": "Сделайте резервную копию сейчас", + "editPolicy": "Редактировать политику", + "addDestinationFirst": "Сначала добавьте пункт назначения", + "createPolicyHint": "Создайте политику резервного копирования для этой службы", + "createPolicy": "Создать политику" + }, + "recent": { + "title": "Последние резервные копии", + "description": "25 самых последних запусков во всех службах этого проекта.", + "loading": "Погрузка…", + "empty": "Резервных копий пока нет.", + "protectedTitle": "Защищенный от застывания чернослив", + "protected": "Защищенный", + "restoreTitle": "Восстановите из этой резервной копии", + "allowPrune": "Дайте настояться, чтобы подрезать", + "protectFrom": "Защищать от удержания" + }, + "toast": { + "runFailed": "Не удалось выполнить резервное копирование", + "toggleProtectionFailed": "Не удалось переключить защиту" + } + }, + "build": { + "edit": "Редактировать", + "webmail": { + "title": "Управляемый открытым кораблем", + "description": "В веб—почте используется фиксированный конвейер сборки и запуска - команды установки, сборки и запуска не настраиваются. Выполните повторное развертывание из обзора почты, чтобы просмотреть изменения, внесенные ранее." + }, + "services": { + "title": "Настройки для каждой службы", + "descriptionTemplate": "В этом проекте есть {serviceLabel}. Команды сборки, фреймворка, портов и запуска отображаются в каждой строке сервиса — просмотрите и отредактируйте их на вкладке \"Сервисы\".", + "open": "Открытые сервисы", + "subAppOne": "Дополнительное приложение {count}", + "subAppOther": "Вложенные приложения {count}", + "composeOne": "Служба компоновки {count}", + "composeOther": "Службы компоновки {count}", + "both": "{subApps} и {composeServices}" + }, + "runtime": { + "title": "Конфигурация среды выполнения", + "description": "Доступно только для чтения. Отредактируйте с помощью мастера развертывания, чтобы каждое изменение отправлялось как новая версия.", + "framework": "Рамки", + "packageManager": "Менеджер пакетов", + "runtimeIsolation": "Изоляция во время выполнения", + "runtimePort": "Порт времени выполнения", + "installCommand": "Команда установки", + "buildCommand": "Команда построения", + "noBuildStep": "Нет этапа сборки", + "outputDirectory": "Выходной каталог", + "rootDirectory": "Корневой каталог", + "composePath": "Создать файл", + "startCommand": "Команда запуска", + "staticNoServer": "Статический (без сервера)", + "modeSandboxed": "Изолированный (контейнер)", + "modeDirect": "Прямой (хост-процесс)", + "modeDefault": "Значение по умолчанию (разрешено при развертывании)", + "modeStatic": "Нет — обслуживаются как статические файлы." + }, + "storage": { + "title": "Постоянное хранилище", + "description": "Пути сохраняются, когда новая версия заменяет старую. Все остальное в контейнере удаляется при развертывании.", + "edit": "Редактировать", + "save": "Сохранить", + "cancel": "Отменить", + "saved": "Хранилище обновлено. Это применимо при следующем развертывании.", + "reset": "Использовать значения фреймворка по умолчанию", + "empty": "Между развертываниями ничего не сохраняется.", + "inherited": "Значения фреймворка по умолчанию для этого стека.", + "declared": "Набор для этого проекта.", + "placeholder": "загрузки из хранилища\n:/app/public/uploads", + "hint": "По одному на строку. Простой путь относится к приложению (хранилище) или задайте полное подключение (имя:/app/path, /host/path:/app/path)." + }, + "objectStorage": { + "title": "Хранилище объектов", + "description": "Корзина S3 для загрузок — выдерживает повторное развертывание и работает с несколькими репликами, в отличие от локального пути.", + "connect": "Подключить", + "disconnect": "Разъединять", + "disconnected": "Хранилище объектов отключено.", + "connected": "Корзина проверена и подключена. Это применимо при следующем развертывании.", + "loading": "Проверка…", + "empty": "Корзина не подключена. Загруженные файлы сохраняются на диске контейнера.", + "sourceLabel": "Источник", + "externalOption": "Внешний поставщик услуг", + "providerLabel": "Поставщик", + "bucketLabel": "Ведро", + "endpointLabel": "Конечная точка", + "regionLabel": "Регион", + "accessKeyLabel": "Идентификатор ключа доступа", + "secretKeyLabel": "Секретный ключ доступа", + "testAndConnect": "Тестирование и подключение", + "cancel": "Отменить", + "envLabel": "Переменные", + "envHint": "Наборы:", + "appliesOnDeploy": "Применяется при следующем развертывании." + }, + "env": { + "title": "Переменные среды", + "description": "Шифруется в режиме ожидания. Секретные данные остаются замаскированными — записываются только те значения, которые вы изменили.", + "edit": "Редактировать" + } + }, + "envVars": { + "cancel": "Отменить", + "saveChanges": "Сохранить изменения", + "close": "Закрывать", + "applyTitle": "Применить без перестройки", + "applyText": "Сохраненный. Примените их к запущенной службе — она перезапустится с новым env, без клонирования или перестройки.", + "applyButton": "Применить (перезапустить, без перестройки)", + "title": "Переменные среды", + "description": "Производство. Зашифрован в состоянии покоя. Секретные данные отображаются в виде набора — введите для замены; оставьте пустым, чтобы сохранить.", + "empty": "Переменных окружения пока нет.", + "keyPlaceholder": "ключ", + "secretPlaceholder": "•••••••• (набор — тип для замены)", + "valuePlaceholder": "ценность", + "hideValue": "Скрыть значение", + "showValue": "Показать значение", + "markedSecret": "Помеченный грифом секретно", + "markSecret": "Пометить как секретный", + "removeVariable": "Удалить переменную", + "addVariable": "Добавить переменную", + "toast": { + "loadFailed": "Не удалось загрузить переменные окружения", + "loadFailedTitle": "Ошибка", + "validationTitle": "Утверждение", + "saved": "Сохраненные переменные среды", + "savedTitle": "Сохраненный", + "saveFailed": "Не удалось сохранить переменные среды", + "saveFailedTitle": "Сохранить не удалось", + "applying": "Перезапуск службы с новым env — без перестроения.", + "applyingTitle": "Обратившийся", + "applyFailed": "Не удалось применить env к запущенной службе", + "applyFailedTitle": "Применить не удалось" + }, + "linkedBadge": "Связанный", + "linkedManaged": "через {app}", + "linkedTitle": "Связанная интеграция", + "linkedBody": "Это значение получено из соединения {app}. Управляйте им из этого приложения — внесенные здесь изменения не сохранятся.", + "unlink": "Удалить соединение" + }, + "gitInfo": { + "repository": "Хранилище", + "autoDeploy": "Автоматическое развертывание", + "deploysOnPush": "Разворачивается при каждом нажатии", + "manualOnly": "Выполняется только ручное развертывание", + "branchToDeploy": "Филиал для развертывания", + "chooseBranch": "Выберите, какую ветку развернуть из вашего репозитория", + "save": "Сохранить", + "cancel": "Отменить", + "viewOnGithub": "Посмотреть на GitHub", + "recentCommits": "Недавние фиксации", + "totalCommits": "{count} всего", + "noCommits": "Пока никаких коммитов нет", + "toast": { + "fetchBranchesFailed": "Не удалось получить ветки", + "errorTitle": "Ошибка", + "branchUpdated": "Ветка успешно обновлена", + "updatedTitle": "Обновленный", + "branchUpdateFailed": "Не удалось обновить ветку", + "autoDeployEnabled": "Включено автоматическое развертывание", + "autoDeployDisabled": "Автоматическое развертывание отключено", + "autoDeployFailed": "Не удалось обновить автоматическое развертывание" + } + }, + "git": { + "connectFirst": { + "title": "Сначала подключите GitHub", + "description": "Привяжите свою учетную запись на GitHub, чтобы подключить репозиторий к этому проекту.", + "connecting": "Связывающий…", + "connect": "Подключите GitHub" + }, + "link": { + "title": "Связать репозиторий", + "description": "Подключите репозиторий GitHub, чтобы включить развертывание с помощью webhook.", + "select": "Выберите репозиторий" + }, + "picker": { + "title": "Выберите репозиторий", + "description": "Выберите репозиторий для ссылки на этот проект", + "linking": "Связывающий репозиторий…" + }, + "appBanner": { + "title": "Приложение GitHub не установлено", + "description": "Установите приложение Openship GitHub в своей учетной записи или организации, чтобы включить автоматическое развертывание и запуск webhook для облачных проектов.", + "install": "Установите приложение GitHub" + }, + "webhookBanner": { + "title": "Включить автоматическое развертывание", + "description": "Для автоматического развертывания требуется прямая конечная точка webhook. Разместите этот API Openship на общедоступном URL-адресе или настройте подтвержденный домен webhook для прямой доставки." + }, + "source": { + "title": "Хранилище исходных текстов", + "description": "Интеграция Git, триггеры развертывания и работоспособность репозитория", + "repository": "Хранилище", + "open": "Открыть" + }, + "webhookEndpoint": { + "title": "Конечная точка Webhook", + "descriptionSet": "GitHub доставляет push-события непосредственно в этот домен", + "descriptionUnset": "Выберите домен для прямой доставки webhook", + "updating": "Обновление...", + "select": "Выберите домен...", + "clear": "Четкий выбор" + }, + "autoDeployCard": { + "title": "Автоматическое развертывание", + "enabled": "Включенный", + "disabled": "Нетрудоспособный", + "descDelivers": "Толчки доставляют в {domain}", + "descAuto": "Автоматически запускает запускающие устройства", + "descManual": "Развертывание должно быть запущено вручную" + }, + "webhookCard": { + "title": "Веб-крючок", + "direct": "Прямой", + "active": "Активный", + "inactive": "Неактивный", + "descDirect": "Мероприятия проводятся непосредственно через {domain}", + "descActive": "События репозитория достигают Openship", + "descInactive": "Webhook не был настроен или не отвечает" + }, + "rollbackStrategy": { + "title": "Стратегия отката", + "rebuild": "Перестроить (git)", + "instant": "Мгновенный (моментальный снимок)", + "descRebuild": "Восстанавливает старую фиксацию, если только ее образ все еще не находится на хосте.", + "descInstant": "Сохраняет образ каждой версии, поэтому восстановление никогда не выполняется заново. Используется больший объем диска.", + "toggleAria": "Переключение режима сохранения моментальных снимков", + "keepNone": "Не храните никаких дополнительных копий", + "keepCopies": "Сохраняйте копию для каждой версии", + "descRebuildFiles": "Восстанавливает старый коммит, если только его файлы все еще не находятся на хосте.", + "descInstantFiles": "Сохраняет файлы всех версий, поэтому восстановление никогда не выполняется заново. Используется больший объем диска." + }, + "rollbackHistory": { + "title": "История отката", + "valueOne": "Версия {count}", + "valueOther": "Версии {count}", + "descSnapshot": "Более старые версии удаляются для освобождения места на диске.", + "descGit": "Последние изображения сохраняются в любом случае, поэтому при откате сборка может быть пропущена.", + "decreaseAria": "Уменьшить историю откатов", + "increaseAria": "Увеличить историю откатов", + "sizeEach": "~{size} каждый", + "diskFree": "{size} бесплатно", + "autoBadge": "определяемый автоматически размер", + "manualBadge": "устанавливается вручную", + "kindFiles": "созданные файлы на диске", + "kindImages": "изображения на хосте", + "descGitFiles": "Файлы последних версий сохраняются в любом случае, поэтому при откате сборка может быть пропущена." + }, + "commits": { + "title": "Недавние фиксации", + "subtitle": "Последние фиксации в {branch}", + "empty": "Никаких коммитов найдено не было", + "emptyDesc": "Перейдите в свой репозиторий, и здесь появятся последние действия по фиксации.", + "viewAll": "Просмотр всех коммитов на GitHub" + }, + "cloneToken": { + "title": "Переопределение токена клонирования", + "description": "Токен в рамках проекта, используемый модулем clone, прежде чем вернуться к вашему глобальному токену или приложению GitHub", + "loading": "Погрузка…", + "explainer": "Вставьте сюда ссылку на GitHub, чтобы использовать ее только для этого проекта. Наивысший приоритет в цепочке клонирования - переопределяет ваш токен уровня настроек и приложение GitHub.", + "hide": "Скрыть токен", + "show": "Показать жетон", + "saveToken": "Сохранить токен", + "cancel": "Отменить", + "savedTitle": "Токен, сохраненный для этого проекта", + "lastUpdated": "Последнее обновление {when}", + "justNow": "прямо сейчас", + "replace": "Заменять", + "clear": "Четкий" + }, + "toast": { + "pasteToken": "Вставьте маркер перед сохранением", + "cloneTokenTitle": "Токен клонирования", + "tokenSaved": "Сохраненный токен клонирования проекта", + "tokenSaveFailed": "Не удалось сохранить токен", + "tokenCleared": "Токен клонирования проекта очищен", + "tokenClearFailed": "Не удалось очистить токен", + "autoDeployEnabled": "Включено автоматическое развертывание", + "autoDeployDisabled": "Автоматическое развертывание отключено", + "autoDeployFailed": "Не удалось переключить автоматическое развертывание", + "rollbackGit": "Стратегия отката: управляемая Git (без моментальных снимков)", + "rollbackSnapshot": "Стратегия отката: Моментальный снимок (артефакты сохраняются)", + "rollbackStrategyFailed": "Не удалось обновить стратегию отката", + "rollbackWindowOne": "Сохранение последней версии {count} для отката", + "rollbackWindowOther": "Сохранение последних версий {count} для отката", + "rollbackHistoryFailed": "Не удалось обновить историю отката", + "webhookDomainSet": "Для домена Webhook установлено значение {domain}", + "webhookDomainCleared": "Домен Webhook очищен", + "webhookDomainFailed": "Не удалось установить домен webhook", + "linked": "Связан с {repo}", + "appNotInstalled": "Приложение GitHub не установлено для этой учетной записи", + "linkFailed": "Не удалось связать репозиторий" + } + }, + "logs": { + "noRuntime": "Нет журналов времени выполнения", + "noRuntimeDesc": "В этом проекте нет запущенного серверного процесса и домена, поэтому потоковой передачи нет. Добавьте домен, и здесь появятся журналы его пограничных запросов.", + "terminal": "Терминал", + "server": "Сервер", + "requests": "Запросы", + "target": "Цель журнала выполнения", + "targetDescProject": "Переключение между временем выполнения проекта и временем выполнения службы.", + "targetDescService": "Переключайтесь между режимами работы служб.", + "projectRuntime": "Время выполнения проекта", + "selectService": "Выберите службу, чтобы просмотреть ее журналы выполнения.", + "projectFallback": "Проект" + }, + "resources": { + "title": "Мощность машины", + "description": "Ограничения по процессору и памяти для контейнеров этого проекта.", + "loading": "Считывание данных с целевого компьютера…", + "machineCapacity": "Машина: {cpu} vCPU · {memory}", + "exceedsMachine": "Превосходит эту машину", + "appliesOnNextDeploy": "Ограничения применяются при повторном создании контейнера — повторном развертывании, чтобы изменения вступили в силу.", + "tiers": { + "unlimited": { + "name": "Никаких ограничений", + "description": "Используйте всю машину целиком (по умолчанию)", + "spec": "Производительность машины" + }, + "micro": { + "name": "Микро", + "description": "Крошечные коляски и рабочие" + }, + "low": { + "name": "Низкий", + "description": "Небольшие приложения и статичные сайты" + }, + "medium": { + "name": "Средний", + "description": "Большинство веб-приложений" + }, + "high": { + "name": "Высокий", + "description": "Приложения с интенсивным трафиком" + } + }, + "custom": { + "name": "Обычай", + "description": "Устанавливайте свои собственные ограничения", + "notSet": "Не установлен" + }, + "customPanel": { + "boundedBy": "На этом компьютере установлены {cpu} vCPU и {memory}. Введите 0, если количество не ограничено.", + "capacityUnknown": "Не удалось определить емкость устройства, поэтому ограничение не установлено. Введите 0, чтобы указать, что ограничений нет.", + "cpuCores": "Процессорные ядра", + "memory": "Объем оперативной памяти (МБ)", + "zeroMeansNoLimit": "0 = без ограничений", + "cancel": "Отменить", + "saving": "Экономия…", + "save": "Сохранить" + }, + "toast": { + "updated": "Обновлена мощность машины", + "updateFailed": "Не удалось обновить питание компьютера", + "invalidValues": "Значения процессора и памяти должны быть равны 0 или положительному числу" + } + }, + "sleep": { + "title": "Режим работы машины", + "description": "Доступность управления и экономическая эффективность", + "autoSleep": "Автоматический режим сна", + "recommended": "рекомендуемый", + "autoSleepDesc": "Останавливается в режиме ожидания, мгновенно просыпается", + "autoSleepMeta": "Экономичный • Отсутствие холодного пуска", + "alwaysOn": "Всегда включен", + "alwaysOnDesc": "Контейнер никогда не останавливается", + "alwaysOnMeta": "Максимальная доступность • Более высокая стоимость", + "infoTitle": "Как работает автоматический режим сна", + "infoBefore": "При поступлении запросов ваш контейнер продолжает работать. После завершения бездействия он переходит в режим ожидания для экономии средств. При следующем запросе он активируется ", + "infoEmphasis": "немедленно", + "infoAfter": " - отсутствие задержек при холодном запуске.", + "toast": { + "updated": "Успешно обновлен спящий режим", + "updateFailed": "Не удалось обновить спящий режим" + } + }, + "deleteDialog": { + "title": "Удалить проект", + "bodyPrefix": "Вы уверены, что хотите удалить ", + "bodySuffix": "? Это действие невозможно отменить, и все данные проекта, развертывания и настройки будут безвозвратно удалены.", + "cancel": "Отменить", + "delete": "Удалить проект" + }, + "deletion": { + "title": "Удалить проект", + "cannotUndo": "Это действие не может быть отменено.", + "aboutToPrefix": "Вы собираетесь удалить ", + "aboutToSuffix": ".", + "deleteAllAria": "Удалить все среды", + "deleteAll": "Удалить все среды", + "deleteAllOn": "Удаляет приложение project и все дочерние среды под ним.", + "deleteAllOff": "Удаляет только эту среду. Остальные ветки остаются.", + "scanning": "Сканирование подключенных служб и томов…", + "wipeAria": "Также удалите служебные данные", + "wipeLabelOne": "Также удалите служебные данные (том {count})", + "wipeLabelOther": "Также стирайте служебные данные (тома {count})", + "wipeOn": "Тома будут удалены безвозвратно - содержимое базы данных, кэши, загрузки - все, что хранится в этих сервисах, исчезнет.", + "wipeOff": "Выключено: контейнеры удаляются, но их именованные тома остаются на диске. Позже присоедините их снова по имени.", + "appData": "Данные приложения", + "volOne": "{count} объем", + "volOther": "{count} тома", + "amberWipe": "Все развертывания, домены, переменные окружения и постоянные служебные данные будут удалены безвозвратно.", + "amberNoWipe": "Все развертывания, домены, переменные окружения и аналитика будут удалены безвозвратно.", + "typePrefix": "Тип ", + "typeSuffix": " подтверждать.", + "cancel": "Отменить", + "confirmDeleteWipe": "Удаление + стирание данных", + "confirmDeleteEnvWipe": "Удалить среду + стереть данные", + "confirmDelete": "Удалить проект", + "confirmDeleteEnv": "Удалить среду", + "recordOnlyLabel": "Удалить только из Openship", + "recordOnlyDesc": "Приложение и его данные продолжают работать на вашем сервере — удаляется только запись Openship. Вы можете повторно импортировать ее позже.", + "recordOnlyReversible": "Обратимый — приложение остается на вашем сервере.", + "recordOnlyNote": "Ничего на сервере не трогается — приложение продолжает работать со своими данными. Удаляется только запись Openship, которую позже можно будет повторно импортировать.", + "confirmRecordOnly": "Удалить запись", + "linkedTitleOne": "Проект {count} подключен к этому приложению", + "linkedTitleOther": "Проекты {count} подключены к этому приложению", + "linkedNote": "Они продолжают работать без изменения своих данных — они только теряют это соединение. Повторно разверните их, чтобы восстановить это.", + "linkedNoteRecordOnly": "Они продолжают работать, но ссылка сохраняется вместе с записью — повторный импорт этого приложения позже не восстановит его." + }, + "routing": { + "title": "Маршрутизация", + "description": "Перезаписывает, перенаправляет и удаляет заголовки. Применяется при сохранении — без перестроения.", + "saving": "Экономия…", + "save": "Сохранить", + "summaryNone": "Ничего не настроено", + "summaryActive": "Сконфигурированный", + "toast": { + "title": "Маршрутизация", + "updated": "Обновлен маршрут — применен к оперативному развертыванию.", + "failed": "Не удалось обновить маршрутизацию" + } + }, + "domains": { + "status": { + "verified": "Проверенный", + "active": "Активный", + "failed": "Неудачный", + "removing": "Удаление", + "pending": "Ожидаемый" + }, + "ssl": { + "includedByHost": "Включено хостом", + "active": "Активный", + "provisioning": "Обеспечение", + "expired": "Истекший", + "error": "Ошибка", + "inactive": "Неактивный", + "external": "Внешний протокол TLS", + "manual": "Ручной сертификат" + }, + "typeCustom": "Пользовательский домен", + "typeFree": "Свободный поддомен", + "primaryDomainTitle": "Основной домен", + "domainNTitle": "Домен {n}", + "portLabel": "Порт {port}", + "noPortSelected": "Порт не выбран", + "meta": { + "accessTitle": "URL-адрес доступа", + "accessSubtitle": "Конечная точка локального развития", + "local": "Местный", + "availableOnMachine": "Доступно на этом компьютере", + "primaryTitle": "Основной домен", + "primaryAcross": "Основной маршрут между доменами {count}", + "hostManaged": "URL-адрес рабочей среды, управляемой хостом", + "customProduction": "Пользовательский производственный домен" + }, + "route": { + "disabled": "Нетрудоспособный", + "routePaused": "Маршрут приостановлен", + "serviceDisabled": "Услуга отключена", + "internal": "Внутренний", + "notExposed": "Не подвергался воздействию", + "public": "Общественный" + }, + "actions": { + "visit": "Посещать", + "editDomains": "Редактировать домены", + "hideSetup": "Скрыть настройки", + "addDomain": "Добавить домен" + }, + "add": { + "title": "Добавить домен", + "description": "Добавьте маршрут: выберите бесплатный или пользовательский домен и порт, к которому он привязан.", + "free": "Свободный поддомен", + "custom": "Пользовательский домен", + "domainName": "Доменное имя", + "subdomain": "Поддомен", + "customPlaceholder": "yourdomain.com", + "defaultAppName": "мое приложение", + "mapsToPort": "Карты до порта", + "servesPath": "Служит путем", + "servesPathHint": "Запросы к этому домену обрабатываются по этому пути в выходных данных вашей сборки.", + "servesPathRedeploy": "Новые пути вступят в силу при следующем развертывании.", + "includeWww": "Включать www", + "includeWwwDesc": "Также создавайте записи для www.{domain}", + "includeWwwFallback": "yourdomain.com", + "externalIngress": "Внешний вход и TLS", + "externalIngressDesc": "TLS завершает работу в восходящем потоке (туннель Cloudflare, балансировщик нагрузки). Проверка только с помощью TXT — домен не обязательно должен указывать на этот сервер, и мы не будем выдавать сертификат.", + "noWww": "Этот домен уже есть в этом проекте.", + "adding": "Добавление...", + "submit": "Добавить домен" + }, + "dns": { + "title": "Записи DNS", + "descPreview": "Добавьте эти записи к своему поставщику DNS, затем нажмите Добавить домен, чтобы прикрепить его", + "descApply": "Примените эти записи к своему DNS-провайдеру, затем дождитесь распространения", + "infoPreview": "Сначала добавьте эти записи — они не изменяются после добавления, поэтому распространение начинается сейчас. Затем нажмите \"Добавить домен\", чтобы прикрепить его, и, наконец, проверьте, как только DNS разрешится.", + "infoApply": "Для распространения изменений DNS по всему миру может потребоваться до 48 часов. Как только записи будут исправлены, нажмите кнопку Подтвердить ниже — мы проверим DNS, пометим домен активным и предоставим SSL в фоновом режиме.", + "verifying": "Подтверждающий...", + "verify": "Проверьте {hostname}" + }, + "records": { + "toggle": "Записи DNS", + "hint": "Добавьте их у своего DNS-провайдера, затем нажмите кнопку Подтвердить.", + "loading": "Загрузка записей…", + "none": "Нет записей для добавления в этот домен." + }, + "verifyMissing": { + "both": "Ни запись CNAME, ни запись TXT пока не разрешаются — добавьте записи ниже, дождитесь распространения DNS, а затем проверьте.", + "cname": "Запись CNAME еще не разрешена — добавьте ее ниже, дождитесь распространения DNS, а затем проверьте.", + "txt": "Запись проверки TXT еще не разрешена — добавьте ее ниже, дождитесь распространения DNS, затем проверьте." + }, + "portHint": { + "body": "На порт {port} ничего не отвечало — запросы могут быть 502, пока приложение не прослушает их.", + "bodyService": "Служба \"{service}\": ничего не отвечает на порт {port} — запросы могут быть 502, пока он не прослушает их там." + }, + "outputHint": { + "body": "Выходные данные сборки не найдены в {path} — проверьте свой выходной каталог и повторно разверните." + }, + "overview": { + "primary": "Первичный", + "mappedTo": "Сопоставленный с", + "redirect": "Перенаправлять", + "redirectValue": "{status} → {hostname}", + "status": "Статус", + "ssl": "Протокол SSL", + "visit": "Посещать" + }, + "cold": { + "localUrl": "Локальный URL-адрес", + "type": "Тип", + "status": "Статус" + }, + "edit": { + "title": "Редактировать домены", + "descServer": "Измените, на какой внутренний порт должен быть направлен маршрут для каждого домена.", + "descStatic": "Измените, какой статический путь должен обслуживать каждый домен.", + "cancel": "Отменить", + "saving": "Экономия...", + "save": "Сохранить изменения" + }, + "addRoute": { + "cancel": "Отменить", + "add": "Добавить маршрут", + "free": "Свободный поддомен", + "custom": "Пользовательский домен", + "customPlaceholder": "app.example.com", + "defaultServiceName": "мой-сервис", + "port": "Порт", + "portPlaceholder": "8080", + "submit": "Добавь", + "loading": "Маршруты погрузки...", + "emptyPrefix": "Доменов пока нет. Щелчок ", + "emptyAction": "Добавить маршрут", + "emptySuffix": " чтобы указать домен на порт службы." + }, + "editRoute": { + "title": "Редактировать маршрут", + "internalOnly": "Только внутренний", + "close": "Закрывать", + "disabledWarning": "Услуга отключена - маршруты неактивны до тех пор, пока услуга не будет снова включена.", + "save": "Сохранить изменения" + }, + "menu": { + "editRoute": "Редактировать маршрут", + "settingPrimary": "Настройка первична...", + "setPrimary": "Установлен в качестве основного", + "verifying": "Подтверждающий...", + "verify": "Проверить", + "renewing": "Обновляющийся...", + "renewSsl": "Обновить протокол SSL", + "rechecking": "Перепроверяю...", + "recheckSsl": "Перепроверьте протокол SSL", + "uploadCert": "Загрузить сертификат" + }, + "certUpload": { + "title": "Загрузить сертификат", + "desc": "Предоставляйте TLS из вашего собственного сертификата (bring-your-own или Cloudflare Origin CA) вместо Let's Encrypt. Используйте это, когда вышестоящий прокси подключен к этому домену, а origin по-прежнему нуждается в реальном сертификате (Cloudflare Full-strict). Certbot отключается для этого домена после загрузки сертификата — обновите его, загрузив новый.", + "certLabel": "Сертификат (fullchain PEM)", + "certPlaceholder": "-----СЕРТИФИКАТ НАЧАЛА РАБОТЫ-----", + "keyLabel": "Закрытый ключ (PEM)", + "keyPlaceholder": "-----ЗАПУСК ЗАКРЫТОГО КЛЮЧА-----", + "submit": "Установить сертификат", + "submitting": "Установка...", + "close": "Отменить" + }, + "toast": { + "enterPort": "Введите порт, на который должен быть перенаправлен этот домен (1-65535).", + "addDomainTitle": "Добавить домен", + "addDomainFailed": "Не удалось добавить домен", + "addDomainFailedTitle": "Не удалось добавить домен", + "addedCustom": "Добавлен {label} — примените записи DNS, затем проверьте.", + "addedFree": "Добавлен {label}.", + "copied": "Скопировано в буфер обмена", + "verifiedSuccess": "{hostname} подтвержден — SSL запускается в фоновом режиме.", + "verifiedTitle": "Подтвержденный домен", + "verifyNotYet": "{hostname} еще не удалось проверить.", + "verifyFailedTitle": "Не удалось выполнить проверку", + "verifyFailed": "Не удалось подтвердить домен.", + "sslRenewed": "Протокол SSL обновлен для {hostname}.", + "sslRenewFailed": "Не удалось обновить SSL для {hostname}.", + "sslTitle": "Протокол SSL", + "sslVerified": "SSL подтвержден для {hostname}.", + "sslNoCert": "Пока не найден действительный сертификат для {hostname}. Если вы только что запустили программу, дайте Let's Encrypt время, а затем перепроверьте.", + "sslRecheckFailed": "Не удалось перепроверить SSL для {hostname}.", + "certUploaded": "Сертификат установлен для {hostname}.", + "certUploadFailed": "Не удалось установить сертификат для {hostname}.", + "completeEndpoints": "Заполните все домены и подключенные порты перед сохранением", + "domainsTitle": "Домены", + "routingUpdated": "Обновлена маршрутизация домена", + "routingUpdateFailed": "Не удалось обновить маршрутизацию домена", + "primaryUpdated": "Обновлен основной домен", + "setPrimaryFailed": "Не удалось установить основной домен", + "routeUpdateFailed": "Не удалось обновить сервисный маршрут", + "publishing": "Публикация — развертывание для установки edge и применения вашего домена…", + "publishFailed": "Домен сохранен, но развертывание не началось — выполните повторное развертывание, чтобы опубликовать его.", + "enterPortShort": "Введите порт, на который должен быть перенаправлен этот домен.", + "noServicePort": "Ни одна служба не публикует порт {port}. Сначала добавьте этот порт в службу.", + "enterCustom": "Введите пользовательский домен.", + "enterSubdomain": "Введите поддомен." + }, + "edge": { + "setUp": "Настроить кромку", + "ready": "Кромка готова", + "checking": "Проверяющий край…", + "recheck": "Повторная проверка", + "foreignProxyHint": "Другой прокси-сервер содержит 80/443" + }, + "diagnosis": { + "title": "Почему это не работает", + "noneYet": "Проверка еще не проводилась, поэтому результат не отображается. Добавьте записи DNS, отображаемые для этого домена, затем запустите проверку.", + "attempts": "{count} до сих пор не удалось выполнить попытку(ы).", + "pillHint": "Покажите, почему" + } + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/projects.json b/apps/dashboard/src/i18n/locales/ru/projects.json new file mode 100644 index 000000000..b2c0383f5 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/projects.json @@ -0,0 +1,514 @@ +{ + "list": { + "loading": "Загрузка...", + "countOne": "Проект {count}", + "countOther": "Проекты {count}", + "noTargetProjects": "Пока нет проектов, направленных на достижение этой цели.", + "noTargetDesc": "Разверните приложение для этой цели или создайте новый проект, чтобы приступить к работе." + }, + "status": { + "live": "Жить", + "paused": "Остановился", + "attention": "Необходимые действия", + "queued": "Поставленный в очередь", + "building": "Здание", + "deploying": "Развертывание", + "failed": "Неудачный", + "cancelled": "Отмененный", + "deleting": "Удаление", + "draft": "Проект" + }, + "serverCta": { + "title": "Развертывание на вашем собственном сервере", + "description": "Подключите сервер по SSH для запуска проектов в вашей собственной инфраструктуре вместе с Openship Cloud.", + "button": "Подключение сервера" + }, + "filters": { + "title": "Фильтровать по целевому объекту", + "subtitle": "Где развертываются проекты", + "allProjects": "Все проекты", + "cloud": "Облако Openship", + "local": "Местный" + }, + "card": { + "liveVersion": "Оперативная версия v{version}", + "appBadge": "Апп", + "sourceLocal": "Местный", + "services": "Услуги", + "static": "Статический", + "standalone": "Автономный", + "worker": "Работник", + "updateAvailable": "Обновление" + }, + "hosting": { + "cloud": "Облако", + "server": "Сервер", + "local": "Местный" + }, + "time": { + "justNow": "прямо сейчас", + "minutesAgo": "{count}м назад", + "hoursAgo": "{count}h назад", + "daysAgo": "{count} назад", + "monthsAgo": "{count}mo назад" + }, + "deploymentCard": { + "visit": "Посещать" + }, + "env": { + "productionFallback": "Производство", + "switchAria": "Переключение среды", + "addBranchAria": "Добавить ветку", + "searchBranches": "Поиск ветвей", + "noBranches": "Ответвлений не найдено", + "environmentName": "Название среды", + "branchLabel": "Метка филиала", + "cancel": "Отменить", + "create": "Создавать", + "manualEnvironment": "Ручная среда", + "toastBranchesTitle": "Ветви", + "toastEnvironmentTitle": "Окружающая среда", + "failedLoadBranches": "Не удалось загрузить ветки", + "failedCreateEnvironment": "Не удалось создать среду" + }, + "detail": { + "breadcrumbDashboard": "Приборная панель", + "projectFallback": "Проект", + "overviewFallback": "Обзор" + }, + "help": { + "contactSupport": "Обратитесь в службу поддержки", + "reportIssue": "Сообщить о проблеме", + "sendFeedback": "отправить отзыв", + "documentation": "Документация", + "joinCommunity": "Присоединяйтесь к сообществу" + }, + "delete": { + "successProject": "Проект успешно удален", + "successEnvironment": "Среда успешно удалена", + "orphanCleanup": "Проект удален. {count} Удаленные ресурсы будут очищены, когда сервер станет доступен.", + "orphanCleanupTitle": "Удалено (ожидается очистка)", + "partialCleanup": "Проект удален, но не удалось выполнить шаг(ы) очистки {count}. Операторам необходимо будет проверить.", + "partialCleanupTitle": "Частичная очистка", + "failed": "Не удалось удалить проект", + "cancellingActiveWork": "Отмена активной работы, затем удаление…", + "cleaningUpTitle": "Уборка", + "hasActiveWork": "Проект активно работает — попробуйте еще раз через мгновение", + "cannotDeleteTitle": "Невозможно удалить", + "deletionInProgress": "Для этого проекта уже запущено другое удаление", + "deletionInProgressTitle": "Выполняется удаление", + "confirmForceOrphan": "Некоторые ресурсы не удалось удалить с сервера. Все равно удалите проект, а позже автоматически очистите их?", + "teardownFailedAt": "Ошибка удаления: {reasons}. Повторите попытку или выполните принудительное удаление, чтобы удалить их.", + "teardownFailed": "Демонтаж не удался", + "cleanupFailedTitle": "Не удалось выполнить очистку", + "alreadyDeleted": "Проект уже удален", + "forceModalTitle": "Не удалось удалить его из источника", + "forceModalBody": "Время выполнения не было достигнуто (или продолжался сбой), поэтому этот проект не был остановлен. Вы все равно можете удалить его из Openship — запись будет удалена, а все оставшиеся ресурсы будут восстановлены автоматически, как только сервер станет доступен.", + "forceModalConfirm": "Удалить из хранилища", + "forceModalCancel": "Отменить", + "unlinked": "Отсоединены от {projects} — повторно разверните их, чтобы применить.", + "unlinkedTitle": "Обновлены подключенные проекты" + }, + "connections": { + "useInProject": "Использование в проекте", + "title": "Использование в проекте", + "subtitle": "Подключите эту базу данных к другому проекту в качестве готового соединения.", + "targetLabel": "Проект", + "targetPlaceholder": "Выберите проект…", + "valueLabel": "Значение для ввода", + "valuesLabel": "Значения для ввода", + "connectedN": "Преобразуйте значения {count} в {project} — повторно разверните для применения.", + "modeInternal": "Внутренний (рекомендуется)", + "modeInternalDesc": "Доступ к нему осуществляется частным образом через общую сеть — без общедоступного порта. Тот же автономный сервер.", + "modePublic": "Общественный", + "modePublicDesc": "Используйте опубликованный порт host:. Работает где угодно; требуется открыть порт базы данных.", + "envKeyLabel": "Переменная среды", + "redeployHint": "Применяется при следующем развертывании объекта.", + "cancel": "Отменить", + "connect": "Подключить", + "connected": "Подключено — повторно разверните целевой объект для применения.", + "failed": "Не удалось подключить услугу.", + "cardTitle": "Подключенные сервисы", + "removed": "Подключение удалено — повторное развертывание для применения.", + "remove": "Удалять", + "modeInternalShort": "Внутренний", + "modePublicShort": "Общественный", + "guideIntroFallback": "Ваш проект получает это соединение, готовое к использованию.", + "whatYouGet": "Что получает ваше приложение", + "advancedValues": "Передовой", + "copy": "Копировать", + "copied": "Скопированный", + "reveal": "Раскрыть", + "hide": "Скрыть", + "openLocalhost": "Открыть на локальном хостинге", + "forwardLocalhost": "Переслать на локальный хост", + "openShort": "Открыть", + "openUrl": "Открыть в новой вкладке", + "forwardShort": "Вперед", + "usedByTitle": "Используется", + "usedByHint": "Проекты {count} зависят от подключения к этому приложению. Отключите связь с используемым проектом.", + "usedByOpen": "Открытый проект", + "linkedCountOne": "Приложение, связанное с {count}", + "linkedCountOther": "Связанные приложения {count}", + "linkedHint": "Работать против этого проекта, а не под его руководством.", + "linkedBadge": "Связанный", + "unlink": "Разъединить", + "openApp": "Открыть приложение", + "internalTitle": "Внутренний адрес", + "internalDescription": "Доступ к этому проекту осуществляется частным образом из другой службы на том же сервере — без общедоступного порта." + }, + "sidebar": { + "project": "Проект", + "untitledProject": "Проект без названия", + "openAria": "Открыть {name}", + "openProjectFallback": "проект", + "open": "Открыть", + "local": "Местный", + "production": "Производство", + "lastDeploy": "Последнее развертывание", + "noDomain": "Нет домена", + "addDomain": "Добавить домен", + "tabs": { + "appSettings": "Настройки", + "overview": "Обзор", + "services": "Приложения и сервисы", + "domains": "Домены и маршруты", + "deployments": "Развертывания", + "health": "Здоровье", + "monitoring": "Мониторинг", + "source": "Источник", + "webhooks": "Веб-крючки", + "runtime": "Конфигурация", + "logs": "Бревна", + "backup": "Резервная копия", + "advanced": "Передовой" + } + }, + "notFound": { + "title": "Проект не найден", + "subtitle": "Мы не смогли найти этот проект", + "bodyPrefix": "Проект", + "bodySuffix": "не существует в вашем рабочем пространстве.", + "reasonDeleted": "Возможно, проект был удален", + "reasonAccess": "Возможно, у вас нет доступа к этому проекту", + "reasonUrl": "Возможно, указан неверный URL-адрес домена", + "dashboard": "Приборная панель", + "reload": "Перезагрузить", + "needHelp": "Нужна помощь?", + "documentation": "Документация", + "support": "Поддержка" + }, + "draft": { + "headingFailed": "Последнее развертывание не завершилось", + "headingCancelled": "Развертывание было отменено", + "headingReady": "Готов к развертыванию", + "subtextDraft": "Этот проект еще не был развернут. Разверните его, чтобы получить текущий URL-адрес, журналы и аналитику.", + "subtextOther": "Этот проект еще не запущен в реальном времени. Просмотрите исходный код и повторите попытку.", + "deployNow": "Развернуть сейчас", + "connectSource": "Подключите источник", + "settings": "Параметры развертывания", + "detailsTitle": "Подробности", + "detailsDescription": "Что использует этот проект и где", + "type": "Тип", + "typeApp": "Апп", + "typeProject": "Проект", + "target": "Цель", + "targetPending": "Выбранный при развертывании", + "services": "Услуги", + "created": "Созданный", + "attemptsTitle": "Попытки развертывания", + "attemptsDescription": "Каждая сборка для этого проекта — нажмите на одну из них, чтобы открыть ее", + "sourceTitle": "Источник", + "sourceDescription": "Откуда берется этот проект", + "repository": "Хранилище", + "branch": "Ветка", + "localPath": "Локальный путь", + "framework": "Рамки", + "build": "Строить", + "noSourceText": "Источник пока не подключен.", + "connectLink": "Подключите репозиторий или локальный путь", + "managedImages": "Управляемые образы контейнеров", + "managedImagesText": "Это приложение работает на основе готовых образов — для подключения нет репозитория. Просто разверните.", + "deleteTitle": "Удалить проект", + "deleteDescription": "Удалите этот проект — его невозможно отменить", + "deleteConfirmPrefix": "Безвозвратно удалить", + "deleteConfirmSuffix": "?", + "cancel": "Отменить", + "delete": "Удалить" + }, + "overview": { + "platformCloud": "Облако Openship", + "platformServer": "Автономный хостинг (сервер)", + "platformLocal": "Автономный хостинг (локальный)", + "modeStatic": "Статичный сайт", + "modeStandalone": "Автономный", + "modeServer": "Сервер", + "modeWorker": "Работник", + "infrastructure": "Инфраструктура", + "platform": "Платформа", + "mode": "Режим", + "port": "Порт", + "sourceCicd": "Источник и CI/CD", + "repository": "Хранилище", + "notConnected": "Не подключен", + "branch": "Ветка", + "autoDeploy": "Автоматическое развертывание", + "webhook": "Веб-крючок", + "traffic": "Движение", + "noTrafficData": "Данных о дорожном движении пока нет", + "services": "Услуги", + "noServicesConnected": "Услуги не подключены", + "manage": "Управлять", + "topPaths": "Верхние пути", + "requestCount": "{count} запрос", + "statusActive": "Активный", + "statusOff": "Прочь", + "server": "Сервер" + }, + "stats": { + "serverRequests": "Запросы к серверу", + "uniqueIPs": "Уникальные IP-адреса", + "avgResponse": "Средний отклик", + "bandwidthOut": "Пропускная способность отсутствует", + "bandwidth": "Пропускная способность", + "requestsSubtext": "{total} всего, {avg} в среднем в час", + "uniqueIPsSubtext": "{pct}% от общего числа", + "responseTime": "Время отклика", + "bandwidthInSubtext": "{value} в", + "loading": "Загрузка...", + "noTraffic": "Движения пока не зафиксировано", + "noVisitors": "Посетителей пока нет", + "waitingRequests": "Ожидание запросов", + "noTransfer": "Перевода пока нет" + }, + "monitoring": { + "noDataTitle": "Данных мониторинга пока нет", + "noDataDescription": "Аналитика появится здесь после того, как развернутое приложение начнет получать трафик.", + "resourcesTitle": "Использование ресурсов", + "resourcesSubtitle": "Живой, обновляемый каждые несколько секунд", + "cpu": "ЦП", + "memory": "Память", + "network": "Сеть", + "diskIo": "Дисковый ввод-вывод", + "ofCores": "из ядер {cores}", + "ofMemory": "из {total}", + "servicesTitle": "Услуги", + "scrollServicesLeft": "Прокрутите службы влево", + "scrollServicesRight": "Прокрутите службы вправо", + "unsupportedTitle": "Использование ресурсов недоступно", + "reconnect": "Повторно подключиться", + "live": "Жить", + "offline": "Разъединенный", + "visitorsTitle": "Посетители в разбивке по странам", + "visitorsSubtitle": "Запросы {total} из стран {countries}", + "visitors": "Посетители", + "approximate": "приблизительный", + "geoUnavailableTitle": "Данные по странам, недоступные в этом регионе", + "geoUnavailableBody": "Пограничный прокси-сервер не может определить страны посещения, поэтому карта остается пустой. На итоговые показатели трафика это не влияет.", + "noCountries": "Данных по странам за этот период пока нет.", + "statusesTitle": "Ответы", + "share": "{pct} ХVARX%", + "visitorDays": "Дни посещения", + "peakDayTooltip": "Самый загруженный день за один день: {peak}. Число возвращающихся посетителей засчитывается один раз в день, поэтому общее количество - это верхняя граница.", + "historyTitle": "Использование с течением времени", + "historyEmptyTitle": "Истории использования пока нет", + "historyEmpty": "Данные о процессоре и памяти проверяются каждые несколько минут — первые точки появляются здесь вскоре после запуска вашего приложения.", + "historyWaiting": "В ожидании первого образца", + "allServices": "Все услуги", + "requests": "запросы", + "moreCountries": "+{count} больше стран", + "previewSample": "Предварительный просмотр с примерами данных", + "previewActive": "Выборочные данные — ненастоящие", + "previewExit": "Выход из предварительного просмотра", + "colorTheme": "Тема", + "colorFlag": "Флаги", + "tooltipRequests": "Запросы {count} · {pct}%", + "allDomains": "Все домены", + "domainScope": "Область действия домена", + "liveHits": "Жить", + "liveHitsHint": "Анимируйте каждый входящий запрос на карте из того же потока, который отображается на вкладке \"Журналы\".", + "liveHitsWaiting": "Ожидание запросов…", + "statusesUnclassified": "{count} без класса состояния", + "trafficTitle": "Обзор трафика", + "trafficSummary": "Запросы {count}", + "servicesMore": "+{count} еще", + "servicesLess": "Показывать меньше", + "pathsOff": { + "title": "Верхние пути отключены", + "desc": "Подсчет количества путей - это единственный показатель, который не является бесплатным, он составляет примерно {share} от объема работы, выполняемой edge при каждом запросе. Все остальное на этой вкладке собирается бесплатно.", + "cta": "Включить верхние пути", + "enabling": "Позволяющий…", + "disable": "Отключите верхние пути" + }, + "liveFeed": "Последние хиты", + "liveFeedHint": "Отобразите список последних посещений на карте (на вкладке \"Журналы\" представлена полная информация)." + }, + "services": { + "failedLoad": "Не удалось загрузить службы", + "retry": "Повторить попытку", + "refresh": "Освежить", + "addService": "Добавь", + "allServices": "Все", + "countOne": "{count} Приложение / сервис", + "countOther": "{count} Приложения и сервисы", + "chooseService": "Выберите один из них, чтобы открыть его полный экран настроек.", + "emptyTitle": "Пока нет приложений или служб", + "emptyDescription": "Добавьте базу данных, кэш или любой другой образ контейнера для запуска вместе с вашим проектом. Выберите из каталога или вставьте любой образ Docker.", + "driftCountOne": "Служба {count} изменена в репозитории", + "driftCountOther": "Службы {count} изменились в репозитории", + "driftDescription": "В настройках репозитория-compose изменены значения, которые вы редактировали здесь. Ваши правки по-прежнему актуальны — для каждого из них сохраните свои или воспользуйтесь репозиториями.", + "keepMine": "Сохрани мой", + "acceptUpstream": "Принять восходящий поток", + "public": "Общественный", + "internal": "Внутренний", + "upstreamChange": "Изменение восходящего потока", + "port": "порт {port}", + "toastServiceTitle": "Услуга", + "toastAddedDeploying": "Добавлен {name} - развертывание…", + "toastStarting": "{name} запускается", + "toastSavedDeploy": "{name} сохранен - разверните проект, чтобы запустить его", + "toastDeployFailed": "Не удалось выполнить развертывание", + "toastAppliedRepo": "{name}: примененные изменения в репозитории", + "toastKeptEdits": "{name}: сохранил ваши правки", + "failedResolveDrift": "Не удалось устранить дрейф", + "failedCreateService": "Не удалось создать службу", + "requestFailed": "Запрос не выполнен" + }, + "serviceStatus": { + "running": "Бегущий", + "stopped": "Остановился", + "disabled": "Нетрудоспособный", + "failed": "Неудачный", + "starting": "Начало", + "restarting": "Повторный запуск", + "unknown": "Неизвестный" + }, + "routingRetry": { + "title": "Бесплатная маршрутизация домена требует особого внимания", + "description": "Приложение доступно на сервере, но оно бесплатное.opsh.io URL-адрес не прошел через облачный интерфейс Openship. Повторите попытку, как только сервер будет доступен из облака через порт 80.", + "retry": "Повторите попытку маршрутизации", + "retrying": "Повторная попытка…", + "success": "Синхронизирована бесплатная маршрутизация домена.", + "failed": "Не удалось синхронизировать маршрутизацию бесплатного домена." + }, + "deployBlocked": { + "redeploy": "Повторно развернуть" + }, + "redeploy": { + "deployStartedLong": "Начато развертывание — открытие развертываний занимает больше времени, чем обычно.", + "deployingTitle": "Развертывание", + "couldNotRefresh": "Не удалось обновить развертывание. Проверьте журнал развертывания для получения подробной информации.", + "couldNotRedeploy": "Не удалось запустить повторное развертывание. Проверьте журнал развертывания для получения подробной информации.", + "errorTitle": "Ошибка", + "failedRedeploy": "Не удалось начать повторное развертывание", + "actionRequiredTitle": "Требуется действие — сбой в работе некоторых служб", + "actionRequiredDescription": "Последняя версия этого проекта была развернута с отказавшими службами и ожидает, что вы сохраните ее или отклоните.", + "reviewDeployment": "Проверка развертывания", + "newCommitTitle": "Доступна новая фиксация", + "newCommitOn": "на", + "newCommitDeployedOn": "— вы работаете на", + "newVersionTitle": "Доступна новая версия", + "newVersionAvailable": "Доступна более новая версия:", + "newVersionDeployed": "— вы работаете на", + "deployVersion": "Развертывание новой версии", + "deploying": "Развертывание…", + "redeployLatest": "Повторно развернуть последнюю версию", + "deployLatestTitle": "Внедрять последние изменения", + "deployLatestMulti": "Извлекает последнюю фиксацию и перестраивает только те службы, файлы которых изменились с момента последнего развертывания.", + "deployLatestSingle": "Извлекает последнюю фиксацию и повторно развертывает с использованием текущей конфигурации.", + "deployingButton": "Развертывание...", + "redeployProject": "Повторно развернуть проект", + "refreshEnv": "Обновить env", + "rebuildAll": "Перестроить все", + "noPublicDomainTitle": "Общественное достояние не подключено", + "noPublicDomainDescOne": "В этом проекте есть служба {count} с открытыми портами, но ни один из них не настроен на доступный домен. Если вы выполните развертывание сейчас, стек может работать внутри системы, но пользователи не смогут получить к нему доступ с общедоступного URL.", + "noPublicDomainDescOther": "В этом проекте есть службы {count} с открытыми портами, но ни одна из них не настроена на доступный домен. Если вы выполните развертывание сейчас, стек может работать внутри системы, но пользователи не смогут получить к нему доступ с общедоступного URL.", + "openServices": "Открытые сервисы", + "deployAnyway": "Развертывать в любом случае", + "suggestedFix": "Предлагаемое решение", + "fixStep1": "Откройте вкладку \"Службы\".", + "fixStep2": "Выберите сервис, который должен быть общедоступным.", + "fixStep3": "Включите доступ к домену и выберите общедоступный порт." + }, + "incomingWebhooks": { + "title": "Входящие веб-запросы", + "subtitle": "Запускайте развертывание или задание с внешнего URL-адреса. Каждый веб-узел получает свой собственный адрес и свою собственную авторизацию.", + "create": "Новый веб-хук", + "loading": "Загрузка веб-ссылок…", + "empty": "Входящих веб-запросов пока нет. Создайте его, чтобы запускать развертывания или задания с внешнего URL-адреса.", + "deleteConfirm": "Удалите webhook \"{name}\"? Его URL-адрес немедленно перестанет работать.", + "removed": "Веб-хук удален.", + "rotated": "Secret rotated — обновляет вызывающий объект новым значением.", + "created": "Создан веб-узел.", + "failed": "Что-то пошло не так.", + "toggleAria": "Включите или отключите этот веб-узел", + "rotate": "Вращать секрет", + "delete": "Удалить", + "urlLabel": "URL-адрес доставки", + "secretLabel": "Секрет", + "copy": "Копировать", + "copied": "Скопированный", + "reveal": "Раскрыть", + "hide": "Скрыть", + "authBadge": { + "token": "Знак", + "hmac": "HMAC (ВМС)", + "none": "Открыть" + }, + "summaryDeploy": "Повторно развертывает этот проект", + "summaryDeployService": "Повторно развертывает службу {service}", + "summaryJob": "Запускает задание {job}", + "createTitle": "Новый входящий веб-хук", + "createSubtitle": "Выберите, что он делает и как абоненты проходят аутентификацию.", + "nameLabel": "Имя", + "namePlaceholder": "например, крючок для развертывания CI", + "actionLabel": "Действие", + "actionDeploy": "Развертывать", + "actionDeployDesc": "Повторно разверните этот проект (или одну службу) при вызове.", + "actionJob": "Выполнить задание", + "actionJobDesc": "Выполняйте одно из своих заданий, когда вас вызовут.", + "serviceLabel": "Обслуживание (по желанию)", + "serviceAll": "Весь проект в целом", + "jobLabel": "Работа", + "jobPlaceholder": "Выберите задание…", + "authLabel": "Идентификация", + "authToken": "Знак", + "authTokenDesc": "Секретный токен на предъявителя — отправьте его в качестве авторизации: на предъявителя или ?token=.", + "authHmac": "Подпись HMAC", + "authHmacDesc": "Вызывающие абоненты подписывают текст общим секретом (X-Signature-256).", + "authNone": "Открыть", + "authNoneDesc": "Авторизации нет — любой, у кого есть URL-адрес, может запустить его. Используйте с осторожностью.", + "cancel": "Отменить" + }, + "health": { + "title": "Здоровье", + "subtitle": "В рамках этого проекта организация Health watch зафиксировала неисправности контейнеров.", + "refresh": "Освежить", + "openTitle": "Открытые инциденты", + "recentTitle": "Последние ({days} дней)", + "emptyOpen": "Никаких открытых инцидентов.", + "emptyRecent": "Никаких инцидентов зафиксировано не было.", + "emptyUnwatched": "Ничего не записывается — часы работоспособности выключены.", + "watchOffTitle": "Индикатор состояния контейнера выключен", + "watchOffBody": "Никакие инциденты не регистрируются, и никакие оповещения не будут отправляться, поэтому пустой список здесь не означает, что все в порядке.", + "watchOffCta": "Включите его в разделе Задания", + "serverDownTitle": "Openship не может связаться с сервером этого проекта", + "serverDownBody": "На этом компьютере ничего не наблюдалось для {duration}, поэтому приведенные ниже инциденты могут быть устаревшими.", + "loadFailed": "Не удалось загрузить инциденты.", + "ongoing": "продолжается работа над {duration}", + "lasted": "длился {duration}", + "started": "запущен {when}", + "recovered": "Восстановленный", + "exitCode": "выйти из {code}", + "restarts": "{count} перезапускается", + "oomKilled": "недостаточно памяти", + "showLog": "Показать выдержку из журнала", + "hideLog": "Скрыть выдержку из журнала", + "kinds": { + "down": "Вниз", + "crash_loop": "Аварийный цикл", + "unhealthy": "Нездоровый", + "server_unreachable": "Сервер недоступен" + } + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/servers.json b/apps/dashboard/src/i18n/locales/ru/servers.json new file mode 100644 index 000000000..286c05a1c --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/servers.json @@ -0,0 +1,511 @@ +{ + "github": { + "title": "Доступ к GitHub", + "desc": "Как этот сервер аутентифицируется на GitHub для клонирования частных репозиториев.", + "loadFailed": "Не удалось загрузить статус на GitHub", + "connected": "Связанный", + "modeToken": "Знак", + "modeSshKey": "SSH-ключ", + "modeDeployKey": "Развертывание ключей", + "connectDevice": "Подключитесь к GitHub", + "deviceHint": "Откройте ссылку и введите этот код:", + "open": "Откройте GitHub", + "connecting": "Ожидание авторизации…", + "connectFailed": "Не удалось установить соединение", + "connectedToast": "GitHub подключен к этому серверу", + "patPlaceholder": "ghp_… (вставьте токен)", + "patHint": "Личный токен доступа, хранящийся в зашифрованном виде для этого сервера.", + "patLabel": "Личный токен доступа", + "or": "или", + "save": "Сохранить", + "savedToast": "Сохраненный", + "saveFailed": "Сохранить не удалось", + "tokenAs": "Аутентифицирован как", + "sshGenerate": "Сгенерировать SSH-ключ", + "sshAddHint": "Добавьте этот ключ в свою учетную запись на GitHub, затем разверните:", + "openGithubKeys": "Откройте SSH-ключи GitHub", + "copy": "Копировать", + "deployKeyUse": "Используйте ключи развертывания для каждого репозитория", + "deployKeyHint": "Openship регистрирует ключ развертывания только для чтения в каждом репозитории при первом развертывании.", + "deployKeyActive": "Режим развертывания-ключ активен — ключи создаются при первом развертывании.", + "deployKeysRegistered": "зарегистрированные ключи развертывания", + "disconnect": "Разъединять", + "disconnectedToast": "GitHub отключен" + }, + "list": { + "title": "Серверы", + "subtitle": "Управляйте своими серверами развертывания и инфраструктурой", + "addServer": "Добавить сервер", + "addRemoteServer": "Добавить удаленный сервер", + "addThisMachine": "Добавьте эту машину", + "addThisMachineError": "Не удалось добавить эту машину в качестве сервера.", + "emptyTitle": "Серверов пока нет", + "emptyDescription": "Подключите сервер по SSH, и Openship позаботится обо всем остальном - Docker, edge, SSL и развертывания будут настроены автоматически.", + "addFirstServer": "Добавьте свой Первый Сервер", + "whatGetsConfigured": "Что будет настроено", + "featContainer": "Среда выполнения контейнера", + "featContainerDesc": "Запускает каждое приложение изолированно", + "featProxy": "Обратный прокси-сервер", + "featProxyDesc": "Маршрутизация и SSL", + "monitoring": "Мониторинг", + "monitoringDesc": "Проверки работоспособности", + "gitDesc": "Исходные развертывания", + "connected": "Связанный", + "error": "Ошибка", + "checking": "Проверка", + "online": "Онлайн", + "offline": "Не в сети", + "authKey": "ключ", + "authPassword": "пароль", + "forwarding": "Переадресация {n}", + "quickInfo": "Краткая информация", + "serverOverview": "Обзор сервера", + "totalServers": "Общее количество серверов", + "connectedLabel": "Связанный", + "errors": "Ошибки", + "seeDocs": "Смотрите документы", + "projects": "Проекты", + "regions": "Регионы", + "thisServer": "Этот сервер", + "currentHost": "Текущий хост", + "projectCountOne": "Проект {n}", + "projectCountMany": "Проекты {n}", + "infra": { + "title": "Компоненты платформы", + "subtitle": "Расширяйте возможности и отправляйте почту по всему вашему автопарку", + "attention": "{n} нуждается во внимании", + "updates": "{n} с обновлениями", + "healthy": "{n} здоровый", + "allHealthy": "Все компоненты находятся в актуальном состоянии", + "updateAll": "Обновить все ({n})", + "restartStopped": "Перезапуск остановлен ({n})", + "scan": "Перепроверьте каждый сервер", + "openServerHint": "Откройте сервер, чтобы завершить их — для этого требуется настройка или ваше согласие.", + "filterAll": "Все", + "filterAttention": "Нуждается во внимании", + "filterUpdates": "Обновления", + "filterHealthy": "Здоровый", + "searchPlaceholder": "Поисковые серверы…", + "noMatches": "Ни один сервер не соответствует этому фильтру.", + "chipEdgeDown": "край вниз", + "chipMailDown": "отправляйте почту вниз", + "chipEdgeMissing": "никакого края", + "chipUpdateOne": "1 обновление", + "chipUpdates": "Обновления {n}", + "started": "Обновление компонентов {n}", + "startedRestart": "Перезапуск компонентов {n}", + "skipped": "{n} нуждаются во внимании на своей странице", + "nothingToDo": "Ничего, что можно было бы применить", + "applyFailed": "Не удалось запустить обновления" + } + }, + "containers": { + "subtitle": "Пограничные и почтовые контейнеры на этом сервере", + "updatesAvailableOne": "доступно 1 обновление", + "updatesAvailableMany": "Доступны обновления {n}", + "scan": "Сканировать", + "scanning": "Сканирующий…", + "componentEdge": "Край", + "componentMail": "Почтовый движок", + "down": "вниз", + "goneEdge": "Контейнер исчез — повторно запустите программу установки, чтобы воссоздать его.", + "goneMail": "Контейнер исчез — повторно запустите программу установки почты, чтобы воссоздать его.", + "legacyEngine": "Устаревшая установка · не упакована в контейнер", + "update": "Обновление", + "updating": "Обновление…", + "fix": "Чинить", + "starting": "Начало…", + "stopped": "Остановился", + "running": "Бегущий", + "upToDate": "До настоящего времени", + "notInstalled": "Не установлен", + "installEdge": "Установить кромку", + "edgeAbsentImpactOne": "Здесь развернут проект {n}, и ничто не направляет к нему трафик.", + "edgeAbsentImpactMany": "Здесь развертываются проекты {n}, трафик к которым никак не маршрутизируется." + }, + "modules": { + "title": "Доступны обновления модулей", + "checkFailedTitle": "Не удалось выполнить проверку обновления модуля", + "needsConfirmation": "нуждается в подтверждении", + "update": "Обновление", + "updating": "Обновление…", + "confirmTitle": "Обновить {module}?", + "confirmIntro": "Это обновление включает в себя изменения, которые требуют вашего одобрения:", + "cancel": "Отменить", + "updateFailed": "Не удалось выполнить обновление {module}" + }, + "tabsNav": { + "servers": "Серверы", + "cluster": "Скопление", + "networking": "Сетевой" + }, + "comingSoon": { + "badge": "Скоро будет", + "clusterTitle": "Кластеры", + "clusterBody": "Объедините серверы в кластер и позвольте Openship планировать и балансировать развертывания на них.", + "networkingTitle": "Сетевой", + "networkingBody": "Частные ссылки, сетевая маршрутизация и правила брандмауэра на всех ваших серверах — все это управляется в одном месте." + }, + "form": { + "sshConnection": "Подключение по SSH", + "sshConnectionDesc": "Подключитесь к вашему серверу по SSH", + "serverName": "Имя сервера", + "serverNamePlaceholder": "например, производство, постановка, разработка...", + "serverNameHelp": "Необязательная метка, отображаемая в списке серверов и заголовке.", + "serverIp": "IP-адрес сервера", + "port": "Порт", + "portPlaceholder": "например, 22", + "username": "Имя пользователя", + "usernamePlaceholder": "например, корень", + "authentication": "Идентификация", + "password": "Пароль", + "sshKey": "SSH-ключ", + "agent": "Агент", + "passwordPlaceholderKeep": "Оставьте поле пустым, чтобы сохранить текущий пароль", + "passwordPlaceholderEnter": "Введите пароль сервера", + "agentInfoBefore": "Подключается с помощью SSH—агента, подобного VSCode, пароль или ключ не требуются. Хост, на котором запущен Openship, уже должен иметь доступ к этому серверу (ключ загружен в его ", + "agentInfoAfter": ").", + "keyModePaste": "Вставить / Загрузить", + "keyModePath": "Путь к хосту", + "keyPath": "Ключевой путь", + "keyPathBrowse": "Просматривать…", + "keyPathHelp": "Абсолютный путь к закрытому ключу на компьютере, на котором запущен Openship.", + "keyPaste": "Закрытый ключ", + "keyPastePlaceholder": "-----ЗАПУСК ЗАКРЫТОГО КЛЮЧА OPENSSH-----\n…", + "keyPasteHelp": "Вставленные ключи шифруются в состоянии покоя и никогда не покидают сервер.", + "keyStoredKeep": "Ключ сохранен — вставьте новый, чтобы заменить его, или оставьте пустым, чтобы сохранить его.", + "keyUploadFile": "Загрузить ключевой файл", + "keyPasteInvalid": "Этот файл не похож на действительный закрытый ключ.", + "passphrase": "Ключевая фраза", + "optional": "(опционально)", + "passphrasePlaceholder": "Введите ключевую фразу или оставьте поле пустым", + "advanced": "Передовой", + "jumpHost": "Ведущий прыжка", + "extraArgs": "Дополнительные аргументы SSH", + "testing": "Тестирование…", + "connected": "Связанный", + "testConnection": "Тестовое подключение", + "saveChanges": "сохранить изменения", + "saveAndContinue": "Сохраните и продолжите настройку", + "modalTitle": "Добавьте свой сервер", + "modalSubtitle": "Подключитесь по SSH. Вы можете завершить настройку позже.", + "saveServer": "Сохранить сервер", + "savingServer": "Экономия…", + "toastIpRequired": "Требуется указать IP-адрес сервера", + "toastPasswordSwitchRequired": "Пароль требуется при переключении на режим аутентификации по паролю", + "toastKeyPathSwitchRequired": "Путь к ключу требуется при переключении на SSH key auth", + "toastKeyRequired": "Требуется закрытый ключ", + "toastUpdated": "Сервер обновлен", + "toastSaved": "Сервер сохранен", + "toastSaveFailed": "Не удалось сохранить сервер", + "toastPasswordTestRequired": "Для проверки подключения требуется пароль", + "toastKeyPathTestRequired": "Для проверки соединения требуется путь к ключу", + "toastConnectionSuccess": "Подключение прошло успешно", + "toastConnectionFailed": "Не удалось установить соединение", + "toastConnectionTestFailed": "Не удалось выполнить проверку подключения" + }, + "detail": { + "tabs": { + "overview": "Обзор", + "migrations": "Миграции", + "components": "Компоненты", + "github": "Автор Git", + "security": "Безопасность", + "ports": "Левый передок", + "terminal": "Терминал" + }, + "healthy": "Здоровый", + "issues": "Проблемы", + "sshPort": "SSH · {port}", + "edit": "Редактировать", + "removeServer": "Удалить сервер", + "serverNotFound": "Сервер не найден", + "serverNotFoundDesc": "Этого сервера нет в вашем рабочем пространстве, или у вас нет к нему доступа. Возможно, он был удален.", + "noServerConfigured": "Ни один сервер не настроен с идентификатором “{id}”.", + "editServer": "Сервер редактирования", + "editSubtitle": "Обновите сведения о подключении для {name}", + "saveChanges": "сохранить изменения", + "connection": "Соединение", + "host": "Хозяин", + "port": "Порт", + "user": "Пользователь", + "auth": "Автор", + "authSshKey": "SSH-ключ", + "authPassword": "Пароль", + "cancel": "Отменить", + "remove": "Удалять", + "removeServerMessage": "Вы уверены? Это приведет к удалению всех учетных данных SSH и настроек подключения.", + "removeComponentTitle": "Удалить {label}", + "removeOpenrestyMessage": "При этом контейнер edge удаляется с сервера. Сертификаты и виртуальные хосты остаются на хосте. Используйте переустановку, когда вам нужно только обновить edge до текущего образа.", + "removeComponentMessage": "Это приведет к удалению {label} с сервера. Это разрушительно и может привести к отключению соответствующих функций развертывания до тех пор, пока вы не установите его снова.", + "reinstallDockerTitle": "Переустановить Docker на этом сервере?", + "reinstallDockerMessage": "При этом запускается официальный установщик Docker, который запускает текущий движок на обновленном сервере, что является серьезным обновлением. Установка или обновление Docker перезапускает демон, и это перезапускает все контейнеры на этом сервере, включая все, что запущено на Openship. Ничто другое не устанавливает Docker за вас: другие шаги пропускают его, пока он работает.", + "removalTakingLonger": "Удаление занимает больше времени, чем ожидалось. Проверьте состояние сервера.", + "removalTimedOutError": "Время удаления истекло - повторно проверьте сервер, чтобы увидеть текущее состояние.", + "toastComponentActionCompleted": "Действие компонента завершено", + "toastSomeActionsFailed": "Не удалось выполнить некоторые действия с компонентами", + "toastHealthCheckFailedAfterInstall": "После установки не удалось выполнить проверку работоспособности", + "toastHealthCheckFailed": "Не удалось выполнить проверку работоспособности", + "toastNoInstallableMissing": "Ни один из устанавливаемых компонентов не отсутствует", + "toastServerMissing": "Сервер отсутствует", + "toastFailedStartInstall": "Не удалось запустить установку", + "toastFailedRun": "Не удалось запустить {label}", + "toastComponentRemoved": "{label} удален", + "toastRemovalTimedOut": "Истечение времени ожидания удаления - повторная проверка состояния сервера", + "toastFailedRemove": "Не удалось удалить {label}", + "toastServerRemoved": "Сервер удален", + "toastFailedRemoveServer": "Не удалось удалить сервер" + }, + "banner": { + "unreachableTitle": "Не удается связаться с {host}", + "unreachableBody": "Openship не удалось установить SSH-соединение с {host}:{port}. Убедитесь, что сервер запущен и что sshd принимает соединения через порт {port}. Если он находится за брандмауэром или NAT, убедитесь, что хост доступен с этого компьютера.", + "authTitle": "Учетные данные SSH отклонены", + "authBody": "Достиг {host}:{port}, но сервер отказал в аутентификации. Ключ или пароль, сохраненный для этого сервера, не соответствует тому, который указан в ~/.ssh/authorized_keys на хосте.", + "noServerTitle": "Неполная конфигурация сервера", + "noServerBody": "В этой записи сервера отсутствуют настройки SSH. Откройте \"Редактировать\", чтобы задать хост, пользователя и учетные данные, затем запустите проверку работоспособности.", + "hostChannelTitle": "Openship не может связаться с хостом этой машины", + "hostChannelBody": "Здесь Openship запускается в контейнере и связывается с хостом по SSH по адресу {target}. Там нет ответа, поэтому он не может запускать операции на уровне хоста в этом окне.", + "hostChannelImpact": "Обычные развертывания в этом окне по—прежнему работают - они выполняются через сокет Docker. Заблокирован до тех пор, пока канал не заработает: выполняется проверка терминала хоста, информации о системе хоста и порта хоста; не запускается управление :80/:443 с прокси-сервера Openship; установка или обновление почтового движка; развертывание приложения каталога, для которого требуется сгенерированный конфигурационный файл на хосте (kong.yml от Supabase, сказать). В этом поле также отображается надпись \"Автономно\" в списке серверов панели мониторинга, когда канал отключен.", + "hostChannelFix": "Запустите это на хосте, затем повторите попытку:", + "hostChannelMissingTitle": "У Openship нет канала к хосту этого компьютера", + "hostChannelMissingBody": "Openship здесь работает в контейнере, и SSH-канал, который он использует для связи с хостом, никогда не был подготовлен. Не было адреса, с которым можно связаться, поэтому здесь ничего не происходит — операции на уровне хоста в этом окне просто некуда запускать.", + "hostChannelWouldUse": "После настройки канал достигнет хоста по адресу {target}. С этим адресом пока ничего не связывалось.", + "hostChannelProvisionFix": "Запустите это на хосте, чтобы подготовить канал, затем повторите попытку:", + "unknownTitle": "Не удалось выполнить проверку работоспособности", + "unknownBody": "Openship не удалось подключиться к этому серверу.", + "checkPowered": "Включен ли VPS / виртуальная машина?", + "pingSuffix": "с этого аппарата - он отвечает?", + "ncSuffix": "- открыт ли порт {port}?", + "checking": "Проверка…", + "retry": "Повторить попытку", + "editCredentials": "Редактировать учетные данные", + "editServer": "Сервер редактирования", + "showRawError": "Показать необработанную ошибку" + }, + "overview": { + "cpu": "ЦП", + "memory": "Память", + "disk": "Диск", + "uptime": "Рабочее время", + "load": "Загрузить {load1} · {load5} · {load15}", + "usageOf": "{used} из {total}", + "sinceLastBoot": "с момента последней загрузки", + "components": "Компоненты", + "checking": "Проверка…", + "allOperational": "Все системы в рабочем состоянии", + "unhealthyOf": "{unhealthy} из {total} нездоровый", + "noData": "Нет данных", + "healthy": "Здоровый", + "unhealthy": "Нездоровый", + "noHealthData": "Пока нет данных о состоянии здоровья" + }, + "components": { + "reinstall": "Переустановить", + "install": "Устанавливать", + "running": "Бегущий...", + "unsupported": "Неподдерживаемый", + "remove": "Удалять", + "systemHealth": "Исправность системы", + "requiredComponents": "Необходимые компоненты и услуги", + "roleDocker": "Среда выполнения контейнера", + "roleGit": "Управление версиями", + "roleOpenresty": "Обратный прокси-сервер", + "roleCertbot": "SSL-сертификаты", + "roleRsync": "Передача файлов", + "installMissing": "Установка отсутствует ({count})", + "allInstalled": "Все установленные", + "installing": "Установка…", + "removing": "Удаление…", + "checking": "Проверка…", + "recheck": "Повторная проверка", + "runningHealthChecks": "Выполнение проверок работоспособности…", + "noHealthData": "Пока нет данных о состоянии здоровья", + "detectedInfrastructure": "Обнаруженная инфраструктура", + "removalComplete": "Удаление завершено", + "removalFinishedErrors": "Удаление завершилось с ошибками", + "installComplete": "Установка завершена", + "installFinishedErrors": "Установка завершена с ошибками", + "removalLogs": "Журналы удаления", + "installLogs": "Установка журналов", + "componentsCount": "Компоненты {completed}/{total}", + "dismiss": "Увольнять", + "statusInstalling": "Установка…", + "statusRemoving": "Удаление…", + "statusInstalled": "Установленный", + "statusRemoved": "Удаленный", + "statusFailed": "Неудачный", + "statusWaiting": "Ожидание" + }, + "ports": { + "title": "Переадресация портов", + "descBefore": "Подобно VS Code: подключитесь к порту удаленного сервера по адресу", + "descAfter": " на этом компьютере. Привязан только к циклической передаче и активен только при пересылке.", + "loading": "Погрузка…", + "noForwards": "Нападающих пока нет.", + "running": "Бегущий", + "stopped": "Остановился", + "stop": "Остановка", + "start": "Начать", + "remove": "Удалять", + "openOnStartup": "Открывается при запуске", + "ariaOpenThisForward": "Откройте эту переадресацию при запуске", + "ariaOpenNewForward": "Открывайте новый форвард при запуске", + "remotePortPlaceholder": "Удаленный порт", + "localPortPlaceholder": "Локальный (автоматический)", + "add": "Добавь", + "toastRemotePortRange": "Удаленный порт должен быть в диапазоне от 1 до 65535", + "toastLocalPortRange": "Локальный порт должен быть равен 0 (автоматически) или 1-65535" + }, + "security": { + "title": "Ограничение скорости", + "subtitle": "Ограничение скорости запросов OpenResty для этого сервера", + "loading": "Загрузка...", + "couldntRead": "Не удалось прочитать конфигурацию ограничения скорости OpenResty", + "retryHint": "Повторите попытку после подтверждения того, что OpenResty установлен и доступен на этом сервере.", + "retry": "Повторить попытку", + "refresh": "Освежить", + "loadedFromLive": "Загружено из конфигурации live OpenResty. Нажмите \"Редактировать\", чтобы изменить его.", + "edit": "Редактировать", + "remove": "Удалять", + "editLiveHint": "Измените лимит скорости live OpenResty для этого сервера.", + "noLimitHint": "Ограничение скорости пока не введено. Для его создания задайте количество запросов в секунду.", + "resetDraft": "Сброс черновика", + "cancel": "Отменить", + "requestsPerSecond": "Запросы / секунда", + "burstAuto": "Пакет рассчитывается автоматически: {burst}", + "burstCustom": "Активировано пользовательское переопределение пакета: {burst}", + "advanced": "Передовой", + "advancedHint": "Переопределите автоматический расчет количества пакетов, если вам нужен более точный контроль.", + "hideAdvanced": "Скрыть расширенный", + "showAdvanced": "Показать продвинутый", + "burstMode": "Режим серийной съемки", + "burstModeHint": "Функция Auto синхронизирует пакет с количеством запросов в секунду. Функция Manual позволяет вам переопределить ее.", + "switchToManual": "Переключитесь на ручное управление", + "useAutomaticBurst": "Используйте автоматическую выборку", + "burstAllowance": "Допуск на разрыв", + "burstAllowanceHint": "Дополнительные запросы ставятся в очередь с помощью nodelay.", + "whitelistedIps": "IP-адреса, внесенные в белый список", + "whitelistHint": "Эти IP-адреса ограничивают скорость обхода. Обратная связь (127.0.0.1, ::1) всегда отображается в белом списке.", + "ipPlaceholder": "например, 145.223.101.50 или 10.0.0.0/8", + "add": "Добавь", + "draftChanges": "Черновик изменений: {summary}", + "noDraftChanges": "Никаких черновых изменений", + "removeRateLimit": "Снять ограничение скорости", + "saveChanges": "Сохранить изменения", + "applyRateLimit": "Применить ограничение по ставке", + "policyBase": "{rps} req/s, пакет {burst}", + "policyWhitelisted": "{base}, {count} занесены в белый список", + "failedReadConfig": "Не удалось прочитать конфигурацию OpenResty", + "toastRateLimitUpdated": "Обновлен лимит ставок: {from} -> {to}", + "toastFailedApply": "Не удалось подать заявку", + "toastFailedSave": "Не удалось сохранить настройки ограничения скорости", + "toastRemoved": "Снято ограничение по ставке", + "toastFailedRemove": "Не удалось снять ограничение скорости", + "toastInvalidIp": "Недопустимый формат IP/CIDR", + "toastAlreadyWhitelisted": "Уже внесен в белый список", + "ports": { + "title": "Воздействие порта", + "subtitle": "Посмотрите, какие порты прослушивания доступны из сети", + "introHint": "Просканируйте каждый порт, который прослушивается на этом компьютере, и отметьте те, которые подключены к общедоступному интерфейсу, а не к loopback.", + "scanButton": "Сканировать порты", + "scanning": "Сканирование прослушивающих портов…", + "rescan": "Повторное сканирование", + "retry": "Повторить попытку", + "scanFailed": "Не удалось просканировать порты", + "scanFailedHint": "Возможно, сервер недоступен. Повторите попытку, как только он снова подключится к сети.", + "summary": "{total} прослушивающие порты · {exposed}, подключенные к сети", + "summaryZeroExposed": "Порты прослушивания {total} · ни один из них не подключен к сети", + "exposed": "Подвергнутый", + "loopback": "Только местный", + "noProcessInfo": "Имена процессов недоступны (ss не установлен на этом хосте).", + "unknownProcess": "Неизвестный процесс", + "empty": "Порты для прослушивания не найдены.", + "inconclusive": "Сканирование не дало результатов", + "inconclusiveHint": "Не удалось прочитать таблицу сокетов на этом хосте. Повторите попытку или проверьте доступ по SSH.", + "reachable": "Достижимый", + "firewalled": "Брандмауэр", + "expectedOpen": "Ожидается, что он будет открыт", + "sensitiveHint": "Не должен быть подключен к Интернету", + "sensitiveReachable": "Конфиденциальный сервис, доступный из Интернета", + "reachableLegend": "“Доступно” было подтверждено при наборе порта из автономного режима; “Защищено брандмауэром” связано, но заблокировано (например, облачным брандмауэром).", + "summaryReachable": "Порты прослушивания {total} · {reachable} доступны из Интернета · {firewalled} заблокирован брандмауэром" + } + }, + "terminal": { + "title": "Терминал", + "description": "Активные оболочки SSH через WebSocket. До 3—х одновременных - копирование при выборе." + }, + "setup": { + "editServer": "Сервер редактирования", + "addServer": "Добавить сервер", + "enterDetails": "Введите данные вашего сервера и выберите способ авторизации", + "gettingStarted": "приступая к работе", + "whatYouNeed": "Что вам нужно", + "needServer": "Сервер с доступом по SSH (Ubuntu, Debian или аналогичный)", + "needAuth": "SSH-ключ или пароль для аутентификации", + "needChecks": "После сохранения Openship выполнит проверку и установит для вас необходимые компоненты, отсутствующие в серверной части.", + "yourServer": "ваш сервер", + "serverSetup": "Настройка сервера", + "subChoose": "Выберите, как вы хотели бы настроить свой сервер", + "subChecking": "Проверка требований к серверу…", + "subResults": "Результаты поиска {host}", + "subInstalling": "Установка компонентов…", + "autoTitle": "Автоматическая настройка", + "autoDesc": "Проверьте требования и установите все автоматически. Один клик - Openship обрабатывает Docker, OpenResty и Git.", + "stepTitle": "Пошаговая настройка", + "stepDesc": "Просмотрите каждый компонент и выберите, что установить. Прежде чем продолжить, ознакомьтесь с подробным статусом.", + "skipTitle": "Пропусти пока", + "skipDesc": "Добавьте сервер, ничего не устанавливая — просто следите за его работоспособностью. Вы можете запустить программу установки позже на странице сервера.", + "connecting": "Подключение к серверу…", + "runningChecks": "Запуск проверки работоспособности системы по SSH", + "connectionFailed": "Не удалось установить соединение", + "installing": "Установка…", + "installationFailed": "Ошибка установки", + "ready": "Готов", + "missing": "Недостающий", + "stepConnect": "Подключить", + "stepCheck": "Проверять", + "stepInstall": "Устанавливать", + "statusInstalling": "Установка…", + "statusDone": "Сделано", + "statusFailed": "Неудачный", + "statusWaiting": "Ожидание", + "overallProgress": "Общий прогресс", + "connectingChecking": "Подключение к {host} и проверка требований…", + "allComponentsInstalled": "Все компоненты установлены", + "setupFinishedErrors": "Настройка завершена с ошибками", + "installingComponents": "Установка компонентов", + "installedOf": "{count} из {total}, установленного на {host}", + "settingUp": "Настройка {host}…", + "allRequirementsMetTitle": "Все требования выполнены", + "allRequirementsMet": "Все требования выполнены", + "readyToDeploy": "{host} готов к развертыванию", + "installLogs": "Установка журналов", + "line": "линия", + "lines": "линии", + "waitingForOutput": "Ожидание вывода…", + "doneGoToServers": "Готово — переходим к серверам", + "goToServers": "Перейти к серверам", + "retryFailed": "Повторная попытка не удалась ({count})", + "setupComplete": "Настройка завершена", + "installAllMissing": "Установите все отсутствующие", + "installMissingComponents": "Установите недостающие компоненты", + "recheck": "Повторная проверка", + "needAttention": "Компоненты {count} требуют особого внимания", + "detectedInfrastructure": "Обнаруженная инфраструктура", + "toastSetupCompleted": "Настройка сервера завершена", + "toastSomeComponentsFailed": "Не удалось установить некоторые компоненты", + "toastSaveBeforeSetup": "Сохраните сервер перед запуском программы установки", + "toastHealthCheckFailed": "Не удалось выполнить проверку работоспособности", + "toastSaveBeforeInstall": "Сохраните сервер перед установкой компонентов", + "toastAlreadyReady": "Сервер уже готов", + "toastFailedStartInstall": "Не удалось запустить установку" + }, + "toastTitles": { + "server": "Сервер", + "serverSetup": "Настройка сервера", + "serverCheck": "Проверка сервера", + "security": "Безопасность", + "portForwarding": "Переадресация портов" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/settings.json b/apps/dashboard/src/i18n/locales/ru/settings.json new file mode 100644 index 000000000..21801ad54 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/settings.json @@ -0,0 +1,1020 @@ +{ + "language": { + "title": "Язык", + "description": "Выберите язык, используемый на панели мониторинга." + }, + "productView": { + "title": "Интерфейс", + "description": "Какую плоскость управления показывает вам эта панель управления?", + "platformLabel": "Полная платформа", + "platformDesc": "Проекты, приложения, развертывания, серверы — все, что может сделать эта установка.", + "mailLabel": "Только по почте", + "mailDesc": "Панель управления почтой на боковой панели: домены, почтовые ящики, DNS, очередь, журналы.", + "instanceDefault": "Для этого экземпляра по умолчанию установлено значение {mode}.", + "useDefault": "Используйте экземпляр по умолчанию" + }, + "mailMode": { + "title": "Режим работы продукта", + "description": "Что представляет собой этот экземпляр. Это значение по умолчанию для всех присутствующих здесь — каждый пользователь по-прежнему может выбрать свой собственный вид в разделе Настройки → Общие.", + "platformLabel": "Полная платформа", + "platformDesc": "Проекты, приложения, развертывания, серверы — все, что может сделать эта установка.", + "mailLabel": "Почта Openship", + "mailDesc": "Помечает экземпляр как Openship Mail и превращает боковую панель в панель управления почтой.", + "savedOverridden": "Сохраненный. Ваш собственный вид не изменился — вы выбрали его в разделе Настройки → Общие.", + "errorToast": "Не удалось изменить режим работы продукта.", + "envNote": "Этот экземпляр следует за OPENSHIP_PRODUCT=mail из среды. Выбор режима здесь переопределяет его." + }, + "common": { + "cancel": "Отменить", + "save": "Сохранить", + "done": "Сделано", + "close": "Закрывать", + "back": "Назад", + "disconnect": "Разъединять", + "remove": "Удалять", + "create": "Создавать", + "previous": "Предыдущий", + "next": "Следующий", + "loading": "Погрузка…", + "copy": "Копировать", + "copied": "Скопированный", + "toast": { + "cloud": "Облако", + "defaults": "Значения по умолчанию", + "settings": "Настройки", + "dns": "DNS-сервер", + "notifications": "Уведомления", + "team": "Команда", + "members": "Члены", + "invitation": "Приглашение", + "invitations": "Приглашения", + "permissions": "Разрешения", + "accessTokens": "Токены доступа", + "cloneCredentials": "Клонировать учетные данные", + "migration": "Миграция", + "switchBack": "Переключитесь обратно", + "export": "Экспорт", + "import": "Импорт", + "importComplete": "Импорт завершен", + "authUpgrade": "Автоматическое обновление", + "disconnect": "Разъединять" + } + }, + "page": { + "title": "Настройки", + "subtitle": "Управляйте своими предпочтениями, командой и конфигурацией экземпляра", + "cloudConnectedToast": "Подключен к облаку Openship" + }, + "sidebar": { + "title": "Настройки", + "tabs": { + "general": "Общие", + "tokens": "Жетоны", + "mcp": "МЦП", + "team": "Команда", + "notifications": "Уведомления", + "email": "Электронная почта", + "systemSender": "Системный отправитель", + "dns": "DNS-сервер", + "audit": "Журнал аудита", + "cloud": "Облако", + "infrastructure": "Инфраструктура", + "instance": "Пример" + } + }, + "email": { + "title": "Электронная почта (SMTP)", + "description": "Служба SMTP, через которую этот экземпляр отправляет почту", + "intro": "Используется для сброса пароля, проверки электронной почты, приглашений в команду и уведомлений. Просто введите учетные данные SMTP от любого провайдера — Amazon SES, Gmail, Mailgun, корпоративного ретранслятора - хост, порт, имя пользователя, пароль. Сервер настраивать не нужно, Openship подключается к нему напрямую. Пароль зашифрован и больше никогда не отображается.", + "loading": "Погрузка…", + "configuredBadge": "Сконфигурированный", + "notConfigured": "Еще не настроено — сброс пароля, приглашения и уведомления по электронной почте остаются недоступными до тех пор, пока вы не введете учетные данные SMTP, указанные ниже.", + "providerLabel": "Поставщик", + "hostLabel": "SMTP-хост", + "hostPlaceholder": "smtp.example.com", + "portLabel": "Порт", + "userLabel": "Имя пользователя", + "userPlaceholder": "user@example.com", + "passwordLabel": "Пароль", + "passwordPlaceholder": "Пароль SMTP или ключ приложения", + "passwordKeepPlaceholder": "•••••••• (оставьте пустым, чтобы поддерживать актуальность)", + "fromLabel": "С адреса", + "fromPlaceholder": "Openship ", + "fromHint": "Необязательный. По умолчанию используется имя пользователя.", + "fromHintRequired": "Обязательно — ваше имя пользователя не является адресом электронной почты, поэтому получателям нужен реальный почтовый адрес.", + "fromRequired": "Введите адрес отправителя — имя пользователя этого провайдера не является адресом электронной почты, поэтому оно не может быть отправителем.", + "fromInvalid": "Адрес отправителя должен содержать действительный адрес электронной почты (например, имя ).", + "save": "Сохранить", + "saving": "Экономия…", + "saved": "Настройки SMTP сохранены", + "saveFailed": "Не удалось сохранить настройки SMTP", + "hostRequired": "Введите SMTP-узел.", + "portInvalid": "Номер порта должен быть от 1 до 65535.", + "testTitle": "Отправьте тестовое электронное письмо", + "testPlaceholder": "you@example.com", + "sendTest": "Отправить тест", + "sending": "Отправка…", + "testSent": "Проверьте отправленное электронное письмо — проверьте почтовый ящик.", + "testFailed": "Тест не пройден", + "saveFirst": "Сохраните настройки SMTP перед отправкой теста.", + "disable": "Отключить и очистить SMTP", + "disabled": "SMTP отключен", + "toastTitle": "Электронная почта" + }, + "dns": { + "title": "Поставщики DNS-услуг", + "description": "Позвольте Openship создавать DNS-записи ваших доменов за вас", + "explainer": "При подключении провайдера добавление пользовательского домена сразу же записывает его записи, поэтому домен проходит проверку и получает свой сертификат без необходимости что-либо вставлять.", + "explainerOwnership": "Openship удаляет только те записи, которые он создал.", + "addProvider": "Подключите провайдера", + "connect": "Подключить", + "namePlaceholder": "Этикетка, например, продукция Cloudflare", + "tokenPlaceholder": "Токен API Cloudflare", + "scopesHint": "Требуется токен с областью действия {scopes}.", + "createTokenLink": "Создайте один из них", + "noneConnected": "Провайдер DNS не подключен. В доменах будут отображены записи, которые вы можете добавить вручную.", + "badgeActive": "Активный", + "badgeInvalid": "Нуждается во внимании", + "invalidHint": "Поставщик отклонил этот токен. Подключите его повторно, чтобы возобновить автоматическую запись.", + "metaLine": " · {provider} · последний подтвержденный {verified}", + "zoneCheck": { + "title": "Проверьте домен", + "description": "Проверьте, управляет ли подключенный провайдер зоной имени хоста, прежде чем добавлять ее.", + "placeholder": "app.example.com", + "check": "Проверять", + "matched": "Управляемая здесь зона {zone}. Записи в этот домен будут внесены автоматически.", + "none": "Ни один подключенный провайдер не управляет этой доменной зоной. Вы будете добавлять записи о ней вручную.", + "unauthorized": "Сохраненный токен был отклонен. Подключите его и повторите попытку.", + "unavailable": "Не удалось дозвониться до DNS—провайдера, так что это неизвестно - это не значит, что что-то неправильно настроено." + }, + "toast": { + "loadFailed": "Не удалось загрузить DNS-провайдеров", + "needBoth": "Введите метку и токен API", + "connected": "Подключенный {name}", + "connectFailed": "Не удалось подключиться к провайдеру", + "disconnected": "Отключенный {name}", + "disconnectFailed": "Не удалось отключить провайдера", + "checkFailed": "Не удалось проверить этот домен" + } + }, + "github": { + "title": "ГитХаб", + "titleWithLogin": "ГитХаб · @{login}", + "noInstallations": "Подключено · Еще не установлено", + "connectedOne": "Подключено · 1 установка", + "connectedMany": "Подключенные · установки {count}", + "requiresCloud": "Требуется Openship Cloud — приложение принадлежит openship.io", + "connectPrompt": "Подключите свою учетную запись на GitHub для развертывания репозиториев", + "checkingConnection": "Проверка соединения…", + "addAccount": "Добавить учетную запись", + "installApp": "Установите приложение GitHub", + "manageOnGithub": "Управление на GitHub", + "disconnect": "Разъединять", + "disconnectTitle": "Отключить {label}", + "disconnectAppLabel": "Приложение Openship на GitHub", + "disconnectAppBody": "При этом строка учетной записи Openship OAuth будет удалена. Приложение GitHub будет установлено до тех пор, пока вы не удалите его на GitHub.", + "cloudExplainer": "Приложение Openship GitHub принадлежит компании openship.io. Подключите свой экземпляр к облаку Openship Cloud, чтобы использовать токены установки с ограниченным доступом для клонирования частных репозиториев (работает для локального И удаленного развертывания).", + "connectCloud": "Подключите облако Openship", + "noCloudTitle": "Клонирование частных репозиториев без облака", + "useSshPerServer": "SSH-ключ для каждого сервера", + "usePat": "Токен доступа", + "noCloudHint": "Настройте SSH-ключ на каждом сервере (Серверы → GitHub) или добавьте персональный токен доступа, который работает для локального и удаленного развертывания.", + "linkExplainer": "Привяжите свою учетную запись на GitHub для импорта репозиториев, включите автоматическое развертывание по нажатию и управляйте филиалами непосредственно с панели мониторинга.", + "connecting": "Связывающий…", + "connect": "Подключите GitHub", + "orgBadge": "Org", + "userBadge": "Пользователь", + "ghCli": { + "title": "gh CLI", + "loggedInAs": "Зарегистрирован как @{login}", + "fallbackDesc": "Необязательный резервный вариант локальной сборки для репозиториев за пределами установленных вами приложений", + "localOnly": "Только локальные сборки", + "localOnlyTitle": "Отказано во время развертывания для сборок на удаленном сервере. Для удаленного развертывания требуется приложение или токен-клон для каждого проекта.", + "usedForDeploys": "Используется для развертывания", + "usedForDeploysTitle": "Нет подключения к облаку — gh CLI является основным источником для всего прямо сейчас", + "activeWarnStrong": "активным источником является gh CLI.", + "activeWarnRest": "В развертывании на удаленных серверах будет отказано — добавьте SSH-ключ для каждого сервера, подключите приложение Openship или установите токен для каждого проекта для развертывания на удаленных целевых объектах.", + "primaryNotePrefix": "При удаленном развертывании используется собственная авторизация на GitHub для каждого сервера (SSH-ключ или токен) или облачное приложение Openship. gh CLI охватывает только", + "primaryNoteStrong": "локальные сборки", + "primaryNoteSuffix": "защищайте репозитории за пределами установленных вами приложений.", + "optionalPrefix": "Необязательный. Бежать", + "optionalSuffix": "на этом компьютере, чтобы разрешить локальную сборку клонов репозиториев вне установленных вами приложений. При удаленном развертывании используется SSH-ключ каждого сервера или приложения.", + "disconnectPrefix": "Чтобы отключиться, запустите", + "disconnectSuffix": "в вашем терминале.", + "use": "Используйте gh CLI", + "login": "Войдите в систему с помощью GitHub", + "deviceHint": "Введите этот одноразовый код на GitHub, чтобы авторизовать этот экземпляр:", + "waiting": "Ожидание авторизации — это обновление происходит автоматически.", + "tokenAltPrefix": "Предпочитаете токен? Добавьте личный токен доступа в разделе", + "tokenAltLink": "Клонировать учетные данные.", + "forwardOnNote": "Переадресация включена — gh CLI также проверяет подлинность клонов удаленного сервера. Ваши идентификационные данные передаются по SSH для каждого клона; на сервере ничего не хранится.", + "forwardOffHint": "Пока что только локальные сборки. Включите \"Перенаправить мой идентификатор git на серверы сборки\", чтобы использовать gh CLI и для развертывания удаленных серверов.", + "manageForward": "Управление переадресацией", + "disconnectBody": "Openship удалит эти учетные данные из этого экземпляра и перестанет использовать их для клонирования. Они остаются действительными на GitHub до тех пор, пока вы не отзовете их там. Вы можете повторно подключиться в любое время.", + "recheck": "Проверьте еще раз" + }, + "activeVia": "Подключается через {method}", + "pickMethod": "Выберите способ доступа Openship к вашим репозиториям.", + "methodDevice": "Вход на GitHub", + "methodApp": "Облачное приложение Openship на GitHub", + "methodAppDesc": "Управляемое приложение — развертывается на удаленных серверах с помощью токенов с коротким сроком службы.", + "methodSshDesc": "Прикрепите ключ развертывания к каждому серверу (Servers → GitHub).", + "methodTokenDesc": "Персональный токен доступа, который можно использовать везде.", + "signIn": "Войдите в систему с помощью GitHub", + "signInDesc": "Войдите в систему через браузер с помощью кода устройства. Регистрироваться не нужно, нет доступа к серверу по SSH.", + "changeMethod": "Способ изменения", + "otherMethods": "Другие методы", + "openGithub": "Откройте GitHub", + "copyCode": "Нажмите, чтобы скопировать", + "tokenConnect": "Подключить", + "tokenCreate": "Создайте токен на GitHub", + "tokenGhHint": "Уже выполнили вход на сервер с помощью", + "tokenSaveFailed": "Не удалось сохранить токен.", + "forwardOffHint": "Только локальные сборки. Включите \"Перенаправлять мои идентификаторы git на серверы сборки\", чтобы использовать их и для развертывания удаленных серверов.", + "remoteCredentialHint": "Используется для просмотра репозиториев и сборок, выполняемых на этом хосте. При развертывании сборки на удаленном сервере используются собственные учетные данные этого сервера — добавьте ключ развертывания или токен для каждого сервера.", + "methodToken": "Токен GitHub", + "methodHostCli": "gh CLI на этом хосте", + "manageTokensOnGithub": "Управление токенами на GitHub", + "manageAccessOnGithub": "Управление доступом на GitHub", + "disconnectScopeNote": "Disconnect удаляет эти учетные данные из Openship и прекращает их использование для клонов. Они остаются действительными на GitHub до тех пор, пока вы не отзовете их там.", + "credentialRejected": "GitHub отклонил сохраненный {method}.", + "credentialRejectedImpact": "Он был отозван, срок действия истек или была утеряна требуемая область действия. При развертывании этого клона с его помощью будет происходить сбой до тех пор, пока вы не подключитесь снова, как показано ниже.", + "credentialUnreachable": "Не удалось связаться с GitHub, чтобы проверить сохраненный {method}.", + "credentialUnreachableImpact": "Обычно это проблема с сетью, а не с неверными учетными данными — Openship продолжает их использовать. Повторное подключение не поможет, если GitHub недоступен.", + "credentialCheckedAt": "Последний раз проверялся {time}" + }, + "deployDefaults": { + "title": "Развертывание по умолчанию", + "description": "Где по умолчанию должны размещаться новые развертывания", + "loading": "Настройки загрузки…", + "intro": "Выбранный целевой объект предварительно выбирается в окне выбора развертывания. Вы все равно можете переопределить его для каждого развертывания или удалить, чтобы он запрашивался каждый раз.", + "defaultServer": "Сервер по умолчанию", + "noServers": "Серверы еще не настроены - добавьте их в окне выбора развертывания.", + "clearDefault": "Очистить значение по умолчанию (спрашивать каждый раз)", + "targets": { + "server": { + "label": "Мой сервер", + "desc": "Настроенный SSH-сервер" + }, + "cloud": { + "label": "Облако открытого корабля", + "desc": "Управляемая облачная инфраструктура" + } + }, + "labelFor": { + "yourServer": "ваш сервер", + "cloud": "Облако Openship" + }, + "toast": { + "pickServer": "Сначала выберите сервер", + "cleared": "Цель развертывания по умолчанию очищена", + "setTo": "По умолчанию установлено значение {label}", + "failed": "Не удалось обновить значение по умолчанию" + } + }, + "buildPreferences": { + "title": "Настройки построения", + "description": "Контролируйте, как создаются и развертываются ваши проекты", + "loading": "Настройки загрузки…", + "intro": "Выберите стратегию сборки по умолчанию для новых развертываний. Переопределения для каждого проекта доступны в настройках проекта.", + "modes": { + "auto": { + "label": "Авто", + "desc": "Интеллектуальный подход к каждому фреймворку" + }, + "server": { + "label": "Сервер", + "desc": "Сборка на удаленном компьютере" + }, + "local": { + "label": "Местный", + "desc": "Сборка на машине" + } + }, + "toast": { + "setTo": "Режим сборки установлен на {mode}", + "failed": "Не удалось обновить режим сборки" + } + }, + "cloneCredentials": { + "title": "Учетные данные для клонирования на GitHub", + "description": "Личный токен, используемый для клонирования частных репозиториев, когда приложение GitHub не установлено", + "loading": "Погрузка…", + "intro": "Вставьте личный токен доступа GitHub (классический или детализированный). Модуль clone использует его в качестве учетных данных второго приоритета - после любого переопределения для каждого проекта, перед токеном установки приложения GitHub.", + "placeholder": "ghp_... или github_pat_…", + "showToken": "Показать жетон", + "hideToken": "Скрыть токен", + "saveToken": "Сохранить токен", + "scopeHintPrefix": "Для частных репозиториев присваивайте токену следующий", + "scopeHintSuffix": "расширенный (классический) или детализированный доступ для чтения к репозиториям, которые вы хотите развернуть.", + "tokenSaved": "Сохраненный токен", + "lastUpdated": "Последнее обновление", + "justNow": "прямо сейчас", + "replace": "Заменять", + "clear": "Четкий", + "useAsDefault": "Использовать в качестве токена клонирования по умолчанию", + "useAsDefaultDesc": "Когда он включен, модуль clone использует этот токен в качестве второго уровня в цепочке (после переопределения для каждого проекта). Когда он выключен, токен сохраняется, но не используется - удобно, если вы хотите, чтобы он был активен только для определенных развертываний.", + "forwardGitLabel": "Перешлите мой идентификатор git для создания серверов", + "forwardGitDesc": "Когда сборка выполняется на удаленном сервере, перенаправьте свой локальный логин GitHub CLI по SSH—туннелю, чтобы частные репозитории клонировались непосредственно на сервере - приложение GitHub не требовалось. Когда он выключен, сервер возвращается к своему собственному логину git, сохраненному токену или общедоступному/локальному пути клонирования.", + "forwardGitFailed": "Не удалось обновить пересылку git", + "toast": { + "pasteFirst": "Вставьте маркер перед сохранением", + "notLikeToken": "Это не похоже на токен GitHub. Все равно сохраняйте, если уверены.", + "saved": "Сохраненный токен клонирования", + "saveFailed": "Не удалось сохранить токен", + "cleared": "Токен клонирования очищен", + "clearFailed": "Не удалось очистить токен", + "updateDefaultFailed": "Не удалось обновить значение по умолчанию" + } + }, + "tokens": { + "title": "Персональные токены доступа", + "description": "Токены на предъявителя для клиентов API, CLI и MCP. Каждый токен действует от вашего имени.", + "explainer1": "По умолчанию токен", + "explainerActsAsYou": "действует так, как вы", + "explainer2": "— он содержит разрешения вашей роли.", + "explainerReadOnly": "Доступен только для чтения", + "explainer3": "блокирует все операции записи, и", + "explainerLimit": "Ограничьтесь конкретными ресурсами", + "explainer4": "применяйте токен именно к тому, что вы выберете, даже если это не относится к вашей собственной роли. Идеально подходит для токена MCP с узким профилем.", + "copyNow": "Скопируйте свой новый токен прямо сейчас", + "onlyTime": "Это единственный раз, когда оно показывается. Храните его в надежном месте.", + "namePlaceholder": "Имя токена (например, клиент MCP)", + "readOnly": "Доступен только для чтения", + "limitToResources": "Ограничьтесь конкретными ресурсами", + "chooseResources": "Выберите ресурсы", + "resourcesSelectedOne": "Выбран ресурс {count}", + "resourcesSelectedMany": "Выбранные ресурсы {count}", + "noResourcesSelected": "Ресурсы еще не выбраны", + "createToken": "Создать токен", + "newToken": "Новый токен", + "loading": "Погрузка…", + "noActive": "Нет активных токенов.", + "badgeReadOnly": "доступен только для чтения", + "badgeScoped": "ограниченный охват", + "metaLine": " · последний раз использовался {lastUsed} · срок действия {expires}", + "revoke": "Отменять", + "expiry": { + "none": "Срок годности не истек", + "days30": "30 дней", + "days90": "90 дней", + "year1": "1 год" + }, + "scopePicker": { + "title": "Область применения токена", + "subtitle": "Токен доступен только для этих ресурсов. Вы можете предоставить доступ только к тем ресурсам, которые у вас есть.", + "saveLabel": "Сделано" + }, + "toast": { + "giveName": "Дайте токену имя", + "pickResource": "Выберите хотя бы один ресурс или отключите определение области", + "createFailed": "Не удалось создать токен", + "revoked": "Аннулированный \"{name}\"", + "revokeFailed": "Не удалось отозвать токен", + "loadFailed": "Не удалось загрузить токены" + } + }, + "mcp": { + "title": "МЦП", + "description": "Подключите агенты искусственного интеллекта к вашему Openship API по протоколу Model Context Protocol.", + "loading": "Погрузка…", + "connectAnother": "Подключите другого клиента", + "bannerStrong": "Вставьте приведенную ниже конечную точку в свой MCP-клиент", + "bannerRest": "(Клод, курсор, ...) — открывается окно браузера, в котором вы подтверждаете доступ и выбираете, к чему может обращаться клиент. Токен для копирования не требуется. Openship - это MCP-сервер, соответствующий стандартам OAuth 2.1.", + "addToClient": "Добавьте к своему клиенту", + "install": "Устанавливать", + "endpoint": "Конечная точка", + "endpointNote": "Потоковая передача-HTTP JSON-RPC. Клиенты, поддерживающие OAuth, авторизуются в браузере; при одобрении вы выбираете, доступны ли они только для чтения + к каким ресурсам клиент может получить доступ.", + "authentication": "Идентификация", + "oauth": "OAuth (Открытый)", + "staticToken": "Статический токен", + "oauthNote": "Клиент открывает браузер для авторизации — вы подтверждаете доступ и выбираете, к чему он может быть подключен. Копировать нечего.", + "tokenNote": "Для клиентов без OAuth или когда вам нужен токен с фиксированной областью действия в конфигурации.", + "clientConfig": "Конфигурация клиента", + "createTokenPrefix": "Создайте токен в", + "tokensTab": "Жетоны", + "createTokenMid": "закладка и замена", + "createTokenSuffix": ". Токен, доступный только для чтения, ограничивает доступ агента к чтению.", + "connectedClients": "Подключенные клиенты", + "clientReadOnly": "Доступен только для чтения", + "clientFullControl": "Полный контроль", + "allResources": "Все ресурсы", + "resourcesOne": "Ресурс {count}", + "resourcesMany": "Ресурсы {count}", + "orgPrefix": "{org} ХVARX · ", + "authorized": "Авторизованный {date}", + "lastUsedSuffix": " · последний раз использовался {date}", + "toast": { + "disconnected": "Клиент MCP отключен", + "disconnectFailed": "Не удалось отключить" + }, + "editAccess": "Доступ к редактированию", + "editScopeTitle": "Доступ к {client}", + "editScopeSubtitle": "Изменения вступают в силу при следующем запросе агента — ему не нужно повторно подключаться.", + "editScopeOrg": "В {org}", + "wasNResourcesOne": "в настоящее время 1 ресурс", + "wasNResourcesMany": "в настоящее время ресурсы {count}", + "saveScope": "Сохранить доступ", + "scopeSaved": "Доступ обновлен", + "scopeSaveFailed": "Не удалось обновить доступ", + "loadScopeFailed": "Не удалось загрузить доступ этого клиента", + "scopeGrantRejected": "Вы больше не можете предоставлять {resource}, поэтому он был удален. Сохраните еще раз, чтобы продолжить.", + "confirmWidenTitle": "Это устраняет все ограничения", + "confirmWidenBody": "Агент будет действовать с учетом вашего полного доступа и вступит в силу немедленно. Нажмите еще раз для подтверждения.", + "confirmWidenAction": "Снимите все ограничения" + }, + "team": { + "heading": "Команда", + "reachability": { + "description": "Товарищам по команде нужен общедоступный URL-адрес, чтобы попасть в это рабочее пространство.", + "notInstalledTitle": "Предоставьте Openship публичный адрес", + "notInstalledBody": "Openship еще не настроен с общедоступным URL-адресом. Разверните его с общедоступным адресом (например, \"openship up --public-url ...\"), затем добавьте домен, чтобы партнеры по команде могли связаться с ним.", + "noDomainTitle": "Добавьте домен в Openship", + "noDomainBody": "Добавьте домен в приложение Openship, чтобы партнеры по команде могли получать доступ к этому рабочему пространству — приглашения включаются автоматически, как только оно запускается.", + "addDomain": "Добавить домен", + "pendingTitle": "Завершите настройку вашего домена", + "pendingBody": "Ваш домен Openship ожидает подтверждения (DNS / SSL). Приглашения будут активированы, как только он заработает.", + "viewDomain": "Просмотр домена" + }, + "descPersonal": "Люди, имеющие доступ к вашему личному рабочему пространству.", + "descTeam": "Люди, имеющие доступ к проектам, развертываниям и серверам этой организации.", + "inviteMember": "Пригласить участника", + "createTeamCard": { + "title": "Создайте командную организацию", + "body": "Вы можете приглашать людей сюда напрямую или создать отдельное общее пространство, которое будет изолировано от ваших личных проектов.", + "button": "Создать команду" + }, + "activeMembers": "Активные участники ({count})", + "you": "(ты)", + "removeMember": "Удалить участника", + "pendingInvitations": "Ожидающие приглашения ({count})", + "invitedAs": "Приглашен как {role} - срок действия {date} истекает", + "roles": { + "owner": "Владелец", + "admin": "Администратор", + "member": "Член", + "restricted": "Ограниченный" + }, + "createTeamModal": { + "title": "Создание командной организации", + "body": "Ваше личное рабочее пространство останется нетронутым. В командной организации есть свои проекты, серверы и приглашенные участники.", + "teamName": "Название команды", + "placeholder": "Acme Inc", + "createTeam": "Создать команду" + }, + "memberPanel": { + "subtitle": "Привилегии предоставляются участникам с ограниченным доступом. По умолчанию владелец/администратор/участник имеют доступ ко всей организации.", + "saveLabel": "Сохранить доступ" + }, + "serverAccessWarning": { + "title": "Предоставить полный доступ к серверу?", + "body": "{member} получит полный контроль над {scope} — каждым развертыванием и его данными, всеми запущенными на нем приложениями, сохраненными секретами и переменными среды, доступом к терминалу и любыми подключенными интеграциями (например, токенами GitHub и ключами развертывания, хранящимися для него). Они смогут управлять этими ресурсами или удалять их.", + "scopeAllServers": "все серверы в этой организации", + "scopeThisServer": "этот сервер", + "scopeCount": "Серверы {count}", + "confirm": "Предоставить доступ" + }, + "confirmRemove": "Удалить этого участника из организации?", + "workspace": { + "deleteWorkspace": "Удалить рабочее пространство", + "leaveWorkspace": "Покинуть рабочее пространство", + "deleteBody": "Навсегда удалите это рабочее пространство и все, что в нем находится.", + "leaveBody": "Покиньте это рабочее пространство — вам понадобится новое приглашение, чтобы вернуться.", + "deleteConfirm": "Удалите это рабочее пространство? Его проекты, участники и настройки будут удалены для всех. Это невозможно отменить.", + "leaveConfirm": "Покиньте это рабочее пространство? Вы потеряете доступ к нему до тех пор, пока вас не пригласят снова.", + "manage": { + "title": "Управление рабочим пространством", + "sectionBody": "Переименуйте это рабочее пространство, приостановите его проекты или удалите его.", + "nameLabel": "Имя рабочей области", + "rename": "Переименовать", + "projects": "Проекты ({count})", + "noProjects": "В этой рабочей области нет проектов.", + "running": "Бегущий", + "stopped": "Остановился", + "pauseTitle": "Приостановите все", + "pauseBody": "Останавливайте каждый проект, но сохраняйте рабочее пространство — возобновляйте в любое время.", + "pauseButton": "Остановить все проекты", + "deleteTitle": "Удалить рабочее пространство", + "deleteBody": "Удаляются все проекты {count} (контейнеры и маршруты) и рабочее пространство. Данные тома остаются доступными для восстановления. Отменить их невозможно.", + "confirmLabel": "Введите “{name}” для подтверждения", + "deleting": "Удаление…", + "deletingProject": "Удаление {name}…", + "deletingWorkspace": "Удаление рабочей области…", + "toastRenamed": "Переименованная рабочая область", + "toastRenameFailed": "Не удалось переименовать рабочую область", + "toastPaused": "Остановленные проекты {count}", + "toastPauseFailed": "Некоторые проекты невозможно было остановить", + "toastProjectFailed": "Не удалось удалить {name}" + } + }, + "toast": { + "teamNameRequired": "Требуется указать название команды", + "teamCreated": "Команда \"{name}\" создана — переходим сейчас…", + "createFailed": "Не удалось создать команду", + "loadFailed": "Не удалось загрузить команду", + "updateRoleFailed": "Не удалось обновить роль", + "removeFailed": "Не удалось удалить", + "cancelFailed": "Не удалось отменить", + "accessUpdated": "Доступ обновлен", + "loadGrantsFailed": "Не удалось загрузить гранты", + "deleteFailed": "Не удалось удалить рабочую область", + "deleteBillingActive": "Отмените активную подписку на это рабочее пространство перед ее удалением.", + "deleted": "Удаленная рабочая область", + "leaveFailed": "Не удалось покинуть рабочее пространство", + "left": "Левое рабочее пространство" + } + }, + "inviteMember": { + "headerTitle": "Пригласите участника", + "headerDescRestricted": "Укажите их роль слева, затем выберите именно то, до чего они могут дотянуться справа.", + "headerDescDefault": "Мы отправим им по электронной почте ссылку для вступления в эту организацию.", + "email": "Электронная почта", + "emailPlaceholder": "teammate@example.com", + "role": "Роль", + "roleMemberTitle": "Член", + "roleMemberDesc": "Чтение и запись ко всем ресурсам в этой организации.", + "roleAdminTitle": "Администратор", + "roleAdminDesc": "Все, что может делать участник, плюс управление участниками + выставление счетов.", + "roleRestrictedTitle": "Ограниченный", + "roleRestrictedDesc": "Доступа по умолчанию нет — выберите, какие именно ресурсы разблокировать.", + "grantsOne": "Грант {count}", + "grantsMany": "Гранты {count}", + "sendVia": "Отправить через", + "yourMailServer": "Ваша почтовая система", + "openshipCloud": "Облако Openship", + "mailReady": "Готов", + "mailNotSetUp": "Не настроено", + "cloudReady": "Связанный", + "cloudNotReady": "Не подключен", + "noMailSystem": "Система электронной почты не настроена, поэтому приглашение не будет доставлено.", + "setUpEmail": "Настройка электронной почты →", + "cloudNotConnected": "Облако Openship не подключено, поэтому оно не может отправить приглашение.", + "connectCloud": "Подключите облако Openship →", + "pickerTitle": "Первоначальный доступ к ресурсам", + "pickerDesc": "Участники с ограниченным доступом сначала не имеют доступа. Выберите, что открывает это приглашение после его принятия — вы можете предоставить больше позже в строке участника.", + "sendInvite": "Отправить приглашение", + "toast": { + "failedSend": "Не удалось отправить приглашение", + "invitationSent": "Приглашение отправлено на {email}", + "personalOrgBlocked": "В личные рабочие области нельзя приглашать участников. Сначала создайте командную организацию, а затем отправляйте приглашения.", + "updateMailSourceFailed": "Не удалось обновить источник почты" + } + }, + "teamWorkspace": { + "title": "Пригласите свою команду", + "description": "Переместите это рабочее пространство туда, куда смогут дотянуться ваши товарищи по команде.", + "body": "Это рабочее пространство доступно только на этом компьютере, поэтому партнеры по команде не могут к нему подключиться, а приглашения отключены. Переместите его в общедоступное место — на свой собственный сервер, в облако Openship или в туннель — чтобы начать приглашать людей.", + "currentMode": "Текущий режим", + "singleUserLocal": "Однопользовательский (локальный)", + "migrate": "Мигрировать", + "ownerOnlyTitle": "Только владелец рабочей области может выполнить миграцию", + "comingSoon": "Скоро появится прямая связь с удаленным экземпляром." + }, + "cloud": { + "checking": "Проверка…", + "fallbackName": "Облако Openship", + "connectedAccount": "Подключенная облачная учетная запись", + "connected": "Связанный", + "disconnect": "Разъединять", + "featuresActive": "Для вашего экземпляра активны облачные развертывания, управляемый протокол SSL и глобальный CDN.", + "connectToCloud": "Подключение к облаку", + "unlockDesktop": "Разблокируйте облачные развертывания, управляемый протокол SSL и глобальную сеть CDN.", + "deployLocal": "Выполняйте развертывание в облаке непосредственно из вашего локального экземпляра.", + "waitingSignIn": "Ожидание входа в систему…", + "connectButton": "Подключитесь к облаку Openship", + "confirmDisconnect": "Отключитесь от Openship Cloud? Облачные развертывания не будут работать до тех пор, пока вы не восстановите подключение.", + "toast": { + "disconnected": "Отключен от облака Openship", + "disconnectFailed": "Не удалось отключить" + }, + "pitch": { + "title": "Добавить облако Openship", + "body": "Каждый проект получает бесплатный домен .Домен {domain} с автоматическим SSL — без DNS и сертификатов. Ваши собственные серверы продолжают работать точно так же, как и сейчас.", + "perkDomain": "Свободный.Домен {domain} + автоматический SSL для каждого проекта", + "perkDeploy": "Выполняйте развертывание в управляемом облаке или оставайтесь на своих собственных серверах", + "perkServices": "Управляемые Postgres, Redis и другие, настраиваемые одним щелчком мыши", + "perkGithub": "Подключитесь к GitHub без регистрации вашего собственного приложения", + "noLockIn": "Вы можете свободно подключаться. Ничто не перемещается, и вы можете отключиться в любой момент.", + "viewPricing": "Просмотр ценообразования" + } + }, + "instance": { + "title": "Пример", + "descDesktop": "Настольное приложение", + "descCloud": "Облако", + "descSelfHosted": "Самодостаточный", + "typeDesktop": "Рабочий стол", + "typeCloud": "Облако Openship", + "typeSelfHosted": "Самодостаточный", + "deployMode": "Режим развертывания: {mode}", + "authNone": "Нулевая аутентификация", + "authCloud": "Облачная авторизация", + "authLocal": "Локальная авторизация", + "localUser": "Локальный пользователь", + "change": "Изменить" + }, + "upgradeAuth": { + "title": "Добавьте пароль", + "description": "Преобразуйте этот экземпляр с нулевой авторизацией в реальный адрес электронной почты и логин с паролем. Ваши проекты и история останутся нетронутыми.", + "close": "Закрывать", + "name": "Имя", + "namePlaceholder": "Джейн Доу", + "email": "Электронная почта", + "emailPlaceholder": "you@example.com", + "password": "Пароль", + "passwordPlaceholder": "Не менее 8 символов", + "useMailServer": "Используйте свой почтовый сервер", + "useMailServerDesc": "Отправляйте сброс пароля, подтверждения и приглашения в команду с вашего подготовленного почтового сервера вместо резервного SMTP на основе env.", + "createAccount": "Создать аккаунт", + "toast": { + "passwordTooShort": "Пароль должен содержать не менее 8 символов", + "accountCreated": "Учетная запись создана — теперь вы вошли в систему", + "failedUpgrade": "Не удалось выполнить обновление" + } + }, + "notifications": { + "channels": { + "title": "Каналы доставки", + "description": "Куда отправляются ваши уведомления. Проверенные каналы доступны; непроверенные пропускаются.", + "empty": "Каналов пока нет. Добавьте один из них, чтобы начать получать уведомления.", + "verified": "Проверенный", + "unverified": "Непроверенный", + "sendTest": "Отправить тест", + "testSent": "Отправленный тест", + "deleteChannel": "Удалить канал", + "addChannel": "Добавить канал", + "confirmDelete": "Удалите этот канал? Подписка на него будет прекращена.", + "channelRemoved": "Канал удален", + "channelAdded": "Добавлен канал" + }, + "describe": { + "slackWebhook": "Слабый веб-крючок", + "discordWebhook": "Веб-крючок Discord", + "msteamsWebhook": "Веб-интерфейс Microsoft Teams webhook", + "inApp": "Значок звонка на панели управления" + }, + "kinds": { + "email": "Электронная почта", + "webhook": "Веб-крючок", + "slack": "Слабина", + "discord": "Диссонанс", + "msteams": "Команды Microsoft Teams", + "telegram": "Телеграмма", + "in_app": "Встроенный в приложение" + }, + "form": { + "labelPlaceholder": "Ярлык (например, электронное письмо по вызову)", + "emailPlaceholder": "you@example.com", + "webhookPlaceholder": "https://example.com/openship-hook", + "slackPlaceholder": "https://hooks .slack.com/services /...", + "discordPlaceholder": "https://discord.com/api/webhooks /...", + "msteamsPlaceholder": "https://prod-00.westus.logic.azure.com/workflows /...", + "telegramTokenPlaceholder": "Токен бота от @BotFather", + "telegramChatPlaceholder": "Идентификатор чата (например, -1001234567890)", + "telegramHint": "Создайте бота с помощью @BotFather, затем отправьте ему сообщение (или добавьте его в свою группу), чтобы он мог ответить.", + "adding": "Добавление…", + "addChannel": "Добавить канал", + "labelRequired": "Требуется этикетка", + "noEmailTransport": "В этом экземпляре не настроен почтовый сервер, поэтому уведомления по электронной почте доставляться не будут.", + "setUpSmtp": "Настройка SMTP →", + "otherAddress": "Другой адрес…" + }, + "subscriptions": { + "title": "О чем следует получать уведомления", + "description": "Выберите, какие события будут транслироваться по какому каналу. Каждая ячейка - это одна подписка.", + "empty": "Сначала добавьте канал, чтобы подписаться на события.", + "allTab": "Все", + "eventHeader": "Событие", + "cellAria": "{category} через {channel}", + "notifyMe": "Уведоми меня" + }, + "orgDefaults": { + "title": "Настройки организации по умолчанию", + "description": "Значения по умолчанию применяются, когда новый участник присоединяется к этой организации. Участники могут изменять настройки для каждого канала.", + "notifyAria": "Уведомить о {category}", + "nChannels": "Каналы {n}" + } + }, + "audit": { + "heading": "Журнал аудита", + "subtitle": "Все, что произошло в этой организации, кто это сделал и когда.", + "searchPlaceholder": "Поиск приложений, серверов, доменов, людей…", + "noMatch": "Ничто не соответствует этим фильтрам.", + "noEvents": "Пока ничего не зафиксировано.", + "clearFilters": "Очистить фильтры", + "showing": "Отображение {from}-{to} из {total}", + "actor": "Актер", + "name": "Имя", + "email": "Электронная почта", + "userId": "Идентификатор пользователя", + "ip": "ip", + "userAgent": "Пользовательский агент", + "resource": "Ресурс", + "type": "Тип", + "id": "Идентификатор", + "changes": "Изменения", + "before": "До", + "after": "После", + "removed": "Удаленный", + "system": "Система", + "actorPrefix": "Актер {id}", + "recording": { + "title": "Записывайте активность", + "description": "Ведите учет всех изменений, внесенных в эту организацию. По умолчанию включено.", + "paused": "Запись выключена. Ничего нового не добавляется — ниже приведены записи, которые были записаны до того, как программа была выключена.", + "retention": "Храните записи для", + "retentionOption": "{days} дней", + "retentionHint": "Старые записи удаляются автоматически.", + "adminOnly": "Только владельцы и администраторы могут изменить это.", + "saveFailed": "Не удалось сохранить настройки активности." + }, + "filters": { + "anyone": "Кто угодно", + "period": "Период", + "allTime": "Все время", + "today": "Сегодня", + "last7": "Последние 7 дней", + "last30": "Последние 30 дней", + "last90": "Последние 90 дней" + }, + "tabs": { + "all": "Все" + }, + "sources": { + "all": "Всё", + "dashboard": "Приборная панель", + "mcp": "Помощник с искусственным интеллектом", + "cli": "КЛИ", + "api": "интерфейс прикладного программирования", + "webhook": "Веб-крючок", + "system": "Система", + "unknown": "Неизвестный" + }, + "day": { + "today": "Сегодня", + "yesterday": "Вчера" + }, + "details": { + "who": "Кто", + "when": "Когда", + "cameFrom": "Пришел из", + "technical": "Технические детали", + "eventType": "Тип события" + } + }, + "updates": { + "title": "Обновления", + "description": "Как Openship проверяет и применяет новые версии", + "checking": "Проверка наличия обновлений…", + "available": "Доступен Openship {version}", + "upToDate": "Вы используете последнюю версию", + "current": "Текущий: {version}", + "rerunToUpdate": " · повторно запустите установку для обновления", + "updateNow": "Обновите сейчас", + "checkNow": "Проверьте сейчас", + "autoUpdateLabel": "Автоматическое обновление", + "autoUpdateDesc": "Загружайте и устанавливайте новые версии автоматически. По умолчанию отключено — вы сами контролируете изменения в своем приложении.", + "notificationsLabel": "Уведомления об обновлениях и системе безопасности", + "notificationsDesc": "Показывайте уведомление, когда новый выпуск или рекомендации по безопасности влияют на вашу версию. Важные рекомендации по безопасности всегда отображаются один раз, даже если эта функция отключена.", + "viewChangelog": "Просмотр списка изменений и релизов", + "securityTitle": "Как работают проверки обновлений", + "securityDescription": "Полная прозрачность в отношении того, что связано с вашей установкой", + "security1": "Openship проверяет наличие обновлений и рекомендаций по безопасности", + "securityOnlyGithub": "только из общедоступных релизов на GitHub", + "security2": "из репозитория с открытым исходным кодом (", + "security3": "). Это только когда-либо", + "securityPulls": "тянет", + "security4": "эти данные — ни один сторонний сервис или сервер, управляемый Openship, не может отправлять обновления или сигналы для вашей установки. Рекомендации прилагаются к каждому выпуску, поэтому вы никогда не получите доступ к неизданным изменениям. Важные предупреждения по безопасности всегда отображаются один раз; все остальное зависит от указанного выше параметра." + }, + "infrastructure": { + "title": "Компоненты платформы", + "description": "Как поддерживать в актуальном состоянии edge и почтовые контейнеры на ваших серверах", + "autoUpdateLabel": "Серверная инфраструктура с автоматическим обновлением", + "autoUpdateDesc": "Когда эта панель управления обновится, автоматически обновите контейнеры edge и mail на подключенных серверах. По умолчанию отключено — в противном случае обновления будут помечены для применения одним щелчком мыши на каждом сервере.", + "autoScanLabel": "Серверная инфраструктура для автоматического сканирования", + "autoScanDesc": "При открытии страницы \"Серверы\" или \"Домашняя страница\" перепроверьте свои серверы, чтобы неактивный или отсутствующий элемент был отмечен без проверки вручную. По умолчанию включен только для обнаружения, это ничего не меняет.", + "attentionOne": "1 компонент, требующий внимания", + "attentionMany": "Компоненты {n} требуют особого внимания", + "updatesOne": "доступно 1 обновление", + "updatesMany": "Доступны обновления {n}", + "allHealthy": "Все компоненты платформы находятся в актуальном состоянии", + "manageLink": "Управление на серверах", + "hostControlLabel": "Развертывание на этом компьютере", + "hostControlDesc": "Позвольте OpenShip развертывать приложения на сервере, на котором он запущен, наряду с вашими подключенными серверами. Отключено при установке с помощью --no-host-control (только на уровне управления) — включите его, чтобы добавить этот компьютер в качестве объекта развертывания.", + "hostControlEnvNote": "Эта машина была настроена на плоскость управления только при установке (--no-host-control). Включение этого параметра отменяет возможность развертывания OpenShip здесь.", + "hostControlError": "Не удалось изменить управление хостом — это может сделать только владелец рабочей области этого компьютера." + }, + "dataTransfer": { + "export": { + "title": "Экспорт данных", + "description": "Загрузите всю базу данных экземпляра в виде файла.", + "intro": "Создает переносимый снимок всего — проектов, серверов, развертываний, настроек. Задайте кодовую фразу, в которую будут включены ваши секретные данные (переменные env, токены, учетные данные SSH); они будут повторно зашифрованы, поэтому перемещение файла будет безопасным. Оставьте это поле пустым для экспорта без секретов.", + "passphraseLabel": "Ключевая фраза (необязательно)", + "passphrasePlaceholder": "Защищает ваши секреты", + "confirmLabel": "Подтвердите ввод ключевой фразы", + "confirmPlaceholder": "Повторите это", + "mismatch": "Парольные фразы не совпадают.", + "exporting": "Поставляющий…", + "exportDownload": "Экспорт и загрузка", + "toastWithSecrets": "Экспортируйте загруженное. Сохраните кодовую фразу — она понадобится вам для импорта.", + "toastNoSecrets": "Экспорт загруженного файла. Секретные данные не были включены (не задана ключевая фраза).", + "toastFailed": "Экспорт не удался." + }, + "import": { + "title": "Импорт данных", + "description": "Восстановите экспортированный файл в этом экземпляре.", + "intro": "Загрузите файл, экспортированный из другой установки Openship. Введите кодовую фразу, которая использовалась при экспорте, чтобы восстановить секретные данные.", + "importFromFile": "Импорт из файла…", + "modalTitle": "Импорт данных экземпляра", + "modalSubtitle": "Восстановите экспортированный моментальный снимок.", + "exportFile": "Экспорт файла", + "fileContainsSecrets": " · содержит секретные данные (требуется ввести ключевую фразу)", + "fileNoSecrets": " · никаких секретов в комплект не входит", + "passphrase": "Ключевая фраза", + "passphrasePlaceholder": "Ключевая фраза, заданная при экспорте", + "mode": "Режим", + "modeReplaceTitle": "Заменить все", + "modeReplaceDesc": "Удалите этот экземпляр и восстановите моментальный снимок в точности. Рекомендуется для переноса на новую машину.", + "modeMergeTitle": "Слиться с существующими", + "modeMergeDesc": "Сохраняйте текущие данные и добавляйте импортированные. Ваша учетная запись и настройки сохраняются.", + "wipeWarn": "При этом все текущие данные в этом экземпляре будут удалены, и вы выйдете из системы.", + "importing": "Импорт…", + "import": "Импорт", + "confirmWipe": "Замените ВСЕ данные в этом экземпляре импортированным моментальным снимком? Это невозможно отменить, и вы выйдете из системы.", + "notExport": "Это не похоже на файл экспорта Openship.", + "cantRead": "Не удалось прочитать этот файл — это допустимый экспорт?", + "importFailed": "Не удалось выполнить импорт.", + "rowsRestored": "Восстановлены строки {count}", + "secretsRestored": "Восстановлены секреты {count}", + "secretsNotRestored": "секреты НЕ восстановлены (нет/неверная кодовая фраза) — повторно введите учетные данные" + } + }, + "migrate": { + "chooseTitle": "Перейти в многопользовательский режим", + "serverTitle": "Перенесите на свой сервер", + "cloudTitle": "Переход в облако Openship", + "tunnelTitle": "Выставлять напоказ через туннель", + "completeTitle": "Миграция завершена", + "back": "Назад", + "chooseIntro": "На данный момент этот инстанс является однопользовательским. Выберите, как вы хотите, чтобы ваши товарищи по команде обращались к нему.", + "cards": { + "serverTitle": "Перенесите на свой сервер", + "serverBody": "SSH-разверните openship на вашем собственном VPS. Данные перемещаются туда. Лучше всего подходит для команд, у которых уже есть инфраструктура.", + "serverMeta": "Отсутствие внешней зависимости", + "cloudTitle": "Переход в облако Openship", + "cloudBody": "Разместите свои данные по адресу api.openship.io. У нас размещается все необходимое. Это лучшее решение для команд, которым нужна нулевая инфраструктура.", + "cloudMetaConnected": "Подключенная облачная учетная запись", + "metaRequiresCloud": "Требуется облачная учетная запись", + "cloudWarn": "Сначала подключитесь к облаку Openship.", + "tunnelTitle": "Сохраняйте локальность, открывайте доступ через туннель", + "tunnelBody": "Ваши данные останутся на этом компьютере. Мы предоставляем туннель Oblien edge, чтобы коллеги по команде могли связаться с вами через общедоступный Интернет — ваш компьютер должен быть подключен к сети.", + "tunnelMetaConnected": "Туннель через Наклонный", + "tunnelWarn": "Туннели настраиваются через вашу облачную учетную запись." + }, + "server": { + "targetServer": "Целевой сервер", + "loadingServers": "Загрузка серверов...", + "noServersPrefix": "Серверы не настроены. Добавьте один из них в", + "pickServer": "Выберите сервер", + "domain": "Домен", + "freeSubdomain": "Свободный поддомен", + "freeSubdomainHint": "name.opsh.io", + "customDomain": "Пользовательский домен", + "customDomainHint": "DNS указывает на сервер", + "freeSlugPlaceholder": "моя команда", + "customHostPlaceholder": "team.acme.com", + "preflight": "Предполетная подготовка", + "sshReachable": "Доступен по SSH", + "releaseAvailable": "Доступен релиз Openship", + "domainReady": "Домен готов", + "runPreflight": "Выполнить предполетный запуск", + "recheck": "Повторная проверка", + "deploying": "Развертывание...", + "startMigration": "Начать миграцию", + "successDetail": "openship теперь запущен на вашем сервере. Идентификатор проекта {projectId}.", + "toastLoadFailed": "Не удалось загрузить серверы", + "toastPreflightFailed": "Предполетная подготовка завершилась неудачей", + "toastMigrationFailed": "Не удалось выполнить миграцию" + }, + "cloud": { + "connectFirstTitle": "Сначала подключите свою облачную учетную запись", + "connectFirstBody": "Откройте Настройки → Облако и войдите в систему на api.openship.io. Затем вернитесь сюда, чтобы выполнить миграцию.", + "whatHappens": "Что происходит, когда вы нажимаете кнопку перенести", + "bullet1": "Ваша локальная база данных удалена (зашифрованные поля удалены — учетные данные не покидают этот компьютер).", + "bullet2": "Дамп будет загружен в api.openship.io в вашей активной организации.", + "bullet3": "Локальный экземпляр становится средством запуска, указывающим на app.openship.io.", + "bullet4": "Вы можете переключиться обратно в любое время — ваши локальные данные останутся на диске.", + "proceedNonEmpty": "Продолжайте, даже если в моей облачной организации уже есть проекты (я разберусь с конфликтами).", + "pushingData": "Передача данных...", + "startMigration": "Начать миграцию", + "successDetail": "Импортированные проекты {projects}, развертывания {deployments}, службы {services}.", + "toastConflict": "В вашей облачной организации уже есть проекты {count}. Установите флажок, чтобы продолжить, и добавьте данные этого экземпляра к тем, которые уже есть.", + "toastFailed": "Не удалось выполнить миграцию в облако" + }, + "tunnel": { + "connectFirstTitle": "Сначала подключите свою облачную учетную запись", + "connectFirstBody": "Туннели настраиваются через облако Openship. Откройте Настройки → Облако и войдите в систему, затем вернитесь сюда.", + "headsUp": "Выше голову", + "bullet1": "Ваши данные останутся на этом компьютере. Ничего не перемещается.", + "bullet2": "Товарищи по команде могут связаться с вами только тогда, когда эта машина подключена к сети.", + "bullet3": "Туннельный агент запускается внутри процесса API — никаких дополнительных услуг для присмотра.", + "tunnelSlug": "Туннельный снаряд", + "slugPlaceholder": "моя команда", + "slugSuffix": ".preview.oblien.com", + "slugHint": "3-32 символа, строчные буквы, цифры, тире. Должно начинаться и заканчиваться буквой или цифрой.", + "provisioning": "Обеспечение...", + "provisionTunnel": "Резервный туннель", + "successDetail": "Туннель \"{slug}\" публикует вашу локальную панель мониторинга.", + "toastSlugTaken": "Получен фрагмент \"{slug}\". Выберите другой.", + "toastNeedsCloud": "Для работы с туннелями необходимо подключить вашу облачную учетную запись. Сначала откройте Настройки → Облако.", + "toastFailed": "Не удалось создать туннель" + }, + "result": { + "complete": "Миграция завершена", + "newLocation": "Новое местоположение", + "open": "Открыть", + "done": "Сделано" + } + }, + "switchBack": { + "nothingTitle": "Ничего, что можно было бы переключить обратно", + "nothingBody": "Этот экземпляр уже находится в однопользовательском режиме.", + "openDashboard": "Открыть панель управления", + "resultTitle": "Вернуться к однопользовательскому режиму", + "resultRestored": "Восстановленные строки {rows} с пульта дистанционного управления ({mode}).", + "resultLocalTunnel": "Локальный режим восстановлен. Туннель разрушен — ваши данные так и не были перемещены.", + "resultLocalGrace": "Локальный режим восстановлен. Удаленные данные остаются нетронутыми в течение 30-дневного льготного периода.", + "relinkTitle": "Повторная привязка учетных данных", + "relinkBody": "Зашифрованные столбцы удаляются при перемещении между хостами. Перелинкуйте их, прежде чем они понадобятся снова:", + "relinkRowOne": "• {table}.{column} (строка {rows})", + "relinkRowMany": "• {table}.{column} (строки {rows})", + "heading": "Переключитесь обратно на однопользовательский режим", + "intro": "Извлеките этот экземпляр из {mode} и снова переведите его в одиночный режим на этом компьютере.", + "modeServer": "ваш сервер", + "modeCloud": "Облако Openship", + "modeTunnel": "туннель", + "current": "Текущий", + "noUrl": "(URL-адрес не записан)", + "teammatesLoseAccess": "Товарищи по команде теряют доступ", + "warnTunnel": "Туннель будет отключен. Всем, кто воспользуется общедоступным URL-адресом, будет отказано в подключении.", + "warnRemote": "Пульт дистанционного управления хранит ваши данные в течение 30 дней в качестве льготного периода на случай, если вы передумаете.", + "dontPull": "Не извлекайте удаленные данные — сохраняйте все, что есть на этом компьютере прямо сейчас.", + "dontPullDesc": "Используйте это, когда пульт дистанционного управления недоступен или вы намеренно хотите отменить удаленные изменения.", + "back": "Назад", + "tearingDown": "Разрушающий...", + "pullingData": "Извлекая данные...", + "switchBack": "Переключитесь обратно", + "toastLoadStateFailed": "Не удалось загрузить состояние", + "toastRemoteUnreachable": "Удаленный доступ недоступен. Поставьте галочку \"не извлекать удаленные данные\", чтобы в любом случае переключиться обратно.", + "toastSwitchBackFailed": "Не удалось выполнить обратный переход" + }, + "routePreferences": { + "title": "Маршрутизация", + "description": "Как преимущество достигает восходящих потоков ваших приложений", + "loading": "Настройки загрузки…", + "intro": "Выберите исходящую адресацию по умолчанию для новых автономных проектов. Переопределения для каждого проекта находятся в настройках проекта.", + "modes": { + "auto": { + "label": "Авто", + "desc": "Рекомендуется (порт обратной связи)" + }, + "loopbackPort": { + "label": "Петлевой порт", + "desc": "Частный порт хоста 127.0.0.1" + }, + "containerIp": { + "label": "IP-адрес контейнера", + "desc": "Расширенный IP—адрес моста" + } + }, + "toast": { + "setTo": "Стратегия маршрута установлена на {mode}", + "failed": "Не удалось обновить стратегию маршрута" + } + }, + "edgeOrphans": { + "title": "Неотслеживаемые пограничные маршруты", + "description": "Имена хостов, которые по-прежнему обслуживает этот компьютер, о которых у Openship нет записей", + "scan": "Сканировать", + "scanning": "Сканирующий…", + "allClear": "Учитывается каждое имя хоста, которое обслуживает edge.", + "comparedTo": "Сравнивается с отслеживаемыми именами хостов {count}.", + "unavailable": "Не смог проверить край", + "explain": "При удалении проекта с помощью \"Удалить только из Openship\" намеренно сохраняется его маршрут. Оставшийся маршрут приложения затем возвращает значение 502, как только его контейнер удаляется, но оставшийся СТАТИЧЕСКИЙ маршрут продолжает обслуживать старые файлы с значением 200 — даже для имени хоста, которое было передано другому проекту.", + "kindStatic": "Статические файлы", + "kindProxy": "Маршрут приложения", + "staticWarning": "Все еще обрабатываю файлы. Это ответы на запросы, поступившие сегодня.", + "proxyWarning": "Указывает на восходящий поток, который, вероятно, исчез.", + "servingFrom": "Подача из", + "proxyingTo": "Проксирование к", + "alsoAnswers": "Также отвечает за", + "stopServing": "Прекратите подавать", + "stopping": "Остановка…", + "stopped": "{hostname} больше не обслуживается.", + "stopFailed": "Не мог перестать обслуживать {hostname}", + "confirmTitle": "Перестать обслуживать {hostname}?", + "confirmBody": "Это удаляет конфигурацию edge только для этого имени хоста. Созданные файлы остаются на диске, и больше ничего на сервере не затрагивается. Если проект позже будет развернут на этом имени хоста, он создаст свой собственный маршрут.", + "confirmCta": "Прекратите подавать", + "cancel": "Отменить" + } +} diff --git a/apps/dashboard/src/i18n/locales/ru/widgets.json b/apps/dashboard/src/i18n/locales/ru/widgets.json new file mode 100644 index 000000000..f03d6f4a6 --- /dev/null +++ b/apps/dashboard/src/i18n/locales/ru/widgets.json @@ -0,0 +1,407 @@ +{ + "shared": { + "dnsRecords": { + "priority": "приоритет {n}", + "recommended": "рекомендуемый", + "name": "Имя", + "value": "Ценность", + "copy": "Копировать" + }, + "errorState": { + "commonCauses": "Общие причины", + "needHelp": "Нужна помощь?", + "needHelpDesc": "Ознакомьтесь с документацией или свяжитесь с нами, если проблема не устранена.", + "documentation": "Документация", + "repoNotFound": { + "title": "Репозиторий не найден", + "subtitle": "Мы не смогли найти хранилище, которое вы ищете.", + "hints": { + "0": "Хранилище является закрытым, и вы не предоставляли доступ к нему", + "1": "Имя или владелец хранилища написаны с ошибкой", + "2": "Хранилище было удалено или перемещено", + "3": "Срок действия вашего подключения к GitHub истек" + }, + "backToLibrary": "Вернуться в библиотеку", + "importRepository": "Импорт репозитория" + }, + "projectNotFound": { + "title": "Проект не найден", + "subtitle": "Проект, который вы ищете, не существует или был удален.", + "hints": { + "0": "Проект был удален", + "1": "У вас нет доступа к этому проекту", + "2": "Указан неверный URL-адрес проекта" + }, + "backToDashboard": "Вернуться к панели управления", + "createNewProject": "Создать новый проект" + }, + "loadFailed": { + "title": "Не удалось загрузить этот проект", + "subtitle": "Возникла проблема с подключением к этому проекту. Проверьте подключение и повторите попытку." + }, + "accessDenied": { + "title": "доступ запрещен", + "subtitle": "У вас нет разрешения на доступ к этому ресурсу.", + "hints": { + "0": "Вы не являетесь владельцем проекта", + "1": "У вашей учетной записи нет необходимых разрешений", + "2": "Изменился состав вашей команды" + }, + "backToDashboard": "Вернуться к панели управления" + } + }, + "machineSettings": { + "title": "Настройки машины", + "configureFor": "Настройка вычислительных ресурсов для", + "docs": "Доктора", + "cpu": "ЦП", + "memory": "Память", + "storage": "Место хранения", + "base": "Основа", + "current": "Текущий", + "creditsPerMonth": "кредиты в месяц", + "fromCurrent": "от текущего", + "viewPricing": "Просмотр ценообразования", + "cancel": "Отменить", + "saving": "Экономия...", + "saveChanges": "сохранить изменения", + "toastUpdated": "Обновлены настройки машины", + "toastFailed": "Не удалось обновить настройки" + }, + "serverSelector": { + "serverLabel": "Сервер", + "loadingServers": "Загрузка серверов…", + "noServerConnected": "Сервер не подключен", + "connectServerFirst": "Добавьте его прямо сейчас, не покидая этой страницы.", + "addServer": "Добавить сервер", + "selectServer": "Выберите сервер…", + "addNewServer": "Добавить новый сервер…" + } + }, + "backup": { + "runCard": { + "streamError": "Не удалось транслировать ход выполнения: {message}", + "loading": "Погрузка…", + "live": "Жить", + "started": "Начатый", + "finished": "Законченный", + "elapsed": "Истекший", + "bytes": "Байты", + "runId": "Идентификатор запуска", + "status": { + "queued": "Поставленный в очередь", + "preparing": "Подготовка", + "snapshotting": "Моментальный снимок", + "uploading": "Загрузка", + "verifying": "Подтверждающий", + "succeeded": "Преуспевший", + "failed": "Неудачный", + "cancelled": "Отмененный", + "serverError": "Ошибка сервера" + }, + "phase": { + "queued": "В ожидании работника…", + "preparing": "Определение пункта назначения + услуга…", + "snapshotting": "Создание артефактов (запуск перед подключением)…", + "uploading": "Потоковая передача в пункт назначения…", + "verifying": "Составление манифеста…" + } + }, + "policyEditor": { + "presetHourly": "Почасовой", + "presetDaily": "Ежедневно (03:17)", + "presetWeekly": "Еженедельно (Вс 03:17)", + "presetMonthly": "Ежемесячно (1-го числа в 03:17)", + "presetManual": "Только вручную", + "selectDestinationAlert": "Выберите пункт назначения", + "failedSave": "Не удалось сохранить политику", + "rotateConfirm": "Повернуть токен webhook? Текущий URL-адрес перестанет работать.", + "failedRotate": "Не удалось повернуть токен", + "editTitle": "Изменить политику резервного копирования", + "createTitle": "Создание политики резервного копирования", + "serviceLabel": "Сервис: {name}", + "projectLevel": "Политика на уровне проекта", + "destination": "Место назначения", + "selectOption": "— выберите —", + "schedule": "График", + "cronPlaceholder": "Настраиваемый cron (5 полей) или оставьте поле пустым для использования только вручную", + "retainCount": "Сохранить количество", + "retainCountHint": "Сохранить N самых последних успешных запусков", + "retainDays": "Сохраняйте дни", + "retainDaysHint": "Выпадение длится более N дней", + "preDeployTrigger": "Триггер предварительного развертывания", + "preDeployLabel": "Автоматическое резервное копирование перед каждым новым развертыванием", + "preDeployHint": "Срабатывает при каждой успешной сборке, непосредственно перед запуском нового кода.", + "webhookTrigger": "Триггер веб-соединения", + "webhookLabel": "Включить входящий URL-адрес веб-узла", + "webhookHint": "Генерирует токен для каждой политики. ОТПРАВЬТЕ сообщение по URL-адресу из любого внешнего триггера (действия на GitHub, мониторинг, ваш собственный планировщик).", + "copyUrl": "Скопировать URL-адрес", + "rotateToken": "Вращать токен", + "preHook": "Предварительный переход (запускается перед моментальным снимком)", + "preHookHint": "Общий для баз данных: pg_dump > /tmp/dump.sql. Ошибка прерывает запуск.", + "postHook": "Post-hook (запускается после загрузки)", + "postHookHint": "Очистка; сбои регистрируются, но не завершаются неудачей при запуске.", + "policyEnabled": "Политика включена", + "cancel": "Отменить", + "saving": "Экономия…", + "saveChanges": "Сохранить изменения", + "createPolicy": "Создать политику", + "methodLabel": "Способ резервного копирования", + "methodAuto": "Авто", + "methodAutoDesc": "Smart для каждой услуги", + "methodVolume": "Объем", + "methodVolumeDesc": "Тома моментальных снимков", + "methodCustom": "Обычай", + "methodCustomDesc": "Ваше собственное командование", + "detected": "Обнаружен {label} — автоматическое резервное копирование с помощью {method}.", + "autoNoDb": "База данных не обнаружена — автоматически будет создан моментальный снимок томов этой службы.", + "volumeHint": "Загружает все тома для этой службы. Работает в режиме реального времени, без сбоев.", + "customCommandLabel": "Команда сброса", + "customCommandHint": "Запускается внутри контейнера; его стандартный вывод становится артефактом.", + "customCommandRequired": "Введите команду сброса для пользовательского метода.", + "advanced": "Расширенные параметры", + "summaryTitle": "Резюме", + "summaryMethod": "Метод", + "summaryScheduleManual": "Только вручную", + "summaryLogical": "Дамп {label}", + "summaryVolume": "Моментальный снимок объема", + "summaryCustom": "Пользовательская команда", + "retentionUnlimited": "Неограниченный", + "keepN": "сохранить {n}", + "olderThanN": "Крышка {n}d" + } + }, + "cloud": { + "connectionGate": { + "reconnect": "Повторно подключите облако Openship", + "deployedOn": "Этот проект развернут в облаке Openship", + "sessionMissing": "У вас отсутствует облачный сеанс Openship. Подключитесь для управления развертываниями, просмотра журналов и доступа к элементам управления временем выполнения {name}.", + "thisProject": "этот проект", + "connecting": "Связывающий…", + "connect": "Подключитесь к облаку Openship", + "readOnlyNote": "Вы по-прежнему можете просматривать эту страницу в режиме только для чтения, даже если вы отключены от сети." + } + }, + "integrations": { + "githubPermission": { + "title": "Подключитесь к GitHub", + "subtitle": "Выберите уровень доступа к хранилищу", + "intro": "Выберите, к каким репозиториям Openship может получить доступ. Вы можете изменить это позже в настройках вашего GitHub.", + "publicTitle": "Только публичные репозитории", + "publicDesc": "Доступ к вашим общедоступным репозиториям. Идеально подходит для проектов с открытым исходным кодом.", + "publicItem1": "Чтение данных общедоступного хранилища", + "publicItem2": "Развертывание общедоступных репозиториев", + "publicItem3": "Создавайте веб-узлы для общедоступных репозиториев", + "allTitle": "Публичные и частные репозитории", + "allDesc": "Полный доступ ко всем вашим репозиториям. Требуется для частных проектов.", + "allItem1": "Чтение общедоступных и частных данных репозитория", + "allItem2": "Разверните любой репозиторий", + "allItem3": "Создайте веб-ссылки для всех репозиториев", + "allItem4": "Доступ к репозиториям организации", + "noteLabel": "Примечание:", + "noteText": "Вы можете отозвать доступ в любое время в настройках GitHub в разделе Приложения → Авторизованные приложения OAuth.", + "cancel": "Отменить", + "connecting": "Связывающий...", + "connect": "Подключитесь к GitHub" + } + }, + "permissions": { + "resourcePicker": { + "failedLoadResources": "Не удалось загрузить ресурсы", + "searchPlaceholder": "Выполните поиск {type}...", + "allResources": "Все {type}", + "noMatch": "Ни один ресурс не соответствует вашему запросу.", + "noResourcesYet": "В этой организации пока нет {type}.", + "selectedSummaryOne": "Ресурс {count} выбран для всех типов.", + "selectedSummaryOther": "Ресурсы {count}, выбранные для всех типов.", + "wildcard": "подстановочный знак", + "coveredByAll": "охваченный всеми", + "failedLoadOrgs": "Не удалось загрузить файлы GitHub orgs", + "failedLoadRepos": "Не удалось загрузить репозитории для {login}", + "noOrgs": "Ни одна организация на GitHub не подключена.", + "collapse": "Коллапс", + "expand": "Расширять", + "entireOrg": "вся организация", + "repoCountOne": "{count} репозиторий", + "repoCountOther": "{count} репозитории", + "coveredByOrg": "Покрывается за счет вышеуказанного гранта для всей организации.", + "noRepos": "Никаких хранилищ.", + "searchRepos": "Поиск репозиториев…" + }, + "sourceAccess": { + "title": "Доступ к источнику", + "subtitle": "Что этот токен может считывать из {repo}", + "tierDeploy": "Только для развертывания", + "tierDeployHint": "Метаданные, ветви и обнаружение сборки. Содержимое файла отсутствует — это значение по умолчанию.", + "tierContent": "Чтение файлов", + "tierContentHint": "Прочитайте содержимое файла. Ограничьтесь указанными ниже путями или оставьте все поля пустыми.", + "tierWrite": "Читать и писать", + "tierWriteHint": "Также изменяйте файлы. Требуется разрешение на запись в хранилище.", + "readPathsLabel": "Читаемые пути", + "writePathsLabel": "Пути, доступные для записи", + "wholeRepo": "Всё", + "addPathPlaceholder": "src/** или package.json", + "addPath": "Добавь", + "removePath": "Удалить {path}", + "errorInvalidPath": "Недопустимый шаблон. Используйте src/** или путь к файлу; .. Абсолютные пути недопустимы.", + "errorDuplicatePath": "Этот шаблон уже указан в списке.", + "problemWriteNeedsPermission": "Для доступа на запись требуется разрешение на запись в хранилище.", + "summaryTitle": "Этот грант позволяет", + "summaryDeployOnly": "Развертывание и проверка. Содержимое файла невозможно прочитать.", + "summaryReadWholeRepo": "Читаю каждый файл.", + "summaryReadScoped": "Только для чтения: {paths}", + "summaryWriteWholeRepo": "Запись любого файла.", + "summaryWriteScoped": "Только запись: {paths}", + "summaryCloneAllowed": "Клонируйте токены, чтобы локальные сборки работали.", + "summaryCloneBlocked": "Никаких токенов клонирования — клон не может быть ограничен путями, поэтому локальные сборки работать не будут.", + "apply": "Применять", + "cancel": "Отменить", + "subtitleAccount": "Что этот токен может считывать из каждого репозитория под {repo}", + "searchPaths": "Поиск файлов и папок…", + "treeLoading": "Загрузка репозитория…", + "treeEmpty": "Это хранилище выглядит пустым.", + "treeNoMatch": "Ни один файл или папка не совпадают.", + "treeError": "Не удалось загрузить дерево репозитория.", + "treeCovered": "{path} уже подпадает под действие более широкого правила, приведенного выше.", + "browseIn": "Просматривать", + "appliesToEveryRepo": "Пути применяются к каждому репозиторию под этой учетной записью.", + "selectedCount": "Выбран {count}", + "clearPaths": "Всё", + "advancedPattern": "Или добавить узор", + "assigningTo": "Присвоение", + "surfaceRead": "Читаемый", + "surfaceWrite": "Доступный для записи", + "buttonHint": "Выберите, какие файлы может читать этот грант", + "searchRepos": "Поиск по репозиториям…", + "noRepoMatch": "Ни одно хранилище не совпадает." + } + }, + "routing": { + "domainSwitcher": { + "notConfigured": "Не настроен", + "selectDomain": "Выберите домен", + "allDomains": "Все домены" + }, + "publicEndpoints": { + "mappedToPort": "Подключен к порту {port}.", + "noPortYet": "Порт еще не выбран.", + "mappedTo": "Сопоставлен с {path}.", + "exposedPort": "Открытый порт", + "staticPath": "Статический путь", + "auto": "Авто", + "domain": "Домен", + "domainsRouted": "Домены {count}, подключенные к этому приложению.", + "accessibleWhere": "Где будет доступен ваш сайт", + "addDomain": "Добавить домен", + "primaryDomain": "Основной домен", + "domainN": "Домен {n}", + "remove": "Удалять" + }, + "configEditor": { + "remove": "Удалять", + "removeHeader": "Удалить заголовок", + "add": "Добавь", + "addHeader": "Добавить заголовок", + "rewrites": "Переписывает", + "rewritesHint": "Используйте другой путь/серверную часть без изменения URL (например, /api/(.*) → серверная часть).", + "redirects": "Перенаправляет", + "redirectsHint": "HTTP-перенаправление (301/308 постоянное, остальное 307).", + "headers": "Заголовки", + "headersHint": "Добавлены заголовки ответов для сопоставления путей.", + "permanent": "постоянный", + "cleanUrls": "Чистые URL-адреса", + "cleanUrlsHint": "(strip .html)", + "trailingSlash": "Завершающая косая черта", + "proxyLimits": "Ограничения на запросы", + "proxyLimitsHint": "Размер загружаемого файла и время ожидания. Если оставить поле пустым, то будут применяться настройки прокси—сервера по умолчанию - загрузка 1 МБ и время ожидания 60 секунд.", + "maxBodySize": "Максимальный размер загружаемого файла", + "maxBodySizeHint": "например, 25 миллионов. Запросы большего размера отклоняются с помощью 413. По умолчанию 1 миллион.", + "readTimeout": "Время ожидания чтения", + "readTimeoutHint": "например, 300 секунд. Как долго нужно ждать ответа приложения. По умолчанию 60 секунд.", + "sendTimeout": "Время ожидания отправки", + "sendTimeoutHint": "например, 300 секунд. Как долго нужно ждать отправки в приложение. По умолчанию 60 секунд.", + "bodyTimeout": "Время ожидания загрузки", + "bodyTimeoutHint": "например, 300 секунд. Увеличьте это значение для больших загрузок, иначе они остановятся в середине передачи. По умолчанию 60 секунд.", + "proxyBuffering": "Буферные ответы", + "proxyBufferingHint": "(отключить для потоковой передачи / SSE)", + "gzip": "Сжатие ответов", + "gzipHint": "(текст в формате gzip, JSON, JS-файлы, CSS)", + "proxyGroups": { + "body": "Тело запроса", + "timeouts": "Тайм-ауты восходящего потока", + "buffering": "Буферизация ответов", + "compression": "Компрессия", + "headers": "Заголовки и протокол", + "upstreamTls": "TLS для доступа к приложению" + }, + "proxyInherit": "nginx по умолчанию", + "proxyNotSet": "не установлен", + "proxyLiveLabel": "Порция:", + "proxyLiveVaries": "зависит от хостинга", + "proxyDrift": "отличается от сохраненного", + "proxyDriftSummary": "Ребро обслуживает разные значения для:", + "proxyAdoptLive": "Примите жизненные ценности", + "proxyLiveUnavailable": "Не удалось прочитать текущую конфигурацию с сервера этого проекта.", + "proxyLiveSource": "Читать из:", + "proxyRefreshLive": "Перечитайте текущую конфигурацию" + }, + "settingsCard": { + "recordLabels": { + "CNAME": "Направляет трафик через пограничную сеть", + "A": "Указывает на IP-адрес вашего сервера", + "TXT": "Проверяет право собственности на домен" + }, + "publiclyExposed": "Публично разоблаченный", + "internalOnly": "Только внутренний", + "freeSubdomain": "Свободный поддомен", + "free": "Свободный", + "customDomain": "Пользовательский домен", + "custom": "Обычай", + "save": "Сохранить", + "checkingDns": "Проверка DNS…", + "addRecordHint": "Добавьте записи {primary} и {txt}", + "viewRecords": "Просмотр записей", + "redirectTo": "Перенаправлять", + "redirectServeApp": "Ознакомьтесь с приложением здесь", + "redirectToHost": "→ {hostname}", + "redirectPermanent": "301 постоянный", + "redirectTemporary": "302 временный", + "exposedPort": "Открытый порт", + "staticPath": "Статический путь", + "staticPathHint": "Используйте файлы из этого подкаталога в выходных данных сборки. Используйте {path} для корневых выходных данных.", + "dnsConfiguration": "Конфигурация DNS", + "addRecordsFor": "Добавьте эти записи для {hostname}", + "nameHost": "Имя / Хост", + "valueTarget": "Ценность / Цель", + "dnsHintSelfhosted": "Добавьте запись A, указывающую на IP-адрес вашего сервера, затем запись TXT для проверки.", + "dnsHintCloud": "Добавьте запись CNAME для маршрутизации, затем запись TXT для проверки.", + "dnsPropagation": "Изменение DNS может занять до 48 часов." + } + }, + "updates": { + "severity": { + "critical": "Критический", + "recommended": "Рекомендуемый", + "info": "Консультативный" + }, + "viewChangelog": "Просмотр списка изменений", + "available": "доступен", + "youreOn": "· вы находитесь на {version}", + "rerunInstall": "Повторно запустите установку, чтобы обновить свой автономный сервер.", + "updateNow": "Обновите сейчас", + "downloading": "Загрузка Openship {version}", + "installing": "Установка — Openship перезапустится", + "updateFailed": "Не удалось выполнить обновление", + "retry": "Повторить попытку", + "changelog": "Журнал изменений", + "updatedTo": "Обновлено до Openship {version}", + "seeChanges": "Посмотрите, что изменилось в этом выпуске.", + "onLatest": "Вы используете последнюю версию.", + "whatsNew": "Что нового", + "whatsNewIn": "Что нового в {version}", + "close": "Закрывать", + "noNotes": "Никаких примечаний к выпуску этой версии нет.", + "viewOnGithub": "Посмотреть на GitHub", + "dismiss": "Увольнять" + } +} diff --git a/docs/i18n/README.ru.md b/docs/i18n/README.ru.md new file mode 100644 index 000000000..d7db80427 --- /dev/null +++ b/docs/i18n/README.ru.md @@ -0,0 +1,253 @@ +

Openship

+ +

+ Платформа развертывания с открытым исходным кодом и возможностью селф-хостинга со встроенным CI/CD.
+ Укажите репозиторий — Openship соберет, доставит, настроит маршрутизацию и TLS-терминацию для приложения. Управляйте через десктопное приложение, веб-панель или CLI. +

+ +

+ + Trendshift + +

+ +

+ npm version + License + Website +

+ +

+ Быстрый старт · + Как это работает · + Интерфейсы · + Документация · + Участие в разработке +

+ +

+ English + العربية + 简体中文 + Español + Français + 日本語 + Português + Deutsch + Türkçe + 한국어 + Русский +

+ +

+ Панель управления Openship +

+ +--- + +## Quick Start + +Сначала нужно принять одно решение: **как запускать сам Openship** (control plane). Всё остальное после этого одинаково. + +| Ваша ситуация | Запуск Openship | Где запускаются приложения | +|---|---|---| +| **Один пользователь, один сервер, без администрирования** | **Десктопное приложение** | Сервер, к которому подключаетесь по SSH, или Openship Cloud | +| **Команда — или нужен push-to-deploy / хостинг на своем сервере** | **Self-hosted сервер** (`openship up`) | На том же сервере (режим Compose) или на удаленном сервере / Cloud (режим bare) | +| **Не хотите ничего администрировать** | **Openship Cloud** | Управляемые песочницы, нулевая настройка | + +> [!TIP] +> **Один пользователь? Используйте десктопное приложение.** Оно запускает control plane Openship на вашем компьютере *только пока приложение открыто* — ничего не остается запущенным на сервере и не публикуется наружу. Постоянно работающий сервер нужен только если требуется **push-to-deploy (CI/CD)**, **командный доступ** или **хостинг приложений на этом же сервере** — то есть задачи, требующие публичного и всегда доступного эндпоинта. + +### Solo — десктопное приложение + +Control plane работает локально и управляет вашими серверами по SSH. Без логинов, без терминала, без публичных портов — скачал, открыл, готово: + +| Платформа | Скачать | +|---|---| +| **macOS** (Apple Silicon) | [Openship-arm64.dmg](https://github.com/oblien/openship/releases/latest/download/Openship-arm64.dmg) | +| **macOS** (Intel) | [Openship-x64.dmg](https://github.com/oblien/openship/releases/latest/download/Openship-x64.dmg) | +| **Windows** | [Openship-win32-x64.zip](https://github.com/oblien/openship/releases/latest/download/Openship-win32-x64.zip) | +| **Linux** | [Openship.AppImage](https://github.com/oblien/openship/releases/latest/download/Openship.AppImage) | + +Linux: `chmod +x Openship.AppImage && ./Openship.AppImage`. У вас уже есть CLI? `openship install` скачает и запустит его. Ссылки всегда ведут на самый свежий релиз. + +Из десктопного приложения вы подключаете сервер (SSH) или Openship Cloud и деплоите на него — само приложение не хостит публичные приложения на вашем ноутбуке. + +### Команда / всегда онлайн — self-hosted сервер + +Установите CLI (содержит API + панель управления) и запустите **`openship`** — интерактивный мастер создаст первого администратора, привяжет домен и установит Openship как системную службу. Запускайте снова в любое время для управления инстансом. + +```bash +curl -fsSL https://get.openship.io | sh # установка (или: npm i -g openship — требуется Node 22+) +openship # пошаговая настройка, затем панель управления +``` + +Скрипт установки содержит собственную Node.js, если системная версия ниже 22; установка через менеджер пакетов использует существующий узел Node. + +Для CI / серверов без GUI пропустите мастер и запустите `openship up` напрямую: + +```bash +openship up # установка + запуск в фоновом режиме (автозапуск + автоперезапуск) +openship up --public-url https://openship.example.com # + запуск панели управления на вашем домене (edge + TLS настроены) +``` + +**`openship up` автоматически выбирает режим работы:** + +- **Linux с Docker → режим Compose** (по умолчанию). Запускает полный стек — Postgres, Redis, API, панель управления и контейнеризованный **OpenResty edge на порту :80/:443** из официальных образов. В этом режиме **приложения хостятся на том же сервере** с автоматической настройкой доменов и SSL-сертификатов Let's Encrypt. Принудительный запуск: `--compose`. +- **Остальные системы → режим bare** (macOS, Windows или Linux без Docker). Один легкий процесс со встроенной базой данных — постоянно работающий control plane, который **деплоит приложения на внешний сервер (SSH) или в Cloud**, аналогично десктопному приложению, но в режиме 24/7 и с обязательной авторизацией. Принудительный запуск: `--bare`. + +Self-hosted инстанс **всегда требует авторизации** (аккаунт администратора создается при первичной настройке). `openship open` открывает панель управления · `openship stop` останавливает службу · `openship update` обновляет версию · `openship up --foreground` запускает в интерактивном режиме. + +> **Предпросмотр нерелизных сборок (dev).** Чтобы запустить CLI, собранный напрямую из исходников (ветка, тег или `main`), установите dev-сборку: +> +> ```bash +> curl -fsSL https://get.openship.io/dev | sh # main (по умолчанию) +> curl -fsSL https://get.openship.io/dev | OPENSHIP_REF=dev sh # ветка/тег (переменная передается в sh) +> openship-dev # тот же CLI, собранный из исходников +> openship-dev update # получить последние исходники + пересобрать +> ``` +> +> Она устанавливается как **отдельная команда `openship-dev`** с изолированной рабочей директорией (`~/.openship-dev`) и отдельной службой автозапуска, поэтому боевой `openship` и его данные останутся нетронутыми. Требуются Bun + git; это неверифицированная dev-сборка. + +**Деплой проекта:** + +```bash +cd your-project +openship init # привязать директорию к проекту +openship deploy +``` + +Полное руководство по серверу и справка по CLI: **[openship.io/docs](https://openship.io/docs)**. + +
+Автодополнение команд (bash/zsh/fish) + +Два способа включить автодополнение по кнопке Tab для `openship`: + +| | Настройка | Особенности | +|---|---|---| +| **Статический файл** (рекомендуется) | `openship completion > ` | Мгновенный запуск оболочки. Обновляйте после выхода новых версий CLI. | +| **Динамический запуск** | добавьте `source <(openship completion )` в конфиг оболочки | Всегда соответствует текущей версии CLI. Добавляет небольшую задержку при открытии нового терминала. | + +**Статический файл:** +```bash +openship completion bash > /etc/bash_completion.d/openship +openship completion zsh > ~/.zsh/completions/_openship +openship completion fish > ~/.config/fish/completions/openship.fish +``` +Откройте новый терминал — готово. + +**Динамический запуск** (пример для zsh): +```bash +echo 'source <(openship completion zsh)' >> ~/.zshrc +``` + +
+ +
+Self-host через чистый Docker Compose (без CLI) + +Self-hosted стек находится в **`docker/docker-compose.yml`** и **скачивает** готовые образы из GitHub Container Registry (`ghcr.io/oblien/*`) — без сборки и компиляции. Запустите из корня репозитория: + +```bash +git clone https://github.com/oblien/openship.git && cd openship +cp .env.example .env # отредактируйте конфиг +docker compose --env-file .env -f docker/docker-compose.yml up -d +``` + +Стек состоит из **postgres + redis + api + dashboard + edge**. Компонент `edge` — это OpenResty на **:80/:443** в контейнере (`network_mode: host`) для маршрутизации и Let's Encrypt. **Только для Linux** (из-за host networking); на macOS/Windows используйте `openship up` (bare). Контейнер `api` монтирует хостовый сокет Docker для сборки и запуска ваших приложений — запускайте только на доверенном сервере. + +**Обновление:** зафиксируйте `OPENSHIP_VERSION` в `.env`, затем `docker compose --env-file .env -f docker/docker-compose.yml pull && … up -d`. Команда `openship update` обслуживает только стек, установленный через CLI. **Сборка из исходников:** добавьте `-f docker/docker-compose.build.yml … up -d --build`. + +**Операции на хосте** (перехват портов `:80`/`:443`, почтовый движок, сканирование портов) требуют каналов container→host SSH, которые `openship up` пробрасывает автоматически. Для ручного метода следует выполнить 5 шагов из `.env.example` в разделе *Host operations from the container*. Описание возможных ошибок: [Troubleshooting → Host control channel](https://openship.io/docs/troubleshooting/host-channel). + +> Файл `docker-compose.yml` в **корне** репозитория — это другой файл: он предназначен для SaaS / сборки **control plane** из исходников. Он **не** подходит для селф-хостинга ваших приложений — используйте `docker/docker-compose.yml` или `openship up`. + +
+ +--- + +## How It Works + +Укажите Openship источник — **репозиторий GitHub**, **локальную папку** или **готовый артефакт** — и он выполнит пайплайн от начала до конца: + +1. **Определение.** Сканирует `package.json`, конфиг фреймворка, lock-файлы, `docker-compose.yml` или `openship.json` для определения стека, менеджера пакетов, команд сборки/запуска и портов. Конфигурационные файлы не обязательны; `openship.json` нужен только если хотите переопределить автоматические настройки. +2. **Сборка.** На целевом сервере или локально в Docker-образ или bare-релиз. Итоговый конфиг фиксируется в снапшоте, чтобы повторные деплои и откаты воспроизводились *абсолютно идентично*. +3. **Запуск.** В контейнере (доступном только на loopback-интерфейсе — без открытых наружу портов) или как процесс под управлением супервизора. +4. **Маршрутизация и безопасность.** OpenResty edge создает vhost обратного прокси для вашего доменного имени и получает SSL-сертификат Let's Encrypt (HTTP-01). Так как маршрутизация и TLS настраиваются *после* успешного запуска приложения, проблемы с DNS или сертификатами не приводят к падению приложения или сбою деплоя. +5. **Push-to-deploy.** Вебхук GitHub перезапускает пайплайн при каждом пуше в отслеживаемую ветку — с пересборкой только тех сервисов, которые реально изменились. + +Базы данных, домены, SSL, CDN, почта и бэкапы управляются из единого интерфейса. + +--- + +## Interfaces + +Три способа управления одним бэкендом: + +- **Десктопное приложение** — удобный GUI, логи в реальном времени, всё в один клик. Идеально для одного разработчика. +- **Веб-панель управления** — аналогичный UI в браузере, созданный для командной работы. +- **CLI** — для скриптов и CI/CD; также используется для установки и администрирования self-hosted инстанса. + +Для автоматизации доступны **MCP-эндпоинт** (для ИИ-агентов) и **REST API**. В качестве MCP-инструментов экспортируются только явно разрешенные маршруты с полной проверкой прав доступа. Документация доступна на [openship.io/docs](https://openship.io/docs). + +> [!NOTE] +> Документация активно дополняется. Если вы нашли неточность или недостающую информацию, мы рады вашим [пул-реквестам](../../CONTRIBUTING.md). + +--- + +## Features + +| | | +|---|---| +| **Встроенный CI/CD** | Push-to-deploy, preview-окружения, staging/prod потоки, откаты | +| **Любой стек** | Node, Python, Go, Rust, PHP, Ruby, Java, .NET, Docker, монорепозитории | +| **Полноценный бэкенд** | Postgres, MySQL, MongoDB, Redis, воркеры, WebSockets, S3-хранилище | +| **Домены и SSL** | Автоматический Let's Encrypt, wildcard-домены, неограниченное число доменов, автопродление | +| **CDN** | Кэширование на edge, HTTP/3, Brotli-сжатие, мгновенный сброс кэша | +| **Почтовый сервер** | Встроенный SMTP с DKIM/SPF/DMARC — без необходимости в Mailgun или SES | +| **Резервное копирование** | По расписанию, базы данных + тома, восстановление в один клик, экспорт | +| **Мониторинг в реальном времени** | Логи сборки, метрики контейнеров, география посетителей — [~1.4 мкс на запрос, 0 записей в БД на запрос](../../docs/monitoring.md) | +| **Масштабирование** | Автомасштабирование в cloud, multi-node режим на self-hosted | +| **Переносимость** | Стандартные Docker-контейнеры — свободный перенос между провайдерами | +| **Docker Compose** | Деплой существующих compose-файлов без изменений | + +--- + +## Deploy Anywhere + +- **Openship Cloud** — управляемый хостинг, автомасштабирование, нулевая настройка +- **Любой VPS** — Hetzner, DigitalOcean, Linode, OVH и другие +- **Выделенные сервера** — bare metal, colocation, homelab +- **Мульти-серверная инфраструктура** — распределение нагрузки по машинам + +Единый интерфейс независимо от места деплоя. + +--- + +## Status + +Готово к продакшену, активно развивается. Self-hosting **бесплатен** (без скрытых платежей). + +**В ближайших релизах:** multi-node кластеры, UI для балансировки нагрузки, приватные сети, расширенный мониторинг и визуальные CI/CD пайплайны. + +--- + +## Contributing + +Подробнее в файле [CONTRIBUTING.md](../../CONTRIBUTING.md). + +--- + +## Security + +Нашли уязвимость? Пожалуйста, сообщите нам **конфиденциально** (не создавайте публичные issue или PR). + +- **Отправить отчет (предпочтительно):** [Сообщить об уязвимости](https://github.com/oblien/openship/security/advisories/new) — приватный GitHub advisory. +- Область охвата и политика раскрытия: [SECURITY.md](../../SECURITY.md). + +--- + +## License + +Openship — это ПО с **открытым исходным кодом** под лицензией [Apache License 2.0](../../LICENSE).