diff --git a/README.md b/README.md
index 2249273a5..c982ef42f 100644
--- a/README.md
+++ b/README.md
@@ -36,6 +36,7 @@
+
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.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Быстрый старт ·
+ Как это работает ·
+ Интерфейсы ·
+ Документация ·
+ Участие в разработке
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+---
+
+## 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).