feat(tgbot): rebuild the Telegram bot around editable screens and inline lists (#6760)

The bot answered every action with a new message, so a chat filled with stale
menus whose buttons still acted, and long client or inbound lists were paged
through dozens of buttons. Each chat now has one live screen that is edited in
place: the menu is grouped into Server, Clients, Traffic and Maintenance, lists
open through inline search, the add-client flow starts from a draft card, QR
codes arrive as one labelled sheet, and repeated notices collapse into one with
a counter. A client's /start and /usage show only that client's own links and
usage, groups are refused, and the settings page warns when the bot's inline
mode is off. Admin topics, the indexed Telegram lookup and every locale,
Slovak included, carry over.
This commit is contained in:
DIMFLIX
2026-10-24 13:39:56 +03:00
committed by GitHub
parent bc1b750e00
commit 15fee2a035
62 changed files with 7449 additions and 1945 deletions
+74 -23
View File
@@ -85,7 +85,6 @@
"uploaded": "Отправлено",
"expiry": "Срок действия",
"totalQuota": "Общий лимит",
"individualLinks": "Индивидуальные ссылки",
"active": "Активна",
"inactive": "Неактивна",
"unlimited": "Неограниченно",
@@ -1830,6 +1829,11 @@
"subIncyResolveDnsIp": "IP DoH-сервера",
"subIncyResolveDnsIpDesc": "IP DoH-сервера, нужен для bootstrap.",
"subIncyGroupRouting": "Маршрутизация",
"tgInlineMissing": "Inline mode is disabled",
"tgInlineMissingDesc": "Lists in the bot open through inline search. Enable it in @BotFather with /setinline, otherwise tapping a search button does nothing.",
"tgInlineRecheck": "Check again",
"tgPrivacyOn": "Режим приватности включён",
"tgPrivacyOnDesc": "Бот работает только в личных сообщениях, поэтому группы он игнорирует намеренно. Приватность в группах решает лишь то, может ли бот читать сообщения группы, — а он это не использует.",
"subHostSortMode": "Порядок узлов подписки",
"subHostSortInbound": "Порядок входящих подключений (по умолчанию)",
"subHostSortHosts": "Порядок хостов",
@@ -2486,7 +2490,6 @@
}
},
"tgbot": {
"keyboardClosed": "❌ Клавиатура закрыта.",
"noResult": "❗ Нет результатов.",
"noQuery": "❌ Запрос не найден. Пожалуйста, повторите команду.",
"wentWrong": "❌ Что-то пошло не так...",
@@ -2508,10 +2511,6 @@
"unknown": "❗ Неизвестная команда",
"pleaseChoose": "👇 Пожалуйста, выберите:\r\n",
"help": "🤖 Добро пожаловать! Этот бот предназначен для предоставления вам данных с сервера и позволяет вносить изменения на него.\r\n\r\n",
"start": "👋 Привет, <i>{{ .Firstname }}</i>.\r\n",
"welcome": "🤖 Добро пожаловать в бота управления <b>{{ .Hostname }}</b>!\r\n",
"status": "✅ Бот функционирует нормально.",
"usage": "❗ Пожалуйста, укажите email для поиска.",
"getID": "🆔 Ваш User ID: <code>{{ .ID }}</code>",
"helpAdminCommands": "🔃 Для перезапуска Xray Core:\r\n<code>/restart</code>\r\n\r\n🔎 Для поиска клиента по email:\r\n<code>/usage [Email]</code>\r\n\r\n📊 Для поиска входящих подключений (со статистикой клиентов):\r\n<code>/inbound [имя подключения]</code>\r\n\r\n🆔 Ваш Telegram User ID:\r\n<code>/id</code>",
"helpClientCommands": "💲 Для просмотра информации о вашей подписке используйте команду:\r\n<code>/usage [Email]</code>\r\n\r\n🆔 Ваш Telegram User ID:\r\n<code>/id</code>",
@@ -2520,14 +2519,7 @@
"restartFailed": "❗ Ошибка при перезапуске Xray-core.\r\n\r\n<code>Ошибка: {{ .Error }}</code>.",
"xrayNotRunning": "❗ Xray Core не запущен.",
"startDesc": "Показать главное меню",
"helpDesc": "Справка по боту",
"statusDesc": "Проверить статус бота",
"idDesc": "Показать ваш Telegram ID",
"usageDesc": "Показать трафик клиента: /usage email",
"inboundDesc": "Поиск входящих: /inbound имя (админ)",
"restartDesc": "Перезапустить ядро Xray (админ)",
"broadcastDesc": "Массовая рассылка всем клиентам (админ)",
"clearallDesc": "Сбросить трафик всех клиентов (админ)"
"statusOk": "✅ Бот в порядке!"
},
"messages": {
"cpuThreshold": "Загрузка процессора составляет {{ .Percent }}%, что превышает пороговое значение {{ .Threshold }}%",
@@ -2571,7 +2563,6 @@
"inviteInvalid": "❗ Эта ссылка-приглашение недействительна или уже использована.\r\n",
"inviteRateLimited": "⏳ Слишком много попыток приглашения. Попробуйте позже.\r\n",
"inviteRateLimitedAdmin": "⚠️ Попытки приглашения заблокированы для {{ .User }} (<code>{{ .ID }}</code>): более {{ .Limit }} попыток за час. Возможно, кто-то подбирает ID подписок.",
"inviteLink": "🔗 Ссылка-приглашение для <code>{{ .Email }}</code>:\r\n<code>{{ .Link }}</code>\r\n\r\nПервый, кто её откроет, будет привязан к этому клиенту.\r\n",
"exhaustedCount": "🚨 Количество исчерпанных {{ .Type }}:\r\n",
"onlinesCount": "🌐 Клиентов онлайн: {{ .Count }}\r\n",
"disabled": "🛑 Отключено: {{ .Disabled }}\r\n",
@@ -2580,13 +2571,11 @@
"refreshedOn": "\r\n📋🔄 Обновлено: {{ .Time }}\r\n\r\n",
"yes": "✅ Да",
"no": "❌ Нет",
"received_email": "📧📥 Email обновлен.",
"received_comment": "💬📥 Комментарий обновлён.",
"email_prompt": "📧 Стандартный email: {{ .ClientEmail }}\n\nВведите ваш email.",
"comment_prompt": "💬 Стандартный комментарий: {{ .ClientComment }}\n\nВведите ваш комментарий.",
"tgid_prompt": "🆔 Стандартный TG-юзер: {{ .ClientTGID }}\n\nОтправьте числовой id пользователя, чтобы привязать к клиенту, либо - / none чтобы очистить.",
"cancel": "❌ Процесс отменён! \n\nВы можете снова начать с /start в любое время. 🔄",
"error_add_client": "⚠️ Ошибка:\n\n {{ .error }}",
"using_default_value": "Используется значение по умолчанию👌",
"incorrect_input": "Ваш ввод недействителен.\nФразы должны быть непрерывными без пробелов.\nПравильный пример: aaaaaa\nНеправильный пример: aaa aaa 🚫",
"broadcastAskText": "📤 Рассылка: пришлите сообщение для ваших клиентов — текст, фото, видео, файл или целый альбом.",
"broadcastAlreadyRunning": "❗ Рассылка уже идёт, дождитесь её завершения.",
@@ -2610,7 +2599,23 @@
"eventNodeDown": "Узел {{ .Name }} НЕДОСТУПЕН",
"eventNodeUp": "Узел {{ .Name }} В СЕТИ",
"eventLoginFallback": "Неудачный вход с {{ .Source }}",
"memoryThreshold": "🔴 Использование памяти {{ .Percent }}% превышает пороговое значение {{ .Threshold }}%"
"memoryThreshold": "🔴 Использование памяти {{ .Percent }}% превышает пороговое значение {{ .Threshold }}%",
"inboundsCount": "🔌 Inbounds: {{ .Count }}\r\n",
"clientsCount": "👥 Clients: {{ .Count }}\r\n",
"category_server": "🖥 Сервер",
"category_clients": "👥 Клиенты",
"category_traffic": "🚦 Трафик",
"category_maintenance": "⚙️ Обслуживание",
"inlineHint": "\r\n🔍 The list opens through search: tap Find and start typing.",
"subURL": "🔗 Subscription: <code>{{ .URL }}</code>\r\n",
"jsonURL": "🧩 JSON: <code>{{ .URL }}</code>\r\n",
"inviteHint": "Send this link to the client: the first Telegram account to open it is bound to the client.",
"qrLegendHeader": "🔳 QR-коды:",
"qrLegendSubscription": "{{ .Code }}. Подписка",
"qrLegendJSON": "{{ .Code }}. JSON-подписка",
"qrLegendLink": "{{ .Code }}. Ссылка для приложения {{ .App }}",
"backupFailed": "Не удалось прочитать базу данных; бэкап не отправлен.",
"privateOnly": "🤖 Бот работает только в личных сообщениях. Открой его в личке."
},
"buttons": {
"closeKeyboard": "❌ Закрыть клавиатуру",
@@ -2626,9 +2631,11 @@
"serverUsage": "💻 Состояние сервера",
"getInbounds": "🔌 Входящие подключения",
"depleteSoon": "⚠️ Скоро конец",
"clientUsage": "Статистика клиента",
"onlines": "🟢 Онлайн",
"commands": "🖱️ Команды",
"catServer": "🖥 Сервер",
"catClients": "👥 Клиенты",
"catTraffic": "🚦 Трафик",
"catMaintenance": "⚙️ Обслуживание",
"refresh": "🔄 Обновить",
"clearIPs": "❌ Очистить IP",
"removeTGUser": "❌ Удалить пользователя Telegram",
@@ -2653,8 +2660,22 @@
"use_default": "🏷️ Использовать по умолчанию",
"change_email": "⚙️📧 Email",
"change_comment": "⚙️💬 Комментарий",
"ResetAllTraffics": "Сбросить весь трафик",
"SortedTrafficUsageReport": "Отсортированный отчет об использовании трафика"
"ResetAllTraffics": "♻️ Сбросить весь трафик",
"SortedTrafficUsageReport": "📈 Отсортированный отчет об использовании трафика",
"restartXray": "♻️ Restart Xray",
"back": "⬅️ Back",
"hide": "🙈 Hide",
"page": "Page {{ .Page }} of {{ .Pages }}",
"searchInbounds": "🔍 Find inbound…",
"searchClients": "🔍 Find client…",
"inlineDisabled": "⚠️ Inline mode is off",
"clientCard": "⬅️ Client card",
"links": "🔗 Links",
"individualLinks": "🔗 Individual links",
"qrCode": "🔳 QR code",
"broadcast": "📢 Рассылка",
"attachInbound": "Привязать инбаунд ({{ .Count }})",
"attachDone": "✅ Готово"
},
"answers": {
"broadcastStarted": "🚀 Рассылка запущена.",
@@ -2682,6 +2703,36 @@
"chooseClient": "Выберите клиента для входящего подключения {{ .Inbound }}",
"chooseInbound": "Выберите входящее подключение",
"qrCodeForClient": "QR-код для клиента {{ .Email }}:"
},
"screens": {
"panel": "Panel",
"main": "Main",
"status": "Server",
"inbounds": "Inbounds",
"clients": "Clients",
"client": "Client",
"links": "Links",
"qr": "QR code",
"wizard": "New client",
"reports": "Report",
"backup": "Backup",
"onlines": "Online",
"deplete": "Running out",
"commands": "Commands",
"broadcast": "Broadcast"
},
"inline": {
"noneTitle": "Nothing found",
"noneDesc": "Use @BotFather /setinline to enable the list.",
"offTitle": "⚠️ Inline mode is disabled for this bot",
"offBody": "Lists are browsed in inline mode. Enable it in @BotFather: /setinline, then tap Check again.",
"recheck": "Check again",
"expired": "истёк",
"fromFirstUse": "с первого использования"
},
"noValue": "—",
"notices": {
"repeat": "\r\n\r\n🔁 repeated {{ .Count }}× · last {{ .Time }}"
}
},
"discord": {