Files
glchat/web/src/i18n/locales/ru.json
T
grendervill 1b1a679827 feat(api): ручки Фаз(ы) 1 — профиль, серверы, роли, админ инстанса
REST-слой Фазы 1 на huma (OpenAPI 3.1 генерируется из кода):

- профиль: GET/PATCH /users/@me, смена пароля со step-up, публичный профиль,
  завершение онбординга (новая миграция 00003 с onboarding_completed_at);
- серверы: создание/изменение/удаление, join/leave, список серверов
  пользователя, журнал действий;
- комнаты: список с учётом прав, создание/изменение/удаление;
- участники: список с профилями и ролями, никнейм, тайм-аут, исключение;
- роли: CRUD, выдача/снятие с проверкой иерархии и запретом выдачи прав выше
  собственных;
- админ инстанса: публичная информация, настройки, серверы, пользователи,
  аудит, выдача прав администратора со step-up; обход лимитов фиксируется в
  аудите отдельной записью limits.bypass;
- движок прав: участие в сервере стало обязательным условием (IsMember),
  не участник не получает прав роли @user; калькулятор прав общий для API и
  Gateway, инвалидация кэша после изменений;
- Gateway: браузерный клиент аутентифицируется cookie на рукопожатии, IDENTIFY
  без токена использует её; события GUILD/CHANNEL/MEMBER/ROLE рассылаются из
  ручек, USER_UPDATE — адресно;
- ошибки huma отдаются в едином конверте {"error":{"code","message"}}.

Тесты: 8 сценариев API (профиль, жизненный цикл сервера и права, лимиты и
обход админом, иерархия ролей, тайм-аут, скрытие комнаты оверрайдом,
членство в движке прав, cookie-идентификация Gateway).
2026-09-19 21:50:06 +03:00

