// Russian primary copy. To add a string: // 1. add the key + RU value here (this file is the canonical key list — `en.ts` // and the `StringKey` type derive from it), // 2. add the same key + EN value in `en.ts`, // 3. consume via `t('key', { var: 'x' })` in components. // Interpolation uses `{name}` placeholders resolved against the second arg. // // The widget no longer renders a hero — that block lives in the host's // BotShellHero. Status is surfaced inline inside the relevant section. export const RU = { // --- Inline section status --------------------------------------------- 'status.unknown': 'Проверка статуса…', 'status.disconnected': 'WhatsApp не привязан', 'status.connected': 'WhatsApp привязан', 'status.connected-as': 'WhatsApp привязан как {handle}', 'status.logging-out': 'Завершение сеанса…', // QR-вход: после успешного скана мост стирает QR и переходит к // подтверждению линка. Это короткий промежуточный pill. 'status.qr-verifying': 'Проверяем вход…', // Pairing-code вход: после ввода кода в приложении ждём, пока WhatsApp // подтвердит линк. По времени совпадает с qr-verifying — секунды. 'status.pairing-verifying': 'Проверяем вход…', // --- Section headers --------------------------------------------------- 'card.login-qr.name': 'Войти по QR-коду', 'card.login-qr.desc': 'Отсканировать QR из мобильного приложения WhatsApp', // WA-эквивалент TG-шного «Войти по номеру». User flow по сути такой // же, как в Telegram: сабмит номера → бот выдаёт код → код вводится. // Отличие: в TG код вводится в виджет, в WA — в само приложение // WhatsApp. Имя кнопки одинаковое для consistency между виджетами. 'card.login-pairing.name': 'Войти по номеру', 'card.login-pairing.desc': 'Ввести номер и получить 8-символьный код для WhatsApp', 'card.refresh.aria': 'Обновить статус', 'card.refresh.label': 'Обновить статус', 'card.refresh.name': 'Обновить статус', 'card.refresh.desc': 'Перепроверить, привязан ли WhatsApp', 'card.refresh.in-flight': 'Проверяю…', // --- About panel ------------------------------------------------------- // WhatsApp-only Meta-ToS risk disclosure is folded into the About // modal as an amber callout at the top of the body. The AboutCard // itself carries `command-card warn` (amber border + amber name) // and a triangle warning glyph in the lead slot — instead of the // info-circle TG / Discord use — so the «риски» half of the hybrid // description («о работе и рисках») is visible at a glance before // the user opens the modal. TG / Discord get the plain «вход, // безопасность, исходный код» variant because they don't carry an // account-loss risk in the same way (Telegram user ToS doesn't // forbid third-party clients; Discord's restriction on self-bots // lives in developer policies, not user ToS proper). The amber // block keeps the unique WhatsApp framing without claiming anything // about TG / Discord by comparison. // // ToS reference for the body: https://www.whatsapp.com/legal/terms-of-service // section «Harm To WhatsApp Or Our Users» forbids «software or // APIs that function substantially the same as our Services» and // «accounts for our Services through unauthorized or automated // means». 'warning.title': 'Важно знать до подключения WhatsApp', 'warning.body-1': 'Mautrix-whatsapp подключает ваш аккаунт через тот же механизм связанных устройств, что и WhatsApp Web. Технически это стандартный API — но в отличие от других мессенджеров, условия использования WhatsApp прямо запрещают подключение через сторонние клиенты, и Meta может заблокировать аккаунт за это.', // Источник про запрет в ToS — даём юзеру возможность дойти до // оригинала самому, не доверять нам на слово. Кликается потому что // host-side iframe sandbox получил allow-popups (см. // src/app/features/bots/BotWidgetEmbed.ts). 'warning.tos-label': 'Условия использования WhatsApp:', 'warning.tos-url': 'https://www.whatsapp.com/legal/terms-of-service', 'card.about.name': 'Как работает WhatsApp-бот', // Hybrid copy: tells the user the modal carries BOTH the «как // работает» explainer AND the Meta-ToS risk disclosure. «нажмите, // чтобы прочесть» reinforces interactivity — the amber border + // warning triangle help but the explicit verb seals it. 'card.about.desc': 'Информация о работе и рисках — нажмите, чтобы прочесть', 'about.title': 'О боте WhatsApp', 'about.body-1': 'Этот бот подключает WhatsApp к Vojo. После входа личные чаты и группы из WhatsApp появятся в списке чатов Vojo, а ответы из приложения Vojo будут отправляться собеседникам как обычные сообщения в WhatsApp.', 'about.body-2': 'Для входа нужно мобильное приложение WhatsApp на телефоне с активным аккаунтом. Можно либо отсканировать QR-код через «Настройки → Связанные устройства → Привязать устройство», либо ввести 8-символьный код через «Настройки → Связанные устройства → Привязать с помощью номера телефона».', 'about.body-3': 'Подключение работает через open-source мост mautrix-whatsapp. Он создаёт WhatsApp-сессию на сервере Vojo и использует её для связи WhatsApp с вашим аккаунтом Vojo: получает сообщения из WhatsApp и отправляет ваши ответы обратно. WhatsApp-аккаунт продолжит работать на телефоне как обычно — мост подключается параллельно, как ещё одно связанное устройство.', 'about.github-label': 'Исходный код моста открыт на GitHub:', 'about.github-url': 'https://github.com/mautrix/whatsapp', 'about.body-4': 'Отозвать доступ можно в любой момент — кнопкой «Выйти из WhatsApp» здесь, либо в самом WhatsApp через «Настройки → Связанные устройства → Выйти со всех устройств».', 'about.close': 'Закрыть', 'about.aria-close': 'Закрыть «О боте»', // --- Phone form (pairing-code flow) ------------------------------------ 'auth-card.phone.title': 'Вход по коду из приложения', 'auth-card.phone.label': 'Номер телефона', 'auth-card.phone.placeholder': '+79991234567', // Подсказка, объясняющая что произойдёт после сабмита: мост создаст // 8-символьный код, который надо ввести в WhatsApp app. Пользователь // должен понимать, что код не SMS-OTP, а pairing-token. 'auth-card.phone.hint': 'Введите номер с кодом страны. После этого WhatsApp создаст 8-символьный код — его нужно будет ввести в приложении.', 'auth-card.phone.submit': 'Получить код', 'auth-card.phone.cooldown': 'Повтор через {seconds} сек', 'auth-card.phone.invalid': 'Похоже, номер ещё не полный или введён с ошибкой.', // --- Pairing-code form ------------------------------------------------- 'auth-card.pairing-code.title': 'Введите этот код в WhatsApp', 'auth-card.pairing-code.hint': 'Откройте WhatsApp на телефоне и введите этот код в форме «Связанные устройства → Привязать с помощью номера телефона».', 'auth-card.pairing-code.preparing': 'Готовим код…', 'auth-card.pairing-code.aria': 'Код для входа в WhatsApp. Введите его в приложении на телефоне.', 'auth-card.pairing-code.countdown': 'На ввод осталось {minutes}:{seconds}', 'auth-card.pairing-code.expired': 'Окно входа истекло. Нажмите «Отмена» и попробуйте снова.', 'auth-card.pairing-code.step-1': 'Откройте WhatsApp на телефоне.', 'auth-card.pairing-code.step-2': 'Перейдите в «Настройки → Связанные устройства».', 'auth-card.pairing-code.step-3': 'Нажмите «Привязать устройство → Привязать с помощью номера телефона».', 'auth-card.pairing-code.step-4': 'Введите этот код и подтвердите вход на телефоне.', // --- QR form ----------------------------------------------------------- 'auth-card.qr.title': 'Вход по QR-коду', 'auth-card.qr.hint': 'Откройте WhatsApp на телефоне и отсканируйте этот QR-код.', 'auth-card.qr.preparing': 'Готовим QR-код…', 'auth-card.qr.aria': 'QR-код для входа в WhatsApp. Отсканируйте его телефоном.', // Обратный отсчёт до серверного таймаута. Whatsmeow ротирует QR по // расписанию 60 с + 5 × 20 с = 2 мин 40 с активного окна. Сам QR в // панели всегда свежий (мост шлёт m.replace edits на каждой ротации), // отсчёт показывает оставшееся окно ВСЕГО входа. 'auth-card.qr.countdown': 'На сканирование осталось {minutes}:{seconds}', 'auth-card.qr.expired': 'Окно входа истекло. Нажмите «Отмена» и попробуйте снова.', 'auth-card.qr.step-1': 'Откройте WhatsApp на телефоне.', 'auth-card.qr.step-2': 'Перейдите в «Настройки → Связанные устройства».', 'auth-card.qr.step-3': 'Нажмите «Привязать устройство» и отсканируйте QR-код.', // --- Shared form chrome ------------------------------------------------ 'auth-card.cancel': 'Отмена', 'auth-card.waiting-hint': 'Бот ещё думает… ответ может идти до 30 секунд.', // --- Inline errors ----------------------------------------------------- // login_failed reasons — мы сохраняем верхатимный текст ошибки от // upstream. Это даёт юзеру максимально точную диагностику без перевода, // которое может разъехаться с реальной причиной. Шаблон обёрнут. 'auth-error.login-failed': 'Не удалось войти: {reason}', 'auth-error.invalid-value': 'Значение не принято: {reason}', 'auth-error.submit-failed': 'WhatsApp не принял ввод: {reason}', 'auth-error.start-failed': 'Не удалось начать вход: {reason}', 'auth-error.prepare-failed': 'Не удалось подготовить вход: {reason}', 'auth-error.login-in-progress': 'У бота уже идёт другой вход. Нажмите «Отмена» и попробуйте снова.', 'auth-error.max-logins': 'Достигнут лимит входов ({limit}). Сначала выйдите из существующего аккаунта.', 'auth-error.unknown-command': 'Бот не знает эту команду — проверьте префикс в config.json.', // External-logout варианты — три причины, у каждой своя UX-формулировка. // «another_device» — другой связанный девайс отвязал нас (например, юзер // отвязал bridge с другого ноутбука). «phone_logged_out» — юзер вышел // из WhatsApp на самом телефоне, что ломает все связанные устройства. // «unknown» — fallback, в т.ч. для startup-нотисов «You're not logged // into WhatsApp». 'auth-error.external-logout.another-device': 'WhatsApp отвязал это устройство с другого устройства. Войдите снова.', 'auth-error.external-logout.phone-logged-out': 'Вы вышли из WhatsApp на телефоне — все связанные устройства отвязаны. Войдите снова.', 'auth-error.external-logout.unknown': 'WhatsApp разорвал сессию. Войдите снова.', // --- Logout ------------------------------------------------------------ 'card.logout.name': 'Выйти из WhatsApp', 'card.logout.desc': 'Завершить сеанс на этом аккаунте', 'card.logout.confirm-prompt': 'Точно выйти?', 'card.logout.confirm-yes': 'Выйти', 'card.logout.confirm-no': 'Отмена', 'card.logout.gated': 'Идентификатор сессии ещё загружается — подождите секунду.', // --- Diagnostics in transcript ---------------------------------------- 'diag.connecting': 'Соединение с Vojo… ожидаем capability handshake.', 'diag.ready': 'Готов отправлять команды.', 'diag.checking-status': 'Проверяю статус подключения…', 'diag.send-failed': 'ошибка отправки: {message}', 'diag.history-marker': '─── история ───', 'diag.history-unavailable': 'Не удалось прочитать историю — проверяю статус заново.', // QR-сообщения никогда не выводятся целиком в transcript — body содержит // raw whatsmeow handshake (включая adv-secret, который IS the login // token). Сохранять его в DOM-логе виджета означало бы пережить мост- // редакцию. В логе только нейтральные диагностические строки. 'diag.qr-issued': 'QR-код обновлён.', 'diag.qr-consumed': 'QR-код использован — мост подтверждает скан.', // Pairing-код — не такой же чувствительный как QR adv-secret (это // 8-символьный one-time pairing token, действителен ~3 минуты), но // всё равно по аналогии с QR не дублируем его в transcript — UI и так // показывает код большим моноширинным текстом. В логе только нейтральная // диагностика, чтобы trail был последовательный. 'diag.pairing-code-issued': 'Код для входа выдан.', // Connection warnings от connector handlewhatsapp.go — они не меняют // state виджета, просто пишутся в transcript verbatim, чтобы юзер // понимал, что мост борется с подключением. 'diag.connection-warning': '{text}', // External-logout transcript echo — короткая строка под красным // баннером. 'diag.external-logout': 'WhatsApp разорвал сессию — нужен повторный вход.', // --- Bootstrap failure ------------------------------------------------- 'bootstrap.failed': 'Widget не запустился', 'bootstrap.missing-params': 'Отсутствуют обязательные параметры URL: {names}.', 'bootstrap.embedded-only': 'Эта страница предназначена для встраивания Vojo по маршруту {route}.', } as const; export type StringKey = keyof typeof RU;