diff --git a/.env.example b/.env.example
index 6ca9ddf..7213a66 100644
--- a/.env.example
+++ b/.env.example
@@ -2,8 +2,11 @@
BOT_TOKEN=your_bot_token_here
ADMIN_IDS=comma_separated_admin_ids
-# Database Configuration
-DB_NAME=bot_database.sqlite3
+POSTGRES_USER=postgres
+POSTGRES_PASSWORD=postgres
+POSTGRES_HOST=remnawave-tg-shop-db
+POSTGRES_PORT=5432
+POSTGRES_DB=postgres
# Localization and Display
DEFAULT_LANGUAGE="ru" # or "en"
diff --git a/docker-compose.yml b/docker-compose.yml
index d79a2f7..5d0d39c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,17 +1,32 @@
services:
- vpn-shop:
- build: .
- container_name: vpn-shop-stable
- hostname: vpn-shop-stable
+ remnawave-tg-shop:
+ image: ghcr.io/machka-pasla/remnawave-tg-shop:latest
+# build: .
+ container_name: remnawave-tg-shop
+ hostname: remnawave-tg-shop
env_file:
- .env
networks:
- remnawave-network
volumes:
- - ./bot_database.sqlite3:/app/bot_database.sqlite3
- ./locales:/app/locales
restart: unless-stopped
+ postgres:
+ image: postgres:17
+ container_name: remnawave-tg-shop-db
+ env_file:
+ - .env
+ volumes:
+ - remnawave-tg-shop-db-data:/var/lib/postgresql/data
+ networks:
+ - remnawave-network
+ restart: unless-stopped
+
networks:
remnawave-network:
external: true
+
+volumes:
+ remnawave-tg-shop-db-data:
+ name: remnawave-tg-shop-db-data
diff --git a/locales/en.json b/locales/en.json
index 8bb8d87..079ea66 100644
--- a/locales/en.json
+++ b/locales/en.json
@@ -1,188 +1,206 @@
{
"welcome": "Welcome, {user_name}!",
- "choose_language": "Please choose your language:",
- "language_set": "Language set to English.",
- "language_set_alert": "Language updated!",
- "main_menu_greeting": "Hello, {user_name}!\nWhat would you like to do?",
- "error_service_unavailable": "⚠️ Service unavailable. Please try again later.",
- "error_occurred_processing_request": "⚠️ An error occurred. Please try again.",
- "unknown_command_private": "Sorry, command not understood. Use /start.",
- "error_try_again": "An error occurred. Please try again.",
+ "main_menu_greeting": "Hi, {user_name}! 👋\nWhat would you like to do?",
- "menu_subscribe_inline": "🚀 Buy",
- "menu_my_subscription_inline": "📆 My Sub/Config",
+ "menu_activate_trial_button": "🆓 Free Trial",
+ "menu_subscribe_inline": "🚀 Purchase",
+ "menu_my_subscription_inline": "🔐 My Subscription",
"menu_referral_inline": "🎁 Referrals",
- "menu_apply_promo_button": "🎁 Promo Code",
- "menu_activate_trial_button": "🆓 Activate Trial",
+ "menu_apply_promo_button": "🎟 Promo Code",
"menu_language_settings_inline": "🌐 Language",
"menu_server_status_button": "📊 Status",
"menu_support_button": "💬 Support",
- "menu_terms_button": "📄 Terms Of Service",
- "back_to_main_menu_button": "⬅️ Main Menu",
+ "menu_terms_button": "📄 Terms of Service",
+ "back_to_main_menu_button": "⬅️ Back",
+
+ "choose_language": "Choose language / Выберите язык:",
+ "language_set_alert": "Language changed!",
+ "error_occurred_try_again": "An error occurred, please try again.",
+ "error_displaying_menu": "Error displaying menu.",
+ "main_menu_unknown_action": "Unknown action.",
- "no_subscription_options_available": "Subscription options are currently unavailable.",
"select_subscription_period": "Select subscription period:",
- "subscribe_for_months_button": "{months}mo - {price} {currency_symbol}",
- "confirm_subscription_prompt": "Subscribe for {months} months for {price} {currency_symbol}?\n\nConfirm payment?",
- "confirm_payment_button": "✅ Confirm ({price} {currency_symbol})",
+ "no_subscription_options_available": "No subscription options available at the moment.",
+ "subscribe_for_months_button": "{months} mo. - {price} {currency_symbol}",
+ "confirm_subscription_prompt": "Confirm subscription purchase:\nDuration: {months} mo.\nPrice: {price} {currency_symbol}",
+ "pay_button": "💳 Pay",
+ "confirm_payment_button": "✅ Yes ({price} {currency_symbol})",
"cancel_button": "❌ Cancel",
- "payment_service_unavailable": "⚠️ Payment service unavailable. Try later.",
- "error_creating_payment_record": "⚠️ Error preparing payment. Try again.",
- "payment_link_message": "To complete your {months} months subscription, please click the button below:",
- "pay_button": "💳 Pay Now",
- "error_payment_gateway": "⚠️ Payment gateway error. Try again or contact support.",
- "payment_successful": "✅ Payment successful! Your {months} months subscription is active until {end_date}.",
- "payment_failed": "❌ Payment failed/cancelled. If debited, contact support.",
- "payment_description_subscription": "{months}-Month Subscription",
- "my_subscription_details": "ℹ️ Your Subscription\n\n🗓️ Ends: {end_date} (Days left: {days_left})\n\n🔗 Link: {config_link}\n\n📊 Traffic: {traffic_used} / {traffic_limit}\n💡 Panel: {status}",
- "subscription_not_active": "No active subscription. Subscribe now!",
- "config_link_not_available": "N/A (Try /sync or contact support)",
- "traffic_unlimited": "Unlimited",
- "traffic_na": "N/A",
+ "payment_description_subscription": "Subscription payment for {months} mo.",
+ "payment_service_unavailable": "Payment service temporarily unavailable. Please try again later.",
+ "payment_service_unavailable_alert": "Payment service unavailable",
+ "error_creating_payment_record": "Error creating payment record. Please try again later.",
+ "error_payment_gateway_link_failed": "Failed to get payment link. Please contact support.",
+ "payment_link_message": "To pay for {months} mo. subscription, click the button below:",
+ "error_payment_gateway": "Payment gateway error. Please try again later or contact support.",
+ "payment_successful": "✅ Payment successful!\nYour {months}-month subscription is active until {end_date}.",
+ "payment_successful_with_promo": "✅ Payment successful!\nYour {months}-month subscription (with promo bonus +{bonus_days} days) is active until {end_date}.",
+ "payment_successful_with_referral_bonus": "✅ Payment successful!\nYour {months}-month subscription (base end date: {base_end_date}) has been extended by {bonus_days} bonus days for referral from {inviter_name} and is now active until {final_end_date}.",
+ "payment_successful_error_details": "✅ Payment succeeded, but an error occurred displaying details. Your subscription is active. Contact support if anything is wrong.",
+ "payment_failed": "❌ Payment failed or was cancelled. Please try again or contact support.",
+ "error_processing_your_payment": "An error occurred processing your payment after success. Please contact support with the details.",
+
+ "my_subscription_details": "🔐 My Subscription:\n\nStatus: {status}\nActive until: {end_date} (days left: {days_left})\n\nTraffic: {traffic_used} of {traffic_limit}\n\nConfiguration link:\n{config_link}",
+ "config_link_not_available": "not available, contact support",
+ "subscription_not_active": "You have no active subscription.\nWould you like to purchase one?",
"status_active": "Active",
"status_expired": "Expired",
"status_disabled": "Disabled",
- "status_limited": "Limited",
- "status_unknown": "Unknown",
- "subscription_ending_soon_notification": "Dear {user_name},\nYour subscription ends on {end_date} ({days_left} days left).\nRenew to continue service!",
- "payment_successful_with_referral_bonus": "✅ Payment for {months} months successful! Initial end: {base_end_date}.\n\n🎉 Invited by {inviter_name}, you got {bonus_days} bonus days!\nFinal end date: {final_end_date}.",
- "payment_successful_error_details": "Payment successful, but error displaying details. Check 'My Subscription'.",
- "error_processing_your_payment": "Error processing your payment. Please contact support.",
+ "traffic_unlimited": "Unlimited",
+ "traffic_na": "n/a",
+ "error_service_unavailable": "Service temporarily unavailable. Please try again later.",
- "trial_confirm_prompt": "Activate a {days}-day free trial with {traffic_gb} GB traffic?\n\nThis can only be done once and is not available if you've had a subscription before.",
+ "promo_code_prompt": "Please enter your promo code:",
+ "promo_code_not_found": "Promo code {code} not found, expired, or already used the maximum number of times.",
+ "promo_code_already_used_by_user": "You have already used promo code {code}.",
+ "promo_code_no_active_subscription": "You must have an active subscription to apply this promo code.",
+ "promo_code_applied_success": "✅ Promo code {code} applied successfully!\nYour subscription is extended by {bonus_days} days and is now active until {new_end_date}.",
+ "error_applying_promo_bonus": "Failed to apply promo bonus. Please try again later or contact support.",
+ "promo_input_cancelled_short": "Promo code entry cancelled.",
+
+ "trial_feature_disabled": "Free trial is currently unavailable.",
+ "trial_already_had_subscription_or_trial": "You have already used a free trial or had a paid subscription. Free trial is available only once for new users.",
+ "trial_confirm_prompt": "Would you like to activate a free trial for {days} days with {traffic_gb} GB traffic limit?",
"trial_confirm_activate_button": "✅ Activate!",
- "trial_already_had_subscription_or_trial": "A trial period is only available if you haven't had any subscription (including a trial) before.",
- "trial_activation_failed": "⚠️ Sorry, we couldn't activate your free trial at this time. Please contact support.",
- "trial_feature_disabled": "Trial periods are currently not available.",
- "trial_cancelled": "Trial activation cancelled.",
- "trial_activated_alert": "✅ Free trial activated!",
- "trial_activated_details_message": "🎉 Your {days}-day free trial is now active!\nIt's valid until: {end_date}.\nConfig link: {config_link}\nTraffic: {traffic_gb}\nEnjoy!",
+ "trial_activated_alert": "Trial activated!",
+ "trial_activated_details_message": "🚀 Your {days}-day free trial is activated!\n\nValid until: {end_date}\nTraffic: {traffic_gb} GB\n\nYour configuration link:\n{config_link}",
+ "trial_activation_failed": "Failed to activate free trial. Please try again later.",
+ "trial_activation_failed_panel_link": "Failed to link your account to the server for trial activation. Please try again later.",
+ "trial_activation_failed_db": "Database error during trial activation. Please try again later.",
+ "trial_activation_failed_panel_update": "Failed to update trial details on the server. Please try again later.",
+ "user_not_found_for_trial": "Your account was not found in the system. Please run /start first.",
+ "yes_button": "Yes",
+ "no_button": "No",
+ "trial_cancelled_short": "Activation cancelled.",
- "referral_program_info_new": "Invite friends, get bonus days!\n\nYour referral link:\n{referral_link}\n\nBonuses:{bonus_details}",
- "referral_bonus_per_period": "\n\n🎁 Friend's {months}-mo sub:\n ➢ You get: {inviter_bonus_days} days\n ➢ Friend gets: {referee_bonus_days} days",
+ "referral_program_info_new": "Invite friends and earn bonuses!\n\nYour referral link:\n{referral_link}\n\nBonuses:{bonus_details}",
+ "referral_bonus_per_period": "\n\n🎁 For a friend's {months}-month subscription:\n ➢ You: {inviter_bonus_days} days\n ➢ Friend: {referee_bonus_days} days",
"no_bonus_days": "0",
- "referral_no_bonuses_configured": "\nReferral bonus details not set.",
- "referral_link_for_copying_reminder": "Link above. Tap & hold to copy!",
- "referral_bonus_inviter_notification_extended": "🎉 Hooray, {referee_name} (referred by you) has subscribed!\nYou've received {days} bonus days to your subscription.\nYour subscription now ends on: {new_end_date}.",
- "friend_placeholder": "a friend",
-
- "error_user_not_synced_for_config": "Account not fully synced. Try /sync or contact support.",
- "error_fetching_config_link_details": "Error fetching config link details. Try again or contact support.",
- "error_fetching_config_link_details_no_uuid": "Config link ID not found. Contact support.",
- "error_generating_config_link": "Could not generate config link. Try later.",
+ "referral_no_bonuses_configured": "\nNo referral bonuses configured.",
+ "referral_link_for_copying_reminder": "The link is above. Press and hold to copy.",
+ "friend_placeholder": "friend",
+ "referral_bonus_inviter_notification_extended": "🎉 Congrats! Your friend {referee_name} paid for a subscription. You received {days} bonus days! Your subscription is now active until {new_end_date}.",
+ "referral_bonus_inviter_notification_new_sub": "🎉 Congrats! Your friend {referee_name} paid for a subscription. You received a {days}-day bonus subscription! It is active until {new_end_date}.",
- "promo_code_prompt": "Enter your promo code:",
- "promo_code_invalid_or_expired": "❌ Invalid, expired, or already used promo code.",
- "promo_code_no_active_subscription": "❌ Active subscription required to apply this promo code.",
- "promo_code_applied_success": "✅ Promo '{code}' applied! {bonus_days} bonus days added.\nNew end date: {new_end_date}.",
- "promo_code_max_activations_reached": "❌ Promo '{code}' max activations reached.",
- "promo_code_not_found": "❌ Promo code '{code}' not found.",
- "error_applying_promo_bonus": "⚠️ Error applying promo bonus. Try again or contact support.",
- "promo_input_cancelled_no_message": "Promo code input cancelled.",
-
- "user_is_banned": "⚠️ Access restricted. Contact support if this is an error.",
- "contact_support_button": "💬 Support",
- "suspicious_input_ban_message": "⚠️ Suspicious input detected. For security reasons, your access to this bot has been restricted. Please contact support.",
-
- "admin_panel_title": "👑 Admin Panel",
- "admin_panel_button_reply": "👑 Admin Panel",
- "back_to_admin_panel_button": "⬅️ Admin Panel",
- "admin_unknown_action": "Unknown admin action.",
- "admin_action_cancelled_default": "Action cancelled.",
- "prev_page_button": "Prev",
- "next_page_button": "Next",
- "yes_button": "✅ Yes",
- "no_button": "❌ No",
-
- "admin_ban_user_button": "🚫 Ban",
- "admin_unban_user_button": "✅ Unban",
- "admin_view_banned_users_button": "📜 Banned List",
- "admin_ban_user_prompt": "Enter User ID or @username to ban:",
- "admin_unban_user_prompt": "Enter User ID or @username to unban:",
- "admin_invalid_user_id_format": "Invalid User ID. Must be a number.",
- "admin_invalid_username_format": "Invalid username. Format: @username (5-32 chars: letters, numbers, underscores).",
- "admin_user_not_found_by_username": "User with username @{username} not found in bot records.",
- "admin_cannot_ban_self_or_admin": "Cannot ban yourself or the main admin.",
- "admin_user_not_found_in_bot_db": "User ID {user_id} not found in bot.",
- "admin_user_banned_success_panel_too": "✅ User {user_id_or_username} banned (local & panel).",
- "admin_user_banned_local_panel_fail": "⚠️ User {user_id_or_username} banned locally, panel update failed.",
- "admin_user_banned_local_no_panel_uuid": "✅ User {user_id_or_username} banned locally (no panel ID found).",
- "admin_user_unbanned_success_panel_too": "✅ User {user_id_or_username} unbanned (local & panel).",
- "admin_user_unbanned_local_panel_fail": "⚠️ User {user_id_or_username} unbanned locally, panel update failed.",
- "admin_user_unbanned_local_no_panel_uuid": "✅ User {user_id_or_username} unbanned locally (no panel ID found).",
- "admin_user_already_banned": "User {user_id_or_username} is already banned.",
- "admin_user_not_banned": "User {user_id_or_username} is not currently banned.",
- "admin_confirm_unban_prompt": "Are you sure you want to unban user {user_display} (ID: {user_id})?",
- "admin_confirm_ban_prompt": "Are you sure you want to ban user {user_display} (ID: {user_id})?",
- "admin_user_unbanned_from_card": "✅ User {user_display} (ID: {user_id}) has been unbanned.",
- "admin_user_banned_from_card": "✅ User {user_display} (ID: {user_id}) has been banned.",
- "admin_banned_list_title": "🚫 Banned Users List (Page {current_page}/{total_pages})",
- "admin_no_banned_users": "No users are currently banned.",
- "admin_user_card_title": "👤 User Card: {user_display}",
- "user_card_info": "TG ID: {user_id}\nUsername: @{username}\nName: {first_name} {last_name}\nLanguage: {language_code}\nPanel UUID: {panel_user_uuid}\nStatus: {ban_status}\nRegistered: {reg_date}\nSubscription Ends: {sub_end_date}",
- "user_card_banned": "🔴 BANNED",
- "user_card_active": "🟢 Active",
- "user_card_sub_na": "N/A",
- "user_card_unban_button": "✅ Unban This User",
- "user_card_ban_button": "🚫 Ban This User",
- "user_card_back_to_banned_list_button": "⬅️ Banned List",
+ "user_is_banned": "🚫 Your account is banned. Please contact support.",
+ "admin_panel_title": "Admin Panel",
+ "admin_stats_button": "📊 Statistics",
"admin_broadcast_button": "📢 Broadcast",
- "admin_broadcast_enter_message": "Enter broadcast message (HTML supported):",
- "admin_broadcast_confirm_prompt": "Preview:\n\n---\n{message_preview}\n---\n\nSend to all users?",
- "confirm_broadcast_send_button": "✅ Send",
- "cancel_broadcast_button": "❌ Cancel",
- "admin_broadcast_sending_started": "Broadcast started...",
- "admin_broadcast_error_no_message": "Error: No message to broadcast.",
- "admin_broadcast_finished_stats": "📢 Broadcast finished.\nSent: {sent_count}\nFailed: {failed_count}",
- "admin_broadcast_cancelled": "Broadcast cancelled.",
+ "admin_create_promo_button": "🎁 Create Promo",
+ "admin_view_promos_button": "👀 Promo List",
+ "admin_ban_user_button": "🚫 Ban User",
+ "admin_unban_user_button": "✅ Unban User",
+ "admin_view_banned_users_button": "📜 Ban List",
+ "admin_view_logs_menu_button": "📄 Logs",
+ "admin_sync_panel_button": "🔄 Sync",
+ "admin_unknown_action": "Unknown admin action.",
+ "admin_action_cancelled_default": "Action cancelled. Returning to menu.",
+ "admin_action_cancelled_default_alert": "Action cancelled",
+ "back_to_admin_panel_button": "⬅️ Back to Admin",
- "admin_create_promo_button": "🎁 New Promo",
- "admin_view_promos_button": "📜 Promos",
- "admin_promo_create_prompt": "Promo: CODE DAYS MAX_USES [VALID_DAYS]\nEx: SALE24 7 100 30 (30d validity)\nEx: NEWBIE 5 500 (no expiry)",
- "admin_promo_invalid_format": "Invalid format. Use: CODE DAYS USES [VALIDITY]",
- "admin_promo_invalid_values": "Invalid values. Days/uses must be positive. Error: {error}",
- "admin_promo_created_success": "✅ Promo '{code}': {bonus_days}d, {max_activations} uses, {valid_until_str}.",
- "admin_promo_valid_until_display": "Valid until: {date}",
- "admin_promo_valid_indefinitely": "No expiry",
- "admin_promo_creation_failed": "❌ Promo creation failed (exists or DB error).",
- "admin_no_active_promos": "No active promo codes.",
- "admin_active_promos_list_header": "📜 Active Promos:",
- "admin_promo_list_item": "- {code}: {bonus} days, {current}/{max} used, Valid: {valid_until}",
-
- "admin_stats_button": "📊 Stats",
- "admin_stats_header": "📊 Bot Statistics:",
- "admin_stats_users": "\n👥 Users:\n Total: {total_users}\n Banned: {banned_users}\n Active Subs (Bot): {active_subs}",
- "admin_stats_recent_payments_header": "\n💳 Recent Payments (Bot DB):",
- "admin_stats_payment_item": " {status_emoji} {amount} {currency} by {user_info} ({p_status}) on {p_date}",
- "admin_stats_no_payments_found": "\nNo payment records in bot DB.",
- "admin_stats_last_sync_header": "\n🔄 Last Panel Sync:",
+ "admin_stats_header": "📊 Bot Statistics",
+ "admin_stats_users": "👥 Users: Total - {total_users}, Banned - {banned_users}, Active Subs - {active_subs}",
+ "admin_stats_recent_payments_header": "Recent Payments:",
+ "admin_stats_payment_item": "{status_emoji} {amount} {currency} from {user_info} ({p_status}) [{p_date}]",
+ "admin_stats_no_payments_found": "No payments found yet.",
+ "admin_stats_last_sync_header": "Last Panel Sync:",
"admin_stats_sync_time": "Time",
"admin_stats_sync_status": "Status",
- "admin_stats_sync_users_processed": "Panel Users Processed",
- "admin_stats_sync_subs_synced": "Subs Synced",
+ "admin_stats_sync_users_processed": "Users Processed",
+ "admin_stats_sync_subs_synced": "Subscriptions Synced",
"admin_stats_sync_details_label": "Details",
- "admin_sync_status_never_run": "No sync performed yet.",
+ "admin_sync_status_never_run": "Panel sync never run.",
- "admin_view_logs_menu_button": "📜 View Logs",
- "admin_logs_menu_title": "📜 User Activity Logs",
- "admin_view_all_logs_button": "All Logs",
- "admin_view_user_logs_prompt_button": "Logs by User",
- "admin_prompt_for_user_id_or_username_logs": "Enter User ID or @username for logs:",
- "admin_all_logs_title": "📜 All Activity (Page {current_page}/{total_pages})",
- "admin_user_logs_title": "📜 Activity for {user_display} (Page {current_page}/{total_pages})",
- "admin_no_logs_found": "No logs found matching your criteria.",
- "admin_log_entry_format": "[{timestamp_str}] User: {user_display} (ID: {user_id})\nType: {event_type}\nContent: {content_preview}",
- "admin_log_user_not_found": "User '{input}' not found for log viewing.",
+ "admin_broadcast_enter_message": "Enter the broadcast message (HTML supported):",
+ "admin_broadcast_confirm_prompt": "You are about to send the following message (first 200 characters):\n\n{message_preview}\n\nConfirm sending?",
+ "confirm_broadcast_send_button": "✅ Send",
+ "cancel_broadcast_button": "❌ Cancel",
+ "admin_broadcast_sending_started": "Starting broadcast...",
+ "admin_broadcast_error_no_message": "Error: no message to broadcast.",
+ "admin_broadcast_error_no_message_alert": "Broadcast message is empty!",
+ "admin_broadcast_finished_stats": "🏁 Broadcast finished!\nSent: {sent_count}\nFailed: {failed_count}",
+ "admin_broadcast_cancelled": "Broadcast cancelled.",
+ "admin_broadcast_cancelled_alert": "Broadcast cancelled!",
+ "admin_broadcast_cancelled_nav_back": "Broadcast cancelled. You are returned to the admin panel.",
+
+ "admin_promo_create_prompt": "Enter promo details in the format: CODE BONUS_DAYS MAX_USES [VALIDITY_DAYS]\nExample: {example_format}\n(Validity is optional; default is indefinite)",
+ "admin_promo_invalid_format": "Invalid format. Please use: CODE BONUS_DAYS MAX_USES [VALIDITY_DAYS]",
+ "admin_promo_invalid_code_format": "Code must be 3–30 alphanumeric characters.",
+ "admin_promo_invalid_bonus_or_activations": "Bonus days and max uses must be positive numbers.",
+ "admin_promo_invalid_validity_days": "Validity period (in days) must be a positive number.",
+ "admin_promo_invalid_values": "Invalid values. {error}",
+ "admin_promo_invalid_format_general": "Promo parsing error. Check the format.",
+ "admin_promo_created_success": "✅ Promo code {code} created successfully!\nBonus: {bonus_days} days\nMax uses: {max_activations}\nValid until: {valid_until_str}.",
+ "admin_promo_creation_failed_duplicate": "❌ Error: Promo code {code} already exists.",
+ "admin_promo_creation_failed": "❌ Failed to create promo code. Please try again later.",
+ "admin_active_promos_list_header": "Active Promo Codes:",
+ "admin_no_active_promos": "No active promo codes.",
+ "admin_promo_list_item": "{code}: +{bonus}d, {current}/{max} used, valid until {valid_until}",
+ "admin_promo_valid_indefinitely": "indefinite",
+ "admin_promo_valid_until_display": "until {date}",
+
+ "admin_ban_user_prompt": "Enter user ID or @username to ban:",
+ "admin_user_not_found_in_bot_db": "User {user_id} not found in bot database.",
+ "admin_cannot_ban_self_or_admin": "You cannot ban yourself or another admin.",
+ "admin_user_already_banned": "User {user_id_or_username} is already banned.",
+ "admin_user_banned_success_combined": "✅ User {user_id_or_username} banned in bot {panel_status_part}.",
+ "admin_panel_ban_success_part": "and on panel",
+ "admin_panel_ban_fail_part": ", but failed to ban on panel",
+ "admin_user_ban_failed_local_db_error": "❌ Failed to ban user in local database.",
+ "admin_unban_user_prompt": "Enter user ID or @username to unban:",
+ "admin_user_not_banned": "User {user_id_or_username} is not banned.",
+ "admin_user_unbanned_success_combined": "✅ User {user_id_or_username} unbanned in bot {panel_status_part}.",
+ "admin_panel_unban_success_part": "and on panel",
+ "admin_panel_unban_fail_part": ", but failed to unban on panel",
+ "admin_user_unban_failed_local_db_error": "❌ Failed to unban user in local database.",
+ "admin_no_banned_users": "There are no banned users at the moment.",
+ "admin_banned_list_title": "Banned Users (page {current_page}/{total_pages}):",
+ "admin_banned_user_button_text": "{user_display} (ID: {user_id})",
+ "prev_page_button": "⬅️ Prev.",
+ "next_page_button": "Next ➡️",
+ "admin_user_card_title": "User Profile: {user_display}",
+ "user_card_info": "ID: {user_id}\nUsername: @{username}\nName: {first_name} {last_name}\nLanguage: {language_code}\nPanel UUID: {panel_user_uuid}\nStatus: {ban_status}\nRegistered: {reg_date}\nSubscription until: {sub_end_date}",
+ "user_card_banned": "BANNED",
+ "user_card_active": "Active",
+ "user_card_sub_na": "n/a",
+ "user_card_ban_button": "🚫 Ban",
+ "user_card_unban_button": "✅ Unban",
+ "user_card_back_to_banned_list": "⬅️ Back to Ban List",
+ "admin_confirm_action_title": "Confirm: {action_text}",
+ "ban_verb_l": "ban",
+ "unban_verb_l": "unban",
+ "admin_confirm_ban_prompt": "Are you sure you want to ban {user_display} (ID: {user_id})?",
+ "admin_confirm_unban_prompt": "Are you sure you want to unban {user_display} (ID: {user_id})?",
+ "admin_user_banned_from_card_alert": "User {user_display} (ID: {user_id}) has been banned.",
+ "admin_user_unbanned_from_card_alert": "User {user_display} (ID: {user_id}) has been unbanned.",
+ "admin_user_ban_failed_db_error": "Error banning user in database.",
+ "admin_user_unban_failed_db_error": "Error unbanning user in database.",
+ "admin_panel_status_update_fail_part": ", but panel status not updated",
+
+ "admin_logs_menu_title": "Logs Menu:",
+ "admin_view_all_logs_button": "📜 All Message Logs",
+ "admin_view_user_logs_prompt_button": "👤 User Logs",
+ "admin_all_logs_title": "All Logs (page {current_page}/{total_pages}):",
+ "admin_no_logs_found": "No logs found.",
+ "admin_log_entry_format": "{timestamp_str} - {user_display} (ID: {user_id})\n {event_type}: {content_preview}",
"system_or_unknown_user": "System/Unknown",
+ "admin_prompt_for_user_id_or_username_logs": "Enter user ID or @username to view logs:",
+ "admin_log_user_not_found": "User \"{input}\" not found in bot database.",
+ "admin_user_logs_title": "Logs for {user_display} (page {current_page}/{total_pages}):",
- "admin_sync_panel_button": "🔄 Sync Panel",
- "sync_started": "Panel synchronization started...",
- "sync_completed": "Panel synchronization completed.\nStatus: {status}\nDetails: {details}",
- "sync_failed": "Panel synchronization failed.\nDetails: {details}",
- "admin_sync_initiated_from_panel": "Panel sync initiated!",
- "error_cannot_initiate_sync_no_message": "Error: Cannot initiate sync without message context.",
+ "sync_started": "🔄 Starting data sync with panel...",
+ "sync_failed": "❌ Sync with panel failed. Details: {details}",
+ "sync_completed": "✅ Sync with panel completed. Status: {status}. Details: {details}",
+ "sync_completed_details": "Checked: {total_checked} entries.\nUsers synced/updated: {users_synced}.\nSubscriptions synced/updated: {subs_synced}.",
+ "sync_completed_with_errors_details": "Checked: {total_checked} entries.\nUsers synced/updated: {users_synced}.\nSubscriptions synced/updated: {subs_synced}.\nErrors: {errors_count}.\n\nFirst errors:\n{error_details_preview}",
+ "no_errors_placeholder": "none",
+ "admin_sync_initiated_from_panel": "Sync initiated...",
+ "error_displaying_logs_too_long": "Error: logs too long to display in one message. Try viewing logs for a specific user.",
+ "error_displaying_statistics": "Error displaying statistics.",
+ "stub_page_display": "Page",
- "admin_suspicious_promo_attempt_notification": "⚠️ Suspicious Promo Code Input! ⚠️\n\nUser: {user_first_name} (@{user_username}, ID: {user_id})\nInput:
{promo_code_input}",
- "admin_suspicious_promo_attempt_notification_no_username": "⚠️ Suspicious Promo Code Input! ⚠️\n\nUser: {user_first_name} (ID: {user_id})\nInput: {promo_code_input}"
+ "subscription_ending_soon_notification": "👋 Hi, {user_name}!\n\n⏳ Your VPN subscription ends on {end_date} (in {days_left} days).\n\nTo avoid interruption, please renew it in the main menu.",
+
+ "error_unknown": "An unknown error occurred."
}
diff --git a/locales/ru.json b/locales/ru.json
index e36b1c3..263b2e2 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -61,6 +61,7 @@
"trial_feature_disabled": "Пробный период в данный момент недоступен.",
"trial_already_had_subscription_or_trial": "Вы уже использовали пробный период или у вас была платная подписка. Пробный период доступен только один раз для новых пользователей.",
"trial_confirm_prompt": "Хотите активировать бесплатный пробный период на {days} дней с лимитом трафика {traffic_gb}?",
+ "trial_confirm_activate_button": "✅ Активировать!",
"trial_activated_alert": "Пробный период активирован!",
"trial_activated_details_message": "🚀 Ваш пробный период на {days} дней активирован!\n\nДействует до: {end_date}\nТрафик: {traffic_gb}\n\nВаша ссылка на конфигурацию:\n{config_link}",
"trial_activation_failed": "Не удалось активировать пробный период. Пожалуйста, попробуйте позже.",