335 lines
17 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"app": {
"name": "glchat",
"tagline": "Self-hosted общение: текст, голос, видео",
"skipToContent": "Перейти к содержимому"
},
"status": {
"title": "Фундамент развёрнут",
"description": "Сервер отвечает, база данных в режиме WAL, миграции применены. Функции общения появятся в следующих фазах.",
"connecting": "Проверяем состояние сервера…",
"instance": "Инстанс",
"version": "Версия",
"apiVersion": "Версия API",
"schemaReady": "База данных",
"schemaOk": "готова",
"maxUpload": "Максимальный размер загрузки",
"checks": "Проверки",
"retry": "Повторить",
"back": "Назад",
"users": "Пользователей",
"guilds": "Серверов",
"registration": "Регистрация"
},
"health": {
"online": "Сервер доступен",
"offline": "Сервер недоступен"
},
"errors": {
"network.unreachable": "Сервер не отвечает. Проверьте соединение и повторите попытку.",
"network.aborted": "Запрос отменён.",
"instance.not_ready": "Инстанс ещё запускается. Повторите через несколько секунд.",
"internal.error": "Внутренняя ошибка сервера.",
"not_found": "Запрашиваемый ресурс не найден.",
"unknown": "Неизвестная ошибка ({{code}}).",
"auth.2fa_required": "Введите код двухфакторной аутентификации из приложения.",
"auth.totp_invalid": "Неверный код двухфакторной аутентификации.",
"auth.invalid_credentials": "Неверная почта или пароль.",
"auth.step_up_required": "Подтвердите личность: введите пароль заново.",
"auth.guild_limit_reached": "Достигнут лимит серверов на этом инстансе.",
"auth.session_invalid": "Сессия истекла. Войдите снова.",
"auth.unauthorized": "Требуется вход в систему.",
"auth.registration_disabled": "Регистрация на этом инстансе выключена.",
"auth.username_taken": "Такое имя пользователя уже занято.",
"auth.email_taken": "Такая почта уже зарегистрирована.",
"auth.weak_password": "Пароль слишком простой. Используйте не менее 8 символов.",
"auth.too_many_attempts": "Слишком много попыток. Попробуйте позже.",
"permissions.denied": "Недостаточно прав для этого действия.",
"instance.admin_required": "Действие доступно только администратору инстанса.",
"guild.not_found": "Сервер не найден.",
"guild.member_limit_reached": "На сервере достигнут лимит участников.",
"channel.not_found": "Комната не найдена.",
"validation.failed": "Проверьте заполненные поля.",
"rate.limited": "Слишком много запросов. Подождите немного."
},
"theme": {
"switchToLight": "Светлая тема",
"switchToDark": "Тёмная тема",
"label": "Тема",
"dark": "Тёмная",
"light": "Светлая"
},
"language": {
"label": "Язык",
"ru": "Русский",
"en": "English"
},
"common": {
"loading": "Загрузка…",
"retry": "Повторить",
"cancel": "Отмена",
"close": "Закрыть",
"save": "Сохранить",
"saving": "Сохраняем…",
"create": "Создать",
"creating": "Создаём…",
"join": "Присоединиться",
"leave": "Покинуть",
"back": "Назад",
"copy": "Скопировать",
"copied": "Скопировано",
"yes": "Да",
"no": "Нет",
"optional": "необязательно",
"dismiss": "Скрыть"
},
"footer": {
"source": "Исходный код",
"license": "AGPL-3.0"
},
"auth": {
"login": {
"title": "Вход",
"subtitle": "Войдите, чтобы продолжить общение",
"email": "Почта",
"emailPlaceholder": "you@example.com",
"password": "Пароль",
"totp": "Код 2FA",
"totpHint": "Шесть цифр из приложения-аутентификатора.",
"submit": "Войти",
"submitting": "Входим…",
"noAccount": "Ещё нет аккаунта?",
"registerLink": "Зарегистрироваться",
"forgot": "Пароль забыт? Обратитесь к администратору инстанса.",
"instanceStatus": "Состояние инстанса",
"registrationDisabled": "Регистрация на этом инстансе выключена администратором."
},
"register": {
"title": "Регистрация",
"subtitle": "Создайте аккаунт на инстансе {{instance}}",
"username": "Имя пользователя",
"usernameHint": "3–32 символа: латиница, цифры, «_» и «-».",
"displayName": "Отображаемое имя",
"email": "Почта",
"password": "Пароль",
"passwordHint": "Не менее 8 символов.",
"requirements": "Требования к паролю: {{list}}",
"requirementLength": "не менее 8 символов",
"requirementLetter": "хотя бы одна буква",
"requirementDigit": "хотя бы одна цифра",
"submit": "Создать аккаунт",
"submitting": "Создаём аккаунт…",
"haveAccount": "Уже есть аккаунт?",
"loginLink": "Войти",
"disabledTitle": "Регистрация закрыта",
"disabledBody": "Администратор инстанса выключил самостоятельную регистрацию. Попросите приглашение или обратитесь к администратору."
},
"validation": {
"usernameFormat": "Имя пользователя: 3–32 символа, латиница, цифры, «_» или «-».",
"usernameRequired": "Укажите имя пользователя.",
"displayNameRequired": "Укажите отображаемое имя.",
"emailInvalid": "Укажите корректный адрес почты.",
"passwordShort": "Пароль должен быть не короче 8 символов.",
"passwordLetter": "Добавьте в пароль хотя бы одну букву.",
"passwordDigit": "Добавьте в пароль хотя бы одну цифру.",
"passwordMismatch": "Пароли не совпадают."
}
},
"onboarding": {
"title": "Добро пожаловать в glchat",
"greeting": "Привет, {{name}}!",
"subtitle": "Пара шагов — и можно общаться.",
"displayName": "Как вас показывать?",
"displayNameHint": "Это имя видят другие участники.",
"bio": "Расскажи о себе",
"bioPlaceholder": "Чем занимаетесь, что интересно…",
"language": "Язык интерфейса",
"theme": "Тема",
"start": "Начать",
"starting": "Готовим рабочее пространство…",
"skip": "Пропустить и начать",
"note": "Позже всё это можно изменить в настройках."
},
"guilds": {
"railLabel": "Серверы",
"listLabel": "Список серверов",
"add": "Создать сервер",
"addShort": "Создать сервер",
"create": {
"title": "Создать сервер",
"name": "Название сервера",
"namePlaceholder": "Например, «Друзья»",
"hint": "Название можно изменить позже в настройках сервера.",
"submit": "Создать",
"limit": "На инстансе можно создать не более {{count}} серверов."
},
"empty": {
"title": "Пока нет ни одного сервера",
"body": "Присоединитесь к главному серверу инстанса или создайте свой.",
"joinMain": "Присоединиться к главному серверу",
"joining": "Присоединяемся…",
"noMain": "Главный сервер на инстансе не настроен — создайте свой."
},
"leave": "Покинуть сервер",
"leaveConfirm": "Покинуть сервер «{{name}}»?",
"switchTo": "Открыть сервер {{name}}"
},
"channels": {
"title": "Комнаты",
"text": "Текстовые комнаты",
"voice": "Голосовые комнаты",
"category": "Категория",
"empty": "В этом сервере пока нет видимых комнат.",
"select": "Открыть комнату {{name}}",
"add": "Создать комнату",
"create": {
"title": "Новая комната",
"name": "Название комнаты",
"namePlaceholder": "например, общий-чат",
"type": "Тип комнаты",
"typeText": "Текстовая",
"typeVoice": "Голосовая",
"parent": "Категория",
"noParent": "Без категории",
"submit": "Создать"
},
"chatPlaceholder": {
"title": "Чат появится в Фазе 2",
"body": "Комната «{{name}}» уже доступна. Отправка сообщений и голосовые каналы появятся в следующей фазе."
},
"voicePlaceholder": {
"title": "Голосовая комната",
"body": "Подключение к голосу появится в следующих фазах."
},
"noSelection": {
"title": "Выберите комнату",
"body": "Слева — список серверов и комнат. Выберите комнату, чтобы открыть её."
},
"notInGuild": {
"title": "Сервер недоступен",
"body": "Похоже, вы не состоите в этом сервере."
}
},
"user": {
"panelLabel": "Панель пользователя",
"settings": "Настройки пользователя",
"logout": "Выйти",
"loggingOut": "Выходим…",
"statusLabel": "Статус: {{status}}",
"copyId": "Скопировать ID",
"status": {
"online": "В сети",
"idle": "Неактивен",
"dnd": "Не беспокоить",
"invisible": "Невидимый",
"offline": "Не в сети"
}
},
"gateway": {
"label": "Соединение",
"status": {
"idle": "Не подключено",
"connecting": "Подключаемся…",
"connected": "Подключено",
"reconnecting": "Переподключение…",
"disconnected": "Соединение потеряно"
},
"invalidated": "Сессия закрыта сервером. Войдите снова."
},
"settings": {
"title": "Настройки",
"back": "В приложение",
"tabs": {
"label": "Разделы настроек",
"profile": "Профиль",
"security": "Безопасность",
"appearance": "Внешний вид",
"instance": "Инстанс"
},
"profile": {
"title": "Профиль",
"description": "Как вас видят другие участники.",
"displayName": "Отображаемое имя",
"bio": "О себе",
"bioPlaceholder": "Пара слов о себе",
"customStatus": "Своё состояние",
"customStatusPlaceholder": "Например, «Пишу код»",
"customStatusEmoji": "Эмодзи состояния",
"customStatusEmojiPlaceholder": "🚀",
"status": "Статус присутствия",
"locale": "Язык интерфейса",
"saved": "Профиль сохранён.",
"username": "Имя пользователя",
"userId": "ID пользователя",
"badges": "Значки",
"noBadges": "нет"
},
"security": {
"title": "Безопасность",
"description": "Пароль, активные сессии и двухфакторная аутентификация.",
"passwordTitle": "Смена пароля",
"currentPassword": "Текущий пароль",
"newPassword": "Новый пароль",
"confirmPassword": "Повторите новый пароль",
"submitPassword": "Сменить пароль",
"passwordChanged": "Пароль изменён.",
"stepUpTitle": "Подтвердите личность",
"stepUpBody": "Для этого действия сервер требует повторного ввода пароля{{totp}}.",
"stepUpTotp": " и кода 2FA",
"stepUpSubmit": "Подтвердить",
"stepUpSuccess": "Личность подтверждена.",
"stepUpExpired": "Подтверждение устарело, введите пароль заново.",
"stepUpPassword": "Ваш пароль",
"sessionsTitle": "Активные сессии",
"sessionsEmpty": "Активных сессий нет.",
"sessionCurrent": "текущая",
"sessionCreated": "Создана",
"sessionSeen": "Активность",
"sessionIp": "IP",
"sessionAgent": "Устройство",
"unknownAgent": "Неизвестное устройство",
"logoutAll": "Выйти на всех устройствах",
"logoutAllConfirm": "Завершить все сессии, включая текущую?",
"logoutAllDone": "Все сессии завершены.",
"twoFactorTitle": "Двухфакторная аутентификация",
"twoFactorEnabled": "2FA включена",
"twoFactorDisabled": "2FA выключена",
"twoFactorEnable": "Включить 2FA",
"twoFactorSetupHint": "Добавьте секрет в приложение-аутентификатор, затем введите шестизначный код.",
"twoFactorSecret": "Секрет",
"twoFactorUri": "Ссылка otpauth",
"twoFactorQrAlt": "QR-код для настройки 2FA",
"twoFactorQrUnavailable": "QR-код недоступен — добавьте секрет вручную.",
"twoFactorCode": "Код из приложения",
"twoFactorConfirm": "Включить",
"twoFactorEnabledDone": "2FA включена. Сохраните коды восстановления.",
"recoveryTitle": "Коды восстановления",
"recoveryHint": "Каждый код одноразовый. Они показываются только один раз.",
"recoveryCopyAll": "Скопировать все коды"
},
"appearance": {
"title": "Внешний вид",
"description": "Тема и язык интерфейса. Хранятся локально в браузере.",
"theme": "Тема",
"themeHint": "Тёмная тема включена по умолчанию.",
"language": "Язык",
"languageHint": "Русский — основной язык интерфейса."
},
"instance": {
"title": "Инстанс",
"description": "Только для администратора инстанса. Данные только для чтения.",
"notAdmin": "Раздел доступен только администратору инстанса.",
"settings": "Настройки инстанса",
"settingsEmpty": "Настройки не заданы.",
"guilds": "Серверы ({{count}})",
"guildsEmpty": "Серверов нет.",
"users": "Пользователи ({{count}})",
"usersEmpty": "Пользователей нет.",
"audit": "Журнал аудита (последние {{count}})",
"auditEmpty": "Записей нет.",
"memberCount": "{{count}} участн.", "adminBadge": "админ",
"mainBadge": "главный"
}
}
}