Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
<a href="docs/i18n/README.de.md"><img src="https://img.shields.io/badge/lang-Deutsch-555" alt="Deutsch" /></a>
<a href="docs/i18n/README.tr.md"><img src="https://img.shields.io/badge/lang-Türkçe-555" alt="Türkçe" /></a>
<a href="docs/i18n/README.ko.md"><img src="https://img.shields.io/badge/lang-한국어-555" alt="한국어" /></a>
<a href="docs/i18n/README.ru.md"><img src="https://img.shields.io/badge/lang-Русский-555" alt="Русский" /></a>
</p>

<p align="center">
Expand Down
6 changes: 4 additions & 2 deletions apps/dashboard/src/i18n/i18n-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ const MISSING_BASELINE: Record<string, number> = {
// 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.
//
Expand Down Expand Up @@ -176,7 +178,7 @@ const MISSING_BASELINE: Record<string, number> = {
};

/** 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());
Expand Down
2 changes: 1 addition & 1 deletion apps/dashboard/src/i18n/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
114 changes: 114 additions & 0 deletions apps/dashboard/src/i18n/locales/ru/auth.json
Original file line number Diff line number Diff line change
@@ -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": "Скрыть пароль"
}
29 changes: 29 additions & 0 deletions apps/dashboard/src/i18n/locales/ru/autoDns.json
Original file line number Diff line number Diff line change
@@ -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."
}
Loading