diff --git a/.env.example b/.env.example index eb580bec..0d20ed8d 100644 --- a/.env.example +++ b/.env.example @@ -741,7 +741,7 @@ MAINTENANCE_MESSAGE=Ведутся технические работы. Серв # ===== ЛОКАЛИЗАЦИЯ ===== # Укажите язык из AVAILABLE_LANGUAGES. При некорректном значении используется ru. DEFAULT_LANGUAGE=ru -AVAILABLE_LANGUAGES=ru,en,ua,zh +AVAILABLE_LANGUAGES=ru,en,ua,zh,fa # Включить выбор языка при старте и отображение кнопки в меню LANGUAGE_SELECTION_ENABLED=true diff --git a/app/cabinet/routes/admin_email_templates.py b/app/cabinet/routes/admin_email_templates.py index 7299e90f..4e4fdd02 100644 --- a/app/cabinet/routes/admin_email_templates.py +++ b/app/cabinet/routes/admin_email_templates.py @@ -337,7 +337,7 @@ SAMPLE_CONTEXTS: dict[str, dict[str, Any]] = { 'password_reset': {'username': 'John', 'reset_url': 'https://example.com/reset?token=abc123', 'expire_hours': 1}, } -AVAILABLE_LANGUAGES = ['ru', 'en', 'zh', 'ua'] +AVAILABLE_LANGUAGES = ['ru', 'en', 'zh', 'ua', 'fa'] # ============ Schemas ============ diff --git a/app/cabinet/routes/info.py b/app/cabinet/routes/info.py index dc416818..16b9b037 100644 --- a/app/cabinet/routes/info.py +++ b/app/cabinet/routes/info.py @@ -20,6 +20,30 @@ logger = logging.getLogger(__name__) router = APIRouter(prefix='/info', tags=['Cabinet Info']) +_LANGUAGE_META: dict[str, tuple[str, str]] = { + 'ru': ('Русский', '🇷🇺'), + 'en': ('English', '🇬🇧'), + 'ua': ('Українська', '🇺🇦'), + 'zh': ('中文', '🇨🇳'), + 'fa': ('فارسی', '🇮🇷'), +} + + +def _normalize_language_code(value: str | None) -> str: + return (value or '').strip().lower().split('-', 1)[0] + + +def _get_available_language_codes() -> list[str]: + codes: list[str] = [] + seen: set[str] = set() + for code in settings.get_available_languages(): + normalized = _normalize_language_code(code) + if not normalized or normalized in seen: + continue + seen.add(normalized) + codes.append(normalized) + return codes + # ============ Schemas ============ @@ -212,12 +236,19 @@ async def get_service_info(): @router.get('/languages') async def get_available_languages(): """Get list of available languages.""" + codes = _get_available_language_codes() + default_language = _normalize_language_code(getattr(settings, 'DEFAULT_LANGUAGE', 'ru') or 'ru') + return { 'languages': [ - {'code': 'ru', 'name': 'Русский', 'flag': '🇷🇺'}, - {'code': 'en', 'name': 'English', 'flag': '🇬🇧'}, + { + 'code': code, + 'name': _LANGUAGE_META.get(code, (code.upper(), '🌐'))[0], + 'flag': _LANGUAGE_META.get(code, (code.upper(), '🌐'))[1], + } + for code in codes ], - 'default': getattr(settings, 'DEFAULT_LANGUAGE', 'ru') or 'ru', + 'default': default_language, } @@ -236,16 +267,15 @@ async def update_user_language( db: AsyncSession = Depends(get_cabinet_db), ): """Update user's language preference.""" - language = request.get('language', 'ru') - - valid_languages = ['ru', 'en'] - if language not in valid_languages: + requested_language = _normalize_language_code(request.get('language', 'ru')) + available_languages = _get_available_language_codes() + if requested_language not in available_languages: raise HTTPException( status_code=status.HTTP_400_BAD_REQUEST, - detail=f'Invalid language. Supported: {", ".join(valid_languages)}', + detail=f'Invalid language. Supported: {", ".join(available_languages)}', ) - user.language = language + user.language = requested_language await db.commit() await db.refresh(user) diff --git a/app/cabinet/services/email_service.py b/app/cabinet/services/email_service.py index a5c09c02..9818892d 100644 --- a/app/cabinet/services/email_service.py +++ b/app/cabinet/services/email_service.py @@ -119,7 +119,7 @@ class EmailService: verification_token: Verification token verification_url: Base URL for verification (token will be appended) username: User's name for personalization - language: Language code (ru, en, zh, ua) + language: Language code (ru, en, zh, ua, fa) custom_subject: Override subject from admin template custom_body_html: Override body HTML from admin template (already wrapped in base template) @@ -174,6 +174,16 @@ class EmailService: 'ignore': 'Якщо ви не створювали акаунт, просто проігноруйте цей лист.', 'regards': 'З повагою,', }, + 'fa': { + 'greeting': f'سلام{", " + username if username else ""}!', + 'subject': 'تایید آدرس ایمیل', + 'intro': 'از ثبت‌نام شما سپاسگزاریم! لطفاً با کلیک روی دکمه زیر ایمیل خود را تایید کنید:', + 'button': 'تایید ایمیل', + 'or_copy': 'یا این لینک را در مرورگر خود کپی و باز کنید:', + 'expires': f'این لینک تا {expire_hours} ساعت معتبر است.', + 'ignore': 'اگر شما این حساب را ایجاد نکرده‌اید، این ایمیل را نادیده بگیرید.', + 'regards': 'با احترام،', + }, } t = texts.get(language, texts['ru']) @@ -236,7 +246,7 @@ class EmailService: reset_token: Password reset token reset_url: Base URL for password reset (token will be appended) username: User's name for personalization - language: Language code (ru, en, zh, ua) + language: Language code (ru, en, zh, ua, fa) custom_subject: Override subject from admin template custom_body_html: Override body HTML from admin template (already wrapped in base template) @@ -291,6 +301,16 @@ class EmailService: 'warning': "Якщо ви не запитували скидання пароля, проігноруйте цей лист або зв'яжіться з підтримкою.", 'regards': 'З повагою,', }, + 'fa': { + 'greeting': f'سلام{", " + username if username else ""}!', + 'subject': 'بازنشانی رمز عبور', + 'intro': 'درخواستی برای بازنشانی رمز عبور شما دریافت شد. برای تعیین رمز جدید روی دکمه زیر بزنید:', + 'button': 'بازنشانی رمز عبور', + 'or_copy': 'یا این لینک را در مرورگر خود کپی و باز کنید:', + 'expires': f'این لینک تا {expire_hours} ساعت معتبر است.', + 'warning': 'اگر شما درخواست بازنشانی رمز عبور نداده‌اید، این ایمیل را نادیده بگیرید یا با پشتیبانی تماس بگیرید.', + 'regards': 'با احترام،', + }, } t = texts.get(language, texts['ru']) @@ -352,7 +372,7 @@ class EmailService: to_email: New email address code: 6-digit verification code username: User's name for personalization - language: Language code (ru, en, zh, ua) + language: Language code (ru, en, zh, ua, fa) custom_subject: Override subject from admin template custom_body_html: Override body HTML from admin template @@ -401,6 +421,15 @@ class EmailService: 'ignore': 'Якщо ви не запитували зміну email, просто проігноруйте цей лист.', 'regards': 'З повагою,', }, + 'fa': { + 'greeting': f'سلام{", " + username if username else ""}!', + 'subject': 'کد تایید تغییر ایمیل', + 'intro': 'شما درخواست تغییر ایمیل داده‌اید. برای تایید از کد زیر استفاده کنید:', + 'code_label': 'کد تایید شما:', + 'expires': f'این کد تا {expire_minutes} دقیقه معتبر است.', + 'ignore': 'اگر شما درخواست تغییر ایمیل نداده‌اید، این ایمیل را نادیده بگیرید.', + 'regards': 'با احترام،', + }, } t = texts.get(language, texts['ru']) diff --git a/app/cabinet/services/email_templates.py b/app/cabinet/services/email_templates.py index 5d99d65f..814fe8f8 100644 --- a/app/cabinet/services/email_templates.py +++ b/app/cabinet/services/email_templates.py @@ -1,7 +1,7 @@ """ Email notification templates for different notification types. -Supports multiple languages: ru, en, zh, ua +Supports multiple languages: ru, en, zh, ua, fa """ from typing import Any @@ -27,7 +27,7 @@ class EmailNotificationTemplates: Args: notification_type: Type of notification - language: Language code (ru, en, zh, ua) + language: Language code (ru, en, zh, ua, fa) context: Context data for template rendering Returns: @@ -72,6 +72,7 @@ class EmailNotificationTemplates: 'en': 'This is an automated message. Please do not reply to this email.', 'zh': '这是一封自动发送的邮件,请勿回复。', 'ua': 'Це автоматичне повідомлення. Будь ласка, не відповідайте на цей лист.', + 'fa': 'این یک پیام خودکار است. لطفاً به این ایمیل پاسخ ندهید.', } footer_text = footer_texts.get(language, footer_texts['ru']) @@ -182,6 +183,7 @@ class EmailNotificationTemplates: 'en': 'Open Dashboard', 'zh': '打开控制面板', 'ua': 'Відкрити особистий кабінет', + 'fa': 'باز کردن پنل کاربری', } text = texts.get(language, texts['en']) diff --git a/app/config.py b/app/config.py index ee7782e1..0863d1a7 100644 --- a/app/config.py +++ b/app/config.py @@ -531,7 +531,7 @@ class Settings(BaseSettings): SKIP_REFERRAL_CODE: bool = False DEFAULT_LANGUAGE: str = 'ru' - AVAILABLE_LANGUAGES: str = 'ru,en' + AVAILABLE_LANGUAGES: str = 'ru,en,ua,zh,fa' LANGUAGE_SELECTION_ENABLED: bool = True # Округление цен при отображении (≤50 коп вниз, >50 коп вверх) @@ -1198,7 +1198,7 @@ class Settings(BaseSettings): return self.YOOKASSA_QUICK_AMOUNT_SELECTION_ENABLED and not self.DISABLE_TOPUP_BUTTONS def get_available_languages(self) -> list[str]: - defaults = ['ru', 'en', 'ua', 'zh'] + defaults = ['ru', 'en', 'ua', 'zh', 'fa'] try: langs = self.AVAILABLE_LANGUAGES diff --git a/app/database/crud/user.py b/app/database/crud/user.py index 66f1b8af..af359f29 100644 --- a/app/database/crud/user.py +++ b/app/database/crud/user.py @@ -28,6 +28,13 @@ from app.utils.validators import sanitize_telegram_name logger = logging.getLogger(__name__) +def _normalize_language_code(language: str | None, fallback: str = 'ru') -> str: + normalized = (language or '').strip().lower() + if '-' in normalized: + normalized = normalized.split('-', 1)[0] + return normalized or fallback + + def _build_spending_stats_select(): """ Возвращает базовый SELECT для статистики трат пользователей. @@ -232,6 +239,7 @@ async def create_user_no_commit( if not referral_code: referral_code = await create_unique_referral_code(db) + normalized_language = _normalize_language_code(language) default_group = await _get_or_create_default_promo_group(db) promo_group_id = default_group.id @@ -243,7 +251,7 @@ async def create_user_no_commit( username=username, first_name=safe_first, last_name=safe_last, - language=language, + language=normalized_language, referred_by_id=referred_by_id, referral_code=referral_code, balance_kopeks=0, @@ -277,6 +285,7 @@ async def create_user( ) -> User: if not referral_code: referral_code = await create_unique_referral_code(db) + normalized_language = _normalize_language_code(language) attempts = 3 @@ -291,7 +300,7 @@ async def create_user( username=username, first_name=safe_first, last_name=safe_last, - language=language, + language=normalized_language, referred_by_id=referred_by_id, referral_code=referral_code, balance_kopeks=0, @@ -360,6 +369,8 @@ async def update_user(db: AsyncSession, user: User, **kwargs) -> User: for field, value in kwargs.items(): if field in ('first_name', 'last_name'): value = sanitize_telegram_name(value) + if field == 'language': + value = _normalize_language_code(value) if hasattr(user, field): setattr(user, field, value) @@ -1060,6 +1071,7 @@ async def create_user_by_email( Created User object """ referral_code = await create_unique_referral_code(db) + normalized_language = _normalize_language_code(language) default_group = await _get_or_create_default_promo_group(db) user = User( @@ -1071,7 +1083,7 @@ async def create_user_by_email( username=None, first_name=sanitize_telegram_name(first_name) if first_name else None, last_name=None, - language=language, + language=normalized_language, referred_by_id=referred_by_id, referral_code=referral_code, balance_kopeks=0, @@ -1283,6 +1295,7 @@ async def create_user_by_oauth( ) -> User: """Create a new user via OAuth provider.""" referral_code = await create_unique_referral_code(db) + normalized_language = _normalize_language_code(language) default_group = await _get_or_create_default_promo_group(db) column_name = _OAUTH_PROVIDER_COLUMNS.get(provider) @@ -1297,7 +1310,7 @@ async def create_user_by_oauth( username=sanitize_telegram_name(username) if username else None, first_name=sanitize_telegram_name(first_name) if first_name else None, last_name=sanitize_telegram_name(last_name) if last_name else None, - language=language, + language=normalized_language, referral_code=referral_code, balance_kopeks=0, has_had_paid_subscription=False, diff --git a/app/handlers/subscription/common.py b/app/handlers/subscription/common.py index ff9ac24e..c5800be0 100644 --- a/app/handlers/subscription/common.py +++ b/app/handlers/subscription/common.py @@ -416,8 +416,14 @@ def get_traffic_switch_keyboard( buttons.append([InlineKeyboardButton(text=button_text, callback_data=f'switch_traffic_{gb}')]) + language_code = (language or 'ru').split('-')[0].lower() buttons.append( - [InlineKeyboardButton(text='⬅️ Назад' if language == 'ru' else '⬅️ Back', callback_data='subscription_settings')] + [ + InlineKeyboardButton( + text='⬅️ Назад' if language_code in {'ru', 'fa'} else '⬅️ Back', + callback_data='subscription_settings', + ) + ] ) return InlineKeyboardMarkup(inline_keyboard=buttons) diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py index 785bf496..299590fb 100644 --- a/app/keyboards/inline.py +++ b/app/keyboards/inline.py @@ -247,6 +247,8 @@ _LANGUAGE_DISPLAY_NAMES = { 'zh-hant': '🇹🇼 中文 (繁體)', 'vi': '🇻🇳 Tiếng Việt', 'vi-vn': '🇻🇳 Tiếng Việt', + 'fa': '🇮🇷 فارسی', + 'fa-ir': '🇮🇷 فارسی', } @@ -1789,6 +1791,8 @@ def get_add_traffic_keyboard( from app.utils.pricing_utils import get_remaining_months texts = get_texts(language) + language_code = (language or DEFAULT_LANGUAGE).split('-')[0].lower() + use_russian_fallback = language_code in {'ru', 'fa'} months_multiplier = 1 period_text = '' @@ -1826,17 +1830,20 @@ def get_add_traffic_keyboard( total_discount = discount_per_month * months_multiplier if gb == 0: - if language == 'ru': + if use_russian_fallback: text = f'♾️ Безлимитный трафик - {total_price // 100} ₽{period_text}' else: text = f'♾️ Unlimited traffic - {total_price // 100} ₽{period_text}' - elif language == 'ru': + elif use_russian_fallback: text = f'📊 +{gb} ГБ трафика - {total_price // 100} ₽{period_text}' else: text = f'📊 +{gb} GB traffic - {total_price // 100} ₽{period_text}' if discount_percent > 0 and total_discount > 0: - text += f' (скидка {discount_percent}%: -{total_discount // 100}₽)' + if use_russian_fallback: + text += f' (скидка {discount_percent}%: -{total_discount // 100}₽)' + else: + text += f' (discount {discount_percent}%: -{total_discount // 100}₽)' buttons.append([InlineKeyboardButton(text=text, callback_data=f'add_traffic_{gb}')]) @@ -1861,6 +1868,8 @@ def get_add_traffic_keyboard_from_tariff( discount_percent: Процент скидки """ texts = get_texts(language) + language_code = (language or DEFAULT_LANGUAGE).split('-')[0].lower() + use_russian_fallback = language_code in {'ru', 'fa'} if not packages: return InlineKeyboardMarkup( @@ -1888,15 +1897,18 @@ def get_add_traffic_keyboard_from_tariff( discount_percent, ) - period_text = ' /мес' if language == 'ru' else ' /mo' + period_text = ' /мес' if use_russian_fallback else ' /mo' - if language == 'ru': + if use_russian_fallback: text = f'📊 +{gb} ГБ трафика - {discounted_price // 100} ₽{period_text}' else: text = f'📊 +{gb} GB traffic - {discounted_price // 100} ₽{period_text}' if discount_percent > 0 and discount_value > 0: - text += f' (скидка {discount_percent}%: -{discount_value // 100}₽)' + if use_russian_fallback: + text += f' (скидка {discount_percent}%: -{discount_value // 100}₽)' + else: + text += f' (discount {discount_percent}%: -{discount_value // 100}₽)' buttons.append([InlineKeyboardButton(text=text, callback_data=f'add_traffic_{gb}')]) diff --git a/app/localization/loader.py b/app/localization/loader.py index 2e490ad4..9e2248eb 100644 --- a/app/localization/loader.py +++ b/app/localization/loader.py @@ -231,7 +231,7 @@ def ensure_locale_templates() -> None: _copy_locale(template, destination / template.name) return - for locale_code in ('ru', 'en'): + for locale_code in ('ru', 'en', 'fa'): source_path = _DEFAULT_LOCALES_DIR / f'{locale_code}.json' target_path = destination / f'{locale_code}.json' diff --git a/app/localization/locales/fa.json b/app/localization/locales/fa.json new file mode 100644 index 00000000..a16e482c --- /dev/null +++ b/app/localization/locales/fa.json @@ -0,0 +1,1720 @@ +{ + "ACCESS_DENIED": "❌ Доступ запрещен", + "ADDON_INSUFFICIENT_FUNDS_MESSAGE": "⚠️ Недостаточно средств\n\nСтоимость услуги: {required}\nНа балансе: {balance}\nНе хватает: {missing}\n\nВыберите способ пополнения. Сумма подставится автоматически.", + "ADD_COUNTRIES_BUTTON": "🌐 Добавить страны", + "ADD_TRAFFIC_PROMPT": "📈 Добавить трафик к подписке\n\nТекущий лимит: {current_traffic}\nВыберите дополнительный трафик:", + "BUY_TRAFFIC_BUTTON": "📈 Докупить трафик", + "ADMIN_BACK_TO_ADMIN": "⬅️ Назад в админку", + "ADMIN_BACK_TO_LIST": "⬅️ К списку", + "ADMIN_BACK_TO_MAIN": "🏠 В главное меню", + "ADMIN_BACK_TO_MONITORING": "⬅️ Назад к мониторингу", + "ADMIN_BACK_TO_SQUADS": "⬅️ Назад к сквадам", + "ADMIN_BROADCAST_ADD_DOCUMENT": "📄 Добавить документ", + "ADMIN_BROADCAST_ADD_PHOTO": "📷 Добавить фото", + "ADMIN_BROADCAST_ADD_VIDEO": "🎥 Добавить видео", + "ADMIN_BROADCAST_BUTTON_BALANCE": "💰 Пополнить баланс", + "ADMIN_BROADCAST_BUTTON_CONNECT": "🔗 Подключиться", + "ADMIN_BROADCAST_BUTTON_HOME": "🏠 На главную", + "ADMIN_BROADCAST_BUTTON_PROMOCODE": "🎫 Промокод", + "ADMIN_BROADCAST_BUTTON_REFERRALS": "🤝 Партнерка", + "ADMIN_BROADCAST_BUTTON_SUBSCRIPTION": "📱 Подписка", + "ADMIN_BROADCAST_BUTTON_SUPPORT": "🛠️ Техподдержка", + "ADMIN_BROADCAST_CHANGE_MEDIA": "🖼️ Изменить медиа", + "ADMIN_BROADCAST_NO_MEDIA": "⏭️ Без медиа", + "ADMIN_BROADCAST_REPLACE_MEDIA": "🔄 Заменить медиа", + "ADMIN_BROADCAST_SKIP_MEDIA": "⏭️ Пропустить медиа", + "ADMIN_BROADCAST_TARGET_ACTIVE": "📱 С подпиской", + "ADMIN_BROADCAST_TARGET_ACTIVE_ZERO": "🧊 Активна 0 ГБ", + "ADMIN_BROADCAST_TARGET_ALL": "👥 Всем", + "ADMIN_BROADCAST_TARGET_EXPIRED": "🔚 Истекшие", + "ADMIN_BROADCAST_TARGET_EXPIRING": "⏰ Истекающие", + "ADMIN_BROADCAST_TARGET_NO_SUB": "❌ Без подписки", + "ADMIN_BROADCAST_TARGET_TRIAL": "🎁 Триал", + "ADMIN_BROADCAST_TARGET_TRIAL_ZERO": "🥶 Триал 0 ГБ", + "ADMIN_BROADCAST_USE_MEDIA": "✅ Использовать это медиа", + "ADMIN_CAMPAIGNS": "📣 Рекламные кампании", + "ADMIN_CAMPAIGNS_CREATE": "➕ Создать", + "ADMIN_CAMPAIGNS_GENERAL_STATS": "📊 Общая статистика", + "ADMIN_CAMPAIGNS_LIST": "📋 Список кампаний", + "ADMIN_CAMPAIGN_BONUS_BALANCE": "💰 Бонус на баланс", + "ADMIN_CAMPAIGN_BONUS_SUBSCRIPTION": "📱 Бонус на подписку", + "ADMIN_CAMPAIGN_DELETE": "🗑️ Удалить", + "ADMIN_CAMPAIGN_DEVICES": "📱 Устройства", + "ADMIN_CAMPAIGN_DISABLE": "🔴 Выключить", + "ADMIN_CAMPAIGN_DURATION": "📅 Длительность", + "ADMIN_CAMPAIGN_EDIT": "✏️ Редактировать", + "ADMIN_CAMPAIGN_EDIT_NAME": "✏️ Название", + "ADMIN_CAMPAIGN_EDIT_START": "🔗 Параметр", + "ADMIN_CAMPAIGN_ENABLE": "🟢 Включить", + "ADMIN_CAMPAIGN_SERVERS": "🌍 Серверы", + "ADMIN_CAMPAIGN_STATS": "📊 Статистика", + "ADMIN_CAMPAIGN_TRAFFIC": "🌐 Трафик", + "ADMIN_CONTESTS": "🏆 Конкурсы", + "ADMIN_CONTESTS_CREATE": "➕ Новый конкурс", + "ADMIN_CONTESTS_DISABLED": "Конкурсы отключены через переменную окружения CONTESTS_ENABLED.", + "ADMIN_CONTESTS_LIST": "📋 Текущие конкурсы", + "ADMIN_CONTESTS_REFERRAL": "🤝 Реферальные конкурсы", + "ADMIN_CONTESTS_DAILY": "📆 Ежедневные конкурсы", + "ADMIN_CONTESTS_COMING_SOON": "Функционал появится позже.", + "ADMIN_CONTESTS_LIST_HEADER": "🏆 Конкурсы\n", + "ADMIN_CONTESTS_EMPTY": "Пока нет созданных конкурсов.", + "ADMIN_CONTESTS_TITLE": "🏆 Конкурсы\n\nВыберите действие:", + "ADMIN_CONTEST_MODE_PAID": "💳 Реферал с покупкой", + "ADMIN_CONTEST_MODE_REGISTERED": "🧑‍🤝‍🧑 Просто реферал", + "ADMIN_CONTEST_MODE_PROMPT": "Выберите условие зачёта: реферал должен купить подписку или достаточно регистрации.", + "ADMIN_CONTEST_ENTER_TITLE": "Введите название конкурса:", + "ADMIN_CONTEST_ENTER_DESCRIPTION": "Опишите конкурс (или отправьте '-' чтобы пропустить):", + "ADMIN_CONTEST_ENTER_PRIZE": "Укажите призы/выгоды конкурса (или '-' чтобы пропустить):", + "ADMIN_CONTEST_ENTER_START": "Введите дату и время старта (дд.мм.гггг чч:мм) по вашему часовому поясу:", + "ADMIN_CONTEST_ENTER_END": "Введите дату и время окончания (дд.мм.гггг чч:мм) по вашему часовому поясу:", + "ADMIN_CONTEST_ENTER_DAILY_TIME": "Во сколько отправлять ежедневные итоги? Можно несколько через запятую, формат ЧЧ:ММ (например, 12:00 или 12:00,18:00).", + "ADMIN_CONTEST_INVALID_DATE": "Не удалось распознать дату. Формат: 01.06.2024 12:00", + "ADMIN_CONTEST_INVALID_TIME": "Не удалось распознать время. Формат: 12:00", + "ADMIN_CONTEST_END_BEFORE_START": "Дата окончания должна быть позже даты начала.", + "ADMIN_CONTEST_CREATED": "Конкурс создан!", + "ADMIN_CONTEST_PRIZE": "Приз: {prize}", + "ADMIN_CONTEST_LAST_DAILY": "Последняя сводка: {date}", + "ADMIN_CONTEST_STATUS_ACTIVE": "🟢 Активен", + "ADMIN_CONTEST_STATUS_INACTIVE": "⚪️ Выключен", + "ADMIN_CONTEST_TOTAL_EVENTS": "Зачётов: {count}", + "ADMIN_CONTEST_LEADERBOARD_TITLE": "📊 Топ участников:", + "ADMIN_CONTEST_LEADERBOARD": "📊 Лидеры", + "ADMIN_CONTEST_ENABLE": "▶️ Запустить", + "ADMIN_CONTEST_DISABLE": "⏸️ Остановить", + "ADMIN_CONTEST_START_MANUAL": "🧪 Ручной старт", + "ADMIN_CONTEST_EDIT_SUMMARY_TIMES": "🕒 Итоги в день", + "ADMIN_CONTEST_DELETE": "🗑 Удалить", + "ADMIN_CONTEST_DELETE_RESTRICT": "Удалять можно только завершённые конкурсы.", + "ADMIN_CONTEST_DELETED": "Конкурс удалён.", + "ADMIN_CONTEST_NOT_FOUND": "Конкурс не найден.", + "ADMIN_CONTEST_EMPTY_LEADERBOARD": "Пока нет участников.", + "ADMIN_DAILY_CONTESTS_TITLE": "📆 Ежедневные конкурсы", + "ADMIN_EDIT_PRIZE": "🏅 Приз (дни)", + "ADMIN_EDIT_MAX_WINNERS": "👥 Победителей", + "ADMIN_EDIT_ATTEMPTS": "🔁 Попытки", + "ADMIN_EDIT_TIMES": "⏰ Раундов/день", + "ADMIN_EDIT_SCHEDULE": "🕒 Расписание", + "ADMIN_EDIT_COOLDOWN": "⌛ Длительность", + "ADMIN_EDIT_PAYLOAD": "🧩 Payload", + "ADMIN_CONTEST_FIELD_PROMPT": "Введите новое значение для {label}:", + "ADMIN_CONTEST_START_NOW": "Запустить раунд сейчас", + "ADMIN_RESET_ATTEMPTS": "🔄 Сбросить попытки", + "ADMIN_CLOSE_ROUND": "❌ Закрыть раунд", + "ADMIN_ROUND_STARTED": "Раунд запущен", + "ADMIN_UPDATED": "Обновлено", + "ADMIN_INVALID_NUMBER": "Некорректное число", + "ADMIN_INVALID_JSON": "Некорректный JSON", + "CONTEST_MENU_TITLE": "🎲 Игры/Конкурсы\nВыберите игру:", + "CONTESTS_BUTTON": "🎲 Конкурсы", + "CONTEST_EMPTY": "Сейчас игр нет", + "CONTEST_NOT_ELIGIBLE": "Игры доступны только с активной или триальной подпиской.", + "CONTEST_ROUND_FINISHED": "Раунд завершён или недоступен.", + "CONTEST_ALREADY_PLAYED": "У вас уже была попытка в этом раунде.", + "CONTEST_UNKNOWN": "Тип конкурса не поддерживается.", + "CONTEST_QUEST_PROMPT": "Выбери один из узлов 3×3:", + "CONTEST_LOCKS_PROMPT": "Найди взломанную кнопку среди замков:", + "CONTEST_SERVER_PROMPT": "Выбери сервер:", + "CONTEST_CIPHER_PROMPT": "Расшифруй: {q}", + "CONTEST_EMOJI_PROMPT": "Угадай сервис по эмодзи: {q}", + "CONTEST_ANAGRAM_PROMPT": "Составь слово: {letters}", + "CONTEST_BLITZ_PROMPT": "⚡️ Блиц! Нажми «Я здесь!»", + "CONTEST_BLITZ_BUTTON": "Я здесь!", + "CONTEST_WIN": "🎉 Победа! ", + "CONTEST_LOSE": "Не верно, попробуй снова в следующем раунде.", + "CONTEST_PRIZE_GRANTED": "Бонус {days} дней зачислен!", + "ADMIN_CANCEL": "❌ Отмена", + "ADMIN_COMMUNICATIONS_MENU_MESSAGES": "📢 Сообщения в меню", + "ADMIN_COMMUNICATIONS_PROMO_OFFERS": "🎯 Промо-предложения", + "ADMIN_COMMUNICATIONS_SUBMENU_DESCRIPTION": "Управление рассылками и текстами интерфейса:", + "ADMIN_COMMUNICATIONS_SUBMENU_TITLE": "📨 **Коммуникации**\n\n", + "ADMIN_COMMUNICATIONS_WELCOME_TEXT": "👋 Приветственный текст", + "ADMIN_CONTINUE": "✅ Продолжить", + "ADMIN_CRITERIA_ACTIVE_TODAY": "⚡ Активные сегодня", + "ADMIN_CRITERIA_DIRECT": "🎯 Прямая регистрация", + "ADMIN_CRITERIA_INACTIVE_MONTH": "💤 Неактивные 30+ дней", + "ADMIN_CRITERIA_INACTIVE_WEEK": "💤 Неактивные 7+ дней", + "ADMIN_CRITERIA_MONTH": "📅 За месяц", + "ADMIN_CRITERIA_PROMOCODES": "🎫 Использовали промокоды", + "ADMIN_CRITERIA_REFERRALS": "🤝 Через рефералов", + "ADMIN_CRITERIA_TODAY": "📅 Сегодня", + "ADMIN_CRITERIA_WEEK": "📅 За неделю", + "ADMIN_FAQ_ACTION_PROMPT": "Выберите действие:", + "ADMIN_FAQ_ADD_PAGE_BUTTON": "➕ Добавить страницу", + "ADMIN_FAQ_BACK_TO_LIST": "⬅️ К настройкам FAQ", + "ADMIN_FAQ_CANCEL_BUTTON": "⬅️ Отмена", + "ADMIN_FAQ_CONTENT_EMPTY": "❌ Текст не может быть пустым.", + "ADMIN_FAQ_CONTENT_TOO_LONG": "❌ Текст слишком длинный. Максимум 6000 символов.", + "ADMIN_FAQ_CONTENT_UPDATED": "✅ Текст страницы обновлён.", + "ADMIN_FAQ_DESCRIPTION": "FAQ отображается в разделе «Инфо».", + "ADMIN_FAQ_DISABLED_ALERT": "🚫 FAQ отключён.", + "ADMIN_FAQ_DISABLE_BUTTON": "🚫 Отключить показ", + "ADMIN_FAQ_EDIT_CONTENT_BUTTON": "📝 Изменить текст", + "ADMIN_FAQ_EDIT_TITLE_BUTTON": "✏️ Изменить заголовок", + "ADMIN_FAQ_ENABLED_ALERT": "✅ FAQ включён.", + "ADMIN_FAQ_ENABLE_BUTTON": "✅ Включить показ", + "ADMIN_FAQ_ENTER_CONTENT": "Отправьте содержимое страницы FAQ. Допускается HTML.", + "ADMIN_FAQ_ENTER_TITLE": "Введите заголовок для новой страницы FAQ:", + "ADMIN_FAQ_HEADER": "❓ FAQ", + "ADMIN_FAQ_HTML_ERROR": "❌ Ошибка в HTML: {error}", + "ADMIN_FAQ_HTML_HELP": "ℹ️ HTML помощь", + "ADMIN_FAQ_LANGUAGE": "Язык: {lang}", + "ADMIN_FAQ_PAGES_EMPTY": "Страницы ещё не созданы.", + "ADMIN_FAQ_PAGES_OVERVIEW": "Список страниц:\n{items}", + "ADMIN_FAQ_PAGE_CREATED": "✅ Страница FAQ создана.", + "ADMIN_FAQ_PAGE_DELETED": "🗑️ Страница удалена.", + "ADMIN_FAQ_PAGE_DELETE_BUTTON": "🗑️ Удалить", + "ADMIN_FAQ_PAGE_DISABLED_ALERT": "🚫 Страница выключена.", + "ADMIN_FAQ_PAGE_DISABLE_BUTTON": "🚫 Выключить страницу", + "ADMIN_FAQ_PAGE_ENABLED_ALERT": "✅ Страница включена.", + "ADMIN_FAQ_PAGE_ENABLE_BUTTON": "✅ Включить страницу", + "ADMIN_FAQ_PAGE_HEADER": "📄 Страница FAQ", + "ADMIN_FAQ_PAGE_MOVE_DOWN": "⬇️ Ниже", + "ADMIN_FAQ_PAGE_MOVE_UP": "⬆️ Выше", + "ADMIN_FAQ_PAGE_NOT_FOUND": "⚠️ Страница не найдена.", + "ADMIN_FAQ_PAGE_PREVIEW": "Превью:\n{content}", + "ADMIN_FAQ_PAGE_PREVIEW_EMPTY": "Текст ещё не задан.", + "ADMIN_FAQ_PAGE_REORDERED": "✅ Порядок обновлён.", + "ADMIN_FAQ_PAGE_STATS": "Всего страниц: {total}", + "ADMIN_FAQ_PAGE_STATUS": "Статус: {status}", + "ADMIN_FAQ_PAGE_STATUS_ACTIVE": "✅ Активна", + "ADMIN_FAQ_PAGE_STATUS_INACTIVE": "🚫 Выключена", + "ADMIN_FAQ_PAGE_TITLE": "Заголовок: {title}", + "ADMIN_FAQ_PAGE_UPDATED": "Обновлено: {timestamp}", + "ADMIN_FAQ_STATUS_DISABLED": "⚠️ Показ FAQ выключен.", + "ADMIN_FAQ_STATUS_EMPTY": "⚠️ FAQ ещё не настроен.", + "ADMIN_FAQ_STATUS_ENABLED": "✅ FAQ включён. Активных страниц: {count}.", + "ADMIN_FAQ_STATUS_ENABLED_EMPTY": "⚠️ FAQ включён, но нет активных страниц.", + "ADMIN_FAQ_TITLE_EMPTY": "❌ Заголовок не может быть пустым.", + "ADMIN_FAQ_TITLE_TOO_LONG": "❌ Заголовок слишком длинный. Максимум 255 символов.", + "ADMIN_FAQ_TITLE_UPDATED": "✅ Заголовок обновлён.", + "ADMIN_FAQ_UNEXPECTED_STATE": "⚠️ Состояние сброшено.", + "ADMIN_HISTORY_REFRESH": "🔄 Обновить", + "ADMIN_MAINTENANCE_CHECK_API": "🔍 Проверить API", + "ADMIN_MAINTENANCE_DISABLE": "🟢 Выключить техработы", + "ADMIN_MAINTENANCE_ENABLE": "🔧 Включить техработы", + "ADMIN_MAINTENANCE_PANEL_STATUS": "🌐 Статус панели", + "ADMIN_MAINTENANCE_SEND_NOTIFICATION": "📢 Отправить уведомление", + "ADMIN_MAINTENANCE_START_MONITORING": "▶️ Запустить мониторинг", + "ADMIN_MAINTENANCE_STOP_MONITORING": "⏹️ Остановить мониторинг", + "ADMIN_MAIN_MENU": "🏠 Главное меню", + "ADMIN_MAIN_MESSAGES": "📨 Сообщения", + "ADMIN_MAIN_PRICING": "💰 Цены", + "ADMIN_MAIN_PROMO_STATS": "💰 Промокоды/Статистика", + "ADMIN_MAIN_SERVERS": "🌐 Серверы", + "ADMIN_MAIN_SETTINGS": "⚙️ Настройки", + "ADMIN_MAIN_SUPPORT": "🛟 Поддержка", + "ADMIN_MAIN_SYSTEM": "🛠️ Система", + "ADMIN_MAIN_TARIFFS": "📦 Тарифы", + "ADMIN_MAIN_TRIALS": "🧪 Триалы", + "ADMIN_MAIN_PAYMENTS": "💳 Пополнения", + "ADMIN_MAIN_USERS_SUBSCRIPTIONS": "👥 Юзеры/Подписки", + "ADMIN_MESSAGES": "📨 Рассылки", + "ADMIN_MESSAGES_ALL_USERS": "📨 Всем пользователям", + "ADMIN_MESSAGES_BY_CRITERIA": "🔍 По критериям", + "ADMIN_MESSAGES_BY_SUBSCRIPTIONS": "🎯 По подпискам", + "ADMIN_MESSAGES_HISTORY": "📋 История", + "ADMIN_PINNED_MESSAGE": "📌 Закрепленное сообщение", + "ADMIN_PINNED_MESSAGE_UPDATE": "✏️ Обновить", + "ADMIN_PINNED_MESSAGE_DELETE": "🗑️ Удалить и отключить", + "ADMIN_PINNED_POSITION_BEFORE": "⬆️ Показать перед меню", + "ADMIN_PINNED_POSITION_AFTER": "⬇️ Показать после меню", + "ADMIN_PINNED_START_EVERY_TIME": "🔁 Показать при каждом /start", + "ADMIN_PINNED_START_ONCE": "🚫 Показывать только один раз", + "ADMIN_PINNED_NO_CONTENT": "❌ Не удалось прочитать текст или медиа в сообщении, попробуйте снова.", + "ADMIN_PINNED_SAVING": "📌 Сообщение сохранено. Начинаю отправку и закрепление у пользователей...", + "ADMIN_PINNED_UPDATED": "✅ Закрепленное сообщение обновлено\n\n👥 Получателей: {total}\n✅ Отправлено: {sent}\n⚠️ Ошибок: {failed}", + "ADMIN_PINNED_SAVED_ASK_BROADCAST": "📌 Сообщение сохранено!\n\nВыберите, как доставить сообщение пользователям:\n\n• Разослать сейчас — отправит и закрепит у всех активных пользователей\n• Только при /start — пользователи увидят при следующем запуске бота", + "ADMIN_PINNED_SAVED_NO_BROADCAST": "✅ Закрепленное сообщение сохранено\n\nРассылка не выполнена. Пользователи увидят сообщение при следующем вводе /start.", + "ADMIN_PINNED_BROADCAST_NOW": "📨 Разослать сейчас всем", + "ADMIN_PINNED_BROADCAST_ON_START": "⏳ Только при /start", + "ADMIN_MONITORING": "🔍 Мониторинг", + "ADMIN_MONITORING_ALL_LOGS": "📋 Все логи", + "ADMIN_MONITORING_AUTOPAY_SETTINGS": "💳 Настройки автооплаты", + "ADMIN_MONITORING_AUTO_CLEANUP": "🧹 Автоочистка логов", + "ADMIN_MONITORING_BACK_TO_LOGS": "⬅️ К списку логов", + "ADMIN_MONITORING_CHECK_NOW": "🔄 Проверить сейчас", + "ADMIN_MONITORING_CLEAR": "🗑️ Очистить", + "ADMIN_MONITORING_CLEAR_ALL": "🗑️ Очистить ВСЕ логи", + "ADMIN_MONITORING_CLEAR_OLD": "🗑️ Очистить старые", + "ADMIN_MONITORING_CONFIRM_CLEAR": "✅ Да, очистить", + "ADMIN_MONITORING_DELETE_LOG": "🗑️ Удалить этот лог", + "ADMIN_MONITORING_FILTER_AUTOPAY": "💳 Автооплаты", + "ADMIN_MONITORING_FILTER_CYCLES": "🔄 Циклы мониторинга", + "ADMIN_MONITORING_FILTER_ERRORS": "❌ Ошибки", + "ADMIN_MONITORING_FILTER_SUCCESS": "✅ Успешные", + "ADMIN_MONITORING_FORCE_CHECK": "🔄 Принудительная проверка", + "ADMIN_MONITORING_LOGS": "📋 Логи", + "ADMIN_MONITORING_NOTIFICATIONS": "🔔 Уведомления", + "ADMIN_MONITORING_RESTART": "🔄 Перезапустить", + "ADMIN_MONITORING_SETTINGS": "⚙️ Настройки мониторинга", + "ADMIN_MONITORING_SETTINGS_BUTTON": "⚙️ Настройки", + "ADMIN_MONITORING_SET_INTERVAL": "⏱️ Интервал проверки", + "ADMIN_MONITORING_START": "▶️ Запустить", + "ADMIN_MONITORING_STATISTICS": "📊 Статистика", + "ADMIN_MONITORING_STATUS": "📊 Статус", + "ADMIN_MONITORING_STOP": "⏸️ Остановить", + "ADMIN_MONITORING_STOP_HARD": "⏹️ Остановить", + "ADMIN_MONITORING_TEST_NOTIFICATIONS": "🧪 Тест уведомлений", + "ADMIN_PAYMENTS_TITLE": "💳 Проверка пополнений", + "ADMIN_PAYMENTS_DESCRIPTION": "Список счетов на пополнение, созданных за последние 24 часа и ожидающих оплаты.", + "ADMIN_PAYMENTS_NOTICE": "Проверять можно только счета моложе 24 часов и со статусом ожидания.", + "ADMIN_TRIALS_TITLE": "🧪 Управление триалами", + "ADMIN_TRIALS_STATS": "• Использовано всего: {used}\n• Активно сейчас: {active}\n• Доступно к сбросу: {resettable}", + "ADMIN_TRIALS_RESET_BUTTON": "♻️ Сбросить все триалы", + "ADMIN_TRIALS_RESET_RESULT": "♻️ Сбросили {reset_count} триалов.\n\n• Использовано всего: {used}\n• Активно сейчас: {active}\n• Доступно к сбросу: {resettable}", + "ADMIN_TRIALS_RESET_TOAST": "✅ Сброс завершен", + "ADMIN_PAYMENTS_EMPTY": "За последние 24 часа не найдено счетов на пополнение в ожидании.", + "ADMIN_PAYMENTS_ITEM_DETAILS": "📄 №{number}", + "ADMIN_PAYMENT_STATUS_PENDING": "Ожидает оплаты", + "ADMIN_PAYMENT_STATUS_PROCESSING": "Обрабатывается", + "ADMIN_PAYMENT_STATUS_PAID": "Оплачен", + "ADMIN_PAYMENT_STATUS_FAILED": "Ошибка", + "ADMIN_PAYMENT_STATUS_CANCELED": "Отменён", + "ADMIN_PAYMENT_STATUS_UNKNOWN": "Статус неизвестен", + "ADMIN_PAYMENT_STATUS_ON_HOLD": "На удержании", + "ADMIN_PAYMENT_STATUS_EXPIRED": "Просрочен", + "ADMIN_PAYMENT_DETAILS_TITLE": "💳 Детали платежа", + "ADMIN_PAYMENT_AMOUNT": "Сумма", + "ADMIN_PAYMENT_CREATED": "Создан", + "ADMIN_PAYMENT_EXPIRES": "Истекает", + "ADMIN_PAYMENT_GATEWAY_STATUS": "Статус в платёжке", + "ADMIN_PAYMENT_GATEWAY_METHOD": "Метод оплаты", + "ADMIN_PAYMENT_GATEWAY_AMOUNT": "Сумма в платёжке", + "ADMIN_PAYMENT_GATEWAY_ACCOUNT": "Счёт плательщика", + "ADMIN_PAYMENT_GATEWAY_ID": "ID в платёжке", + "ADMIN_PAYMENT_PAYER_AMOUNT": "Оплачено", + "ADMIN_PAYMENT_CRYPTO_AMOUNT": "Сумма в криптовалюте", + "ADMIN_PAYMENT_HAS_LINK": "🔗 Ссылка на оплату доступна в кнопке выше.", + "ADMIN_PAYMENT_OPEN_LINK": "🔗 Открыть ссылку", + "ADMIN_PAYMENT_CHECK_BUTTON": "🔁 Проверить статус", + "ADMIN_PAYMENT_CHECK_HINT": "ℹ️ Можно запустить ручную проверку статуса.", + "ADMIN_PAYMENT_CHECK_NOT_AVAILABLE": "Для этого счёта ручная проверка недоступна.", + "ADMIN_PAYMENT_CHECK_FAILED": "Не удалось обновить статус платежа.", + "ADMIN_PAYMENT_CHECK_SUCCESS": "Статус обновлён: {status}", + "ADMIN_PAYMENT_CHECK_NO_CHANGES": "Статус не изменился после проверки.", + "ADMIN_PAYMENT_NOT_FOUND": "Платёж не найден.", + "ADMIN_NODE_DISABLE": "⏸️ Отключить", + "ADMIN_NODE_ENABLE": "▶️ Включить", + "ADMIN_NODE_RESTART": "🔄 Перезагрузить", + "ADMIN_NODE_STATS": "📊 Статистика", + "ADMIN_PANEL": "\n⚙️ Административная панель\n\nВыберите раздел для управления:\n", + "ADMIN_PERIOD_ALL": "📅 Все время", + "ADMIN_PERIOD_MONTH": "📅 Месяц", + "ADMIN_PERIOD_TODAY": "📅 Сегодня", + "ADMIN_PERIOD_WEEK": "📅 Неделя", + "ADMIN_PERIOD_YESTERDAY": "📅 Вчера", + "ADMIN_PRICING_BUTTON_CORE": "⚙️ Базовые лимиты", + "ADMIN_PRICING_BUTTON_EXTRA": "➕ Дополнительно", + "ADMIN_PRICING_BUTTON_PERIODS": "🗓 Периоды подписки", + "ADMIN_PRICING_BUTTON_PERIOD_OPTIONS": "🗓 Доступные периоды", + "ADMIN_PRICING_BUTTON_TRAFFIC": "📦 Пакеты трафика", + "ADMIN_PRICING_BUTTON_TRAFFIC_OPTIONS": "🚦 Отображение пакетов", + "ADMIN_PRICING_BUTTON_TRIAL": "🎁 Пробный период", + "ADMIN_PRICING_CHOICE_ALREADY": "Это значение уже активно.", + "ADMIN_PRICING_CHOICE_UPDATED": "Выбрано: {label}", + "ADMIN_PRICING_EDIT_CANCEL": "❌ Отмена", + "ADMIN_PRICING_EDIT_CANCELLED": "Изменения отменены.", + "ADMIN_PRICING_EDIT_CANCEL_HINT": "Напишите «Отмена», чтобы вернуться без изменений.", + "ADMIN_PRICING_EDIT_CURRENT": "Текущее значение", + "ADMIN_PRICING_EDIT_EXPIRED": "Сессия редактирования истекла.", + "ADMIN_PRICING_EDIT_INVALID": "Не удалось распознать цену. Укажите число в рублях (например 990 или 990.50).", + "ADMIN_PRICING_EDIT_PROMPT": "Введите новую стоимость в рублях (например 990 или 990.50). Для бесплатного тарифа укажите 0.", + "ADMIN_PRICING_EDIT_SUCCESS": "Цена для {item} обновлена: {price}", + "ADMIN_PRICING_EDIT_TARGET": "Текущий тариф", + "ADMIN_PRICING_EDIT_TITLE": "Изменение цены", + "ADMIN_PRICING_MENU_DESCRIPTION": "Быстрый доступ к тарифам подписок, пакетам трафика и дополнительным услугам.", + "ADMIN_PRICING_MENU_PROMPT": "Выберите раздел для редактирования:", + "ADMIN_PRICING_MENU_SUMMARY": "Краткая сводка:", + "ADMIN_PRICING_MENU_SUMMARY_CORE": "• Базовые лимиты: {summary}", + "ADMIN_PRICING_MENU_SUMMARY_EXTRA": "• Дополнительно: {summary}", + "ADMIN_PRICING_MENU_SUMMARY_PERIODS": "• Периоды: {summary}", + "ADMIN_PRICING_MENU_SUMMARY_PERIOD_OPTIONS": "• Доступные периоды: {summary}", + "ADMIN_PRICING_MENU_SUMMARY_TRAFFIC": "• Трафик: {summary}", + "ADMIN_PRICING_MENU_SUMMARY_TRIAL": "• Триал: {summary}", + "ADMIN_PRICING_MENU_TITLE": "Управление ценами", + "ADMIN_PRICING_PERIOD_DISABLED": "Период отключен.", + "ADMIN_PRICING_PERIOD_ENABLED": "Период включен.", + "ADMIN_PRICING_PERIOD_MIN": "Должен оставаться хотя бы один период.", + "ADMIN_PRICING_SECTION_CORE_TITLE": "⚙️ Базовые лимиты", + "ADMIN_PRICING_SECTION_CURRENT": "Текущие значения:", + "ADMIN_PRICING_SECTION_EMPTY": "Нет доступных значений.", + "ADMIN_PRICING_SECTION_EXTRA_TITLE": "➕ Дополнительные опции", + "ADMIN_PRICING_SECTION_PERIODS_TITLE": "🗓 Периоды подписки", + "ADMIN_PRICING_SECTION_PERIOD_OPTIONS_PROMPT": "Нажмите на период, чтобы включить или выключить его отображение.", + "ADMIN_PRICING_SECTION_PERIOD_OPTIONS_RENEW": "Активные периоды продления: {items}", + "ADMIN_PRICING_SECTION_PERIOD_OPTIONS_SUB": "Активные периоды подписки: {items}", + "ADMIN_PRICING_SECTION_PERIOD_OPTIONS_TITLE": "🗓 Доступные периоды", + "ADMIN_PRICING_SECTION_PROMPT": "Выберите что изменить:", + "ADMIN_PRICING_SECTION_SETTINGS_GENERIC": "⚙️ Настройки", + "ADMIN_PRICING_SECTION_TRAFFIC_OPTIONS_ACTIVE": "Активные пакеты: {items}", + "ADMIN_PRICING_SECTION_TRAFFIC_OPTIONS_NONE": "Активных пакетов нет.", + "ADMIN_PRICING_SECTION_TRAFFIC_OPTIONS_PROMPT": "Нажмите на пакет, чтобы включить или выключить его отображение.", + "ADMIN_PRICING_SECTION_TRAFFIC_OPTIONS_TITLE": "🚦 Отображение пакетов трафика", + "ADMIN_PRICING_SECTION_TRAFFIC_TITLE": "📦 Пакеты трафика", + "ADMIN_PRICING_SECTION_TRIAL_TITLE": "🎁 Пробный период", + "ADMIN_PRICING_SETTING_CANCEL_HINT": "Чтобы вернуться без изменений, ответьте «Отмена».", + "ADMIN_PRICING_SETTING_CURRENT": "Текущее значение", + "ADMIN_PRICING_SETTING_EDIT_TITLE": "Настройка параметра", + "ADMIN_PRICING_SETTING_EDIT_WITH_VALUE": "✏️ {label} • {value}", + "ADMIN_PRICING_SETTING_EXAMPLE": "Пример", + "ADMIN_PRICING_SETTING_FORMAT": "Формат ввода", + "ADMIN_PRICING_SETTING_INVALID": "Не удалось обновить параметр. Проверьте формат значения.", + "ADMIN_PRICING_SETTING_PARAMETER": "Параметр", + "ADMIN_PRICING_SETTING_PROMPT": "Отправьте новое значение или напишите «Отмена». Для очистки используйте none.", + "ADMIN_PRICING_SETTING_SUCCESS": "Параметр {label} обновлен: {value}", + "ADMIN_PRICING_SETTING_TOGGLE_STATEFUL": "{icon} {label}", + "ADMIN_PRICING_SETTING_WARNING": "Важно", + "ADMIN_PRICING_SUMMARY_EMPTY": "—", + "ADMIN_PRICING_TRAFFIC_PACKAGE_DISABLED": "Пакет отключен.", + "ADMIN_PRICING_TRAFFIC_PACKAGE_ENABLED": "Пакет включен.", + "ADMIN_PRICING_TRAFFIC_PACKAGE_MIN": "Должен оставаться хотя бы один пакет.", + "ADMIN_PRIVACY_POLICY_ACTION_PROMPT": "Выберите действие:", + "ADMIN_PRIVACY_POLICY_BACK_BUTTON": "⬅️ К настройкам политики", + "ADMIN_PRIVACY_POLICY_CANCEL": "❌ Отмена", + "ADMIN_PRIVACY_POLICY_CURRENT_PREVIEW": "Текущий текст (превью):", + "ADMIN_PRIVACY_POLICY_DESCRIPTION": "Политика конфиденциальности отображается в разделе «Инфо».", + "ADMIN_PRIVACY_POLICY_DISABLED": "🚫 Политика отключена", + "ADMIN_PRIVACY_POLICY_DISABLE_BUTTON": "🚫 Отключить показ", + "ADMIN_PRIVACY_POLICY_EDIT_BUTTON": "✏️ Изменить текст", + "ADMIN_PRIVACY_POLICY_EDIT_HINT": "Используйте /html_help для справки по тегам.", + "ADMIN_PRIVACY_POLICY_EDIT_PROMPT": "Отправьте новый текст политики конфиденциальности. Допускается HTML-разметка.", + "ADMIN_PRIVACY_POLICY_EDIT_TITLE": "Редактирование политики", + "ADMIN_PRIVACY_POLICY_ENABLED": "✅ Политика включена", + "ADMIN_PRIVACY_POLICY_ENABLE_BUTTON": "✅ Включить показ", + "ADMIN_PRIVACY_POLICY_HEADER": "🛡️ Политика конфиденциальности", + "ADMIN_PRIVACY_POLICY_HTML_ERROR": "❌ Ошибка в HTML: {error}", + "ADMIN_PRIVACY_POLICY_HTML_HELP": "ℹ️ HTML помощь", + "ADMIN_PRIVACY_POLICY_LANGUAGE": "Язык: {lang}", + "ADMIN_PRIVACY_POLICY_PREVIEW_EMPTY": "Текст ещё не задан.", + "ADMIN_PRIVACY_POLICY_PREVIEW_EMPTY_ALERT": "Текст политики пока не задан.", + "ADMIN_PRIVACY_POLICY_PREVIEW_TITLE": "Превью текста:", + "ADMIN_PRIVACY_POLICY_RETURN_TO_EDIT": "⬅️ Назад к редактированию", + "ADMIN_PRIVACY_POLICY_SAVED": "✅ Политика конфиденциальности обновлена.", + "ADMIN_PRIVACY_POLICY_STATUS_DISABLED": "⚠️ Показ политики выключен или текст отсутствует.", + "ADMIN_PRIVACY_POLICY_STATUS_ENABLED": "✅ Политика активна и показывается пользователям.", + "ADMIN_PRIVACY_POLICY_STATUS_ENABLED_EMPTY": "⚠️ Политика включена, но текст пуст — пользователи её не увидят.", + "ADMIN_PRIVACY_POLICY_TOO_LONG": "❌ Текст политики слишком длинный. Максимум 4000 символов.", + "ADMIN_PRIVACY_POLICY_UPDATED_AT": "Последнее обновление: {timestamp}", + "ADMIN_PRIVACY_POLICY_VIEW_BUTTON": "👀 Просмотреть текущий текст", + "ADMIN_PRIVACY_POLICY_VIEW_TITLE": "👀 Текущий текст политики", + "ADMIN_PRIVACY_POLICY_VIEW_TRUNCATED": "\n\n⚠️ Текст сокращён для отображения. Полную версию увидят пользователи в меню.", + "ADMIN_PROMOCODES": "🎫 Промокоды", + "ADMIN_PROMOCODES_ALL": "🎫 Все промокоды", + "ADMIN_PROMOCODES_CREATE": "➕ Создать", + "ADMIN_PROMOCODES_GENERAL_STATS": "📊 Общая статистика", + "ADMIN_PROMOCODE_DELETE": "🗑️ Удалить", + "ADMIN_PROMOCODE_EDIT": "✏️ Редактировать", + "ADMIN_PROMOCODE_STATS": "📊 Статистика", + "ADMIN_PROMOCODE_TOGGLE": "🔄 Статус", + "ADMIN_PROMOCODE_TYPE_BALANCE": "💰 Баланс", + "ADMIN_PROMOCODE_TYPE_DAYS": "📅 Дни подписки", + "ADMIN_PROMOCODE_TYPE_TRIAL": "🎁 Триал", + "ADMIN_PROMOCODE_TYPE_PROMO_GROUP": "🏷️ Промогруппа", + "ADMIN_PROMOCODE_TYPE_DISCOUNT": "💸 Одноразовая скидка", + "ADMIN_PROMO_GROUPS": "💳 Промогруппы", + "ADMIN_PROMO_GROUPS_DEFAULT_LABEL": " (базовая)", + "ADMIN_PROMO_GROUPS_EMPTY": "Промогруппы не найдены.", + "ADMIN_PROMO_GROUPS_MEMBERS_COUNT": "Участников: {count}", + "ADMIN_PROMO_GROUPS_SUMMARY": "Всего групп: {count}\nВсего участников: {members}", + "ADMIN_PROMO_GROUPS_TITLE": "💳 Промогруппы", + "ADMIN_PROMO_GROUP_ADDON_DISCOUNT_DISABLED": "🧩 Скидки на доп. услуги: отключены", + "ADMIN_PROMO_GROUP_ADDON_DISCOUNT_ENABLED": "🧩 Скидки на доп. услуги: включены", + "ADMIN_PROMO_GROUP_ADDON_DISCOUNT_UPDATED_DISABLED": "🧩 Скидки на докупку доп. услуг отключены.", + "ADMIN_PROMO_GROUP_ADDON_DISCOUNT_UPDATED_ENABLED": "🧩 Скидки на докупку доп. услуг включены.", + "ADMIN_PROMO_GROUP_AUTO_ASSIGN_DISABLED": "Автовыдача по суммарным тратам: отключена", + "ADMIN_PROMO_GROUP_AUTO_ASSIGN_LINE": "Автовыдача по суммарным тратам: от {amount} ₽", + "ADMIN_PROMO_GROUP_CREATED": "Промогруппа «{name}» создана.", + "ADMIN_PROMO_GROUP_CREATED_BACK_BUTTON": "↩️ К промогруппам", + "ADMIN_PROMO_GROUP_CREATE_AUTO_ASSIGN_PROMPT": "Введите сумму общих трат (в ₽) для автоматической выдачи этой группы. Отправьте 0, чтобы отключить.", + "ADMIN_PROMO_GROUP_CREATE_DEVICES_PROMPT": "Введите скидку на устройства (0-100):", + "ADMIN_PROMO_GROUP_CREATE_NAME_PROMPT": "Введите название новой промогруппы:", + "ADMIN_PROMO_GROUP_CREATE_PERIOD_PROMPT": "Введите скидки на периоды подписки (например, 30:10, 90:15). Отправьте 0, если без скидок.", + "ADMIN_PROMO_GROUP_CREATE_SERVERS_PROMPT": "Введите скидку на серверы (0-100):", + "ADMIN_PROMO_GROUP_CREATE_TRAFFIC_PROMPT": "Введите скидку на трафик (0-100):", + "ADMIN_PROMO_GROUP_DELETED": "Промогруппа «{name}» удалена.", + "ADMIN_PROMO_GROUP_DELETE_BUTTON": "🗑️ Удалить", + "ADMIN_PROMO_GROUP_DELETE_CONFIRM": "Удалить промогруппу «{name}»? Все пользователи будут переведены в базовую группу.", + "ADMIN_PROMO_GROUP_DELETE_FORBIDDEN": "Базовую промогруппу нельзя удалить.", + "ADMIN_PROMO_GROUP_DETAILS_DEFAULT": "Это базовая группа.", + "ADMIN_PROMO_GROUP_DETAILS_MEMBERS": "Участников: {count}", + "ADMIN_PROMO_GROUP_DETAILS_TITLE": "💳 Промогруппа: {name}", + "ADMIN_PROMO_GROUP_DISCOUNTS_HEADER": "💸 Скидки промогруппы:", + "ADMIN_PROMO_GROUP_DISCOUNT_LINE_DEVICES": "• Устройства: {percent}%", + "ADMIN_PROMO_GROUP_DISCOUNT_LINE_SERVERS": "• Серверы: {percent}%", + "ADMIN_PROMO_GROUP_DISCOUNT_LINE_TRAFFIC": "• Трафик: {percent}%", + "ADMIN_PROMO_GROUP_EDIT_AUTO_ASSIGN_PROMPT": "Введите сумму общих трат (в ₽) для автовыдачи. Текущее значение: {current}.", + "ADMIN_PROMO_GROUP_EDIT_BUTTON": "✏️ Изменить", + "ADMIN_PROMO_GROUP_EDIT_DEVICES_PROMPT": "Введите новую скидку на устройства (0-100):", + "ADMIN_PROMO_GROUP_EDIT_FIELD_AUTO_ASSIGN": "🤖 Автовыдача по тратам", + "ADMIN_PROMO_GROUP_EDIT_FIELD_DEVICES": "📱 Скидка на устройства", + "ADMIN_PROMO_GROUP_EDIT_FIELD_NAME": "✏️ Изменить название", + "ADMIN_PROMO_GROUP_EDIT_FIELD_PERIODS": "⏳ Скидки по периодам", + "ADMIN_PROMO_GROUP_EDIT_FIELD_SERVERS": "🖥 Скидка на серверы", + "ADMIN_PROMO_GROUP_EDIT_FIELD_TRAFFIC": "🌐 Скидка на трафик", + "ADMIN_PROMO_GROUP_EDIT_MENU_HINT": "Выберите параметр для изменения:", + "ADMIN_PROMO_GROUP_EDIT_MENU_TITLE": "✏️ Настройки промогруппы «{name}»", + "ADMIN_PROMO_GROUP_EDIT_NAME_PROMPT": "Введите новое название промогруппы (текущее: {name}):", + "ADMIN_PROMO_GROUP_EDIT_PERIOD_PROMPT": "Введите новые скидки на периоды (текущие: {current}). Отправьте 0, если без скидок.", + "ADMIN_PROMO_GROUP_EDIT_SERVERS_PROMPT": "Введите новую скидку на серверы (0-100):", + "ADMIN_PROMO_GROUP_EDIT_TRAFFIC_PROMPT": "Введите новую скидку на трафик (0-100):", + "ADMIN_PROMO_GROUP_INVALID_AUTO_ASSIGN": "Введите неотрицательное число в рублях или 0 для отключения.", + "ADMIN_PROMO_GROUP_INVALID_NAME": "Название не может быть пустым.", + "ADMIN_PROMO_GROUP_INVALID_PERCENT": "Введите число от 0 до 100.", + "ADMIN_PROMO_GROUP_INVALID_PERIOD_DISCOUNTS": "Введите пары период:скидка через запятую, например 30:10, 90:15, или 0.", + "ADMIN_PROMO_GROUP_MEMBERS_BUTTON": "👥 Участники", + "ADMIN_PROMO_GROUP_MEMBERS_EMPTY": "В этой группе пока нет участников.", + "ADMIN_PROMO_GROUP_MEMBERS_TITLE": "👥 Участники группы {name}", + "ADMIN_PROMO_GROUP_PERIOD_DISCOUNTS_HEADER": "⏳ Скидки по периодам:", + "ADMIN_PROMO_GROUP_TOGGLE_ADDON_DISCOUNT_DISABLE": "🧩 Отключить скидки на доп. услуги", + "ADMIN_PROMO_GROUP_TOGGLE_ADDON_DISCOUNT_ENABLE": "🧩 Включить скидки на доп. услуги", + "ADMIN_PROMO_GROUP_UPDATED": "Промогруппа «{name}» обновлена.", + "ADMIN_PROMO_GROUP_PRIORITY_LINE": "🎯 Приоритет: {priority}", + "ADMIN_PROMO_GROUP_CREATE_PRIORITY_PROMPT": "Введите приоритет группы (0 = базовая, чем больше - тем выше приоритет):", + "ADMIN_PROMO_GROUP_EDIT_PRIORITY_PROMPT": "Введите новый приоритет (текущий: {current}):", + "ADMIN_PROMO_GROUP_EDIT_FIELD_PRIORITY": "🎯 Приоритет", + "ADMIN_PROMO_GROUP_INVALID_PRIORITY": "❌ Приоритет должен быть неотрицательным целым числом", + "ADMIN_USER_PROMO_GROUPS_PRIMARY": "⭐ Основная: {name} (Priority: {priority})", + "ADMIN_USER_PROMO_GROUPS_ADDITIONAL": "Дополнительные группы:", + "ADMIN_USER_PROMO_GROUPS_NONE": "У пользователя нет промогрупп", + "ADMIN_USER_PROMO_GROUP_ADDED": "✅ Группа «{name}» добавлена", + "ADMIN_USER_PROMO_GROUP_REMOVED": "🗑 Группа «{name}» удалена", + "ADMIN_USER_PROMO_GROUP_CANNOT_REMOVE_LAST": "❌ Нельзя удалить последнюю промогруппу", + "ADMIN_PROMO_OFFERS_TITLE": "🎯 Промо-предложения\n\nВыберите предложение для настройки:", + "ADMIN_PROMO_OFFER_ACTIVE_DURATION": "Скидка после активации действует {hours} ч.", + "ADMIN_PROMO_OFFER_ALLOWED": "Доступные категории:", + "ADMIN_PROMO_OFFER_BACK_TO_LIST": "⬅️ К промопредложениям", + "ADMIN_PROMO_OFFER_BACK_TO_TEMPLATE": "↩️ К предложению", + "ADMIN_PROMO_OFFER_CTA_BUY": "Купить подписку", + "ADMIN_PROMO_OFFER_CTA_EXTEND": "Продлить подписку", + "ADMIN_PROMO_OFFER_DISCOUNT": "Доп. скидка: {percent}% (суммируется с другими скидками)", + "ADMIN_PROMO_OFFER_EXTEND": "Скидка на продление", + "ADMIN_PROMO_OFFER_LOGS": "📜 Лог операций", + "ADMIN_PROMO_OFFER_LOGS_ACTION_CLAIMED": "Принято", + "ADMIN_PROMO_OFFER_LOGS_ACTION_CONSUMED": "Использовано", + "ADMIN_PROMO_OFFER_LOGS_ACTION_DISABLED": "Отключено", + "ADMIN_PROMO_OFFER_LOGS_AMOUNT": "💰 Сумма: {amount}", + "ADMIN_PROMO_OFFER_LOGS_DESCRIPTION": "📝 {description}", + "ADMIN_PROMO_OFFER_LOGS_EFFECT_DISCOUNT": "💸 Скидка", + "ADMIN_PROMO_OFFER_LOGS_EFFECT_TEST": "🧪 Тестовый доступ", + "ADMIN_PROMO_OFFER_LOGS_EMPTY_BODY": "Записей пока нет.", + "ADMIN_PROMO_OFFER_LOGS_NEW_SQUADS": "🌍 Новые сквады: {squads}", + "ADMIN_PROMO_OFFER_LOGS_PAGINATION": "Страница {page}/{total}", + "ADMIN_PROMO_OFFER_LOGS_PERCENT": "📉 Скидка: {percent}%", + "ADMIN_PROMO_OFFER_LOGS_REASON_AUTOPAY": "🤖 Применено при автопродлении", + "ADMIN_PROMO_OFFER_LOGS_REASON_EXPIRED": "⏳ Предложение истекло", + "ADMIN_PROMO_OFFER_LOGS_REASON_GENERIC": "ℹ️ Действие: {reason}", + "ADMIN_PROMO_OFFER_LOGS_REASON_MANUAL": "💳 Списано при ручной оплате", + "ADMIN_PROMO_OFFER_LOGS_REASON_TEST_EXPIRED": "⏳ Тестовый доступ отключён", + "ADMIN_PROMO_OFFER_LOGS_SOURCE": "🏷 Источник: {source}", + "ADMIN_PROMO_OFFER_LOGS_SQUAD": "🌍 Сквад: {squad}", + "ADMIN_PROMO_OFFER_LOGS_TITLE": "📜 Лог операций промо-предложений", + "ADMIN_PROMO_OFFER_LOGS_UNKNOWN_USER": "Неизвестный пользователь", + "ADMIN_PROMO_OFFER_LOGS_USER": "👤 {user}", + "ADMIN_PROMO_OFFER_NO_SQUADS_AVAILABLE": "❌ Доступные серверы не найдены.", + "ADMIN_PROMO_OFFER_NO_USERS": "Подходящих пользователей не найдено.", + "ADMIN_PROMO_OFFER_PREVIEW": "Предпросмотр:", + "ADMIN_PROMO_OFFER_PROMPT_ACTIVE_DURATION": "Укажите срок действия активированной скидки (в часах):", + "ADMIN_PROMO_OFFER_PROMPT_BUTTON": "Введите новый текст кнопки:", + "ADMIN_PROMO_OFFER_PROMPT_DISCOUNT": "Введите размер скидки в процентах:", + "ADMIN_PROMO_OFFER_PROMPT_DURATION": "Введите длительность тестового доступа (в часах):", + "ADMIN_PROMO_OFFER_PROMPT_MESSAGE": "Введите новый текст предложения:", + "ADMIN_PROMO_OFFER_PROMPT_VALID": "Укажите срок действия (в часах):", + "ADMIN_PROMO_OFFER_PURCHASE": "Скидка на покупку", + "ADMIN_PROMO_OFFER_RESULT": "📬 Рассылка завершена\nОтправлено: {sent}\nОшибок: {failed}", + "ADMIN_PROMO_OFFER_SELECTED_SQUAD": "Текущий сквад: {name}", + "ADMIN_PROMO_OFFER_SELECTED_SQUAD_EMPTY": "Текущий сквад: не выбран", + "ADMIN_PROMO_OFFER_SELECTED_SQUAD_UUID": "Текущий сквад: {uuid}", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_BACK": "↩️ Назад", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_CLEAR": "🗑 Очистить", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_CLEARED": "✅ Сквад очищен", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_HINT": "Выберите сервер для тестового доступа из списка ниже.", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_NOT_FOUND": "❌ Сервер не найден", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_PAGE": "Страница {page}/{total}", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_TITLE": "🌍 Выберите сквад", + "ADMIN_PROMO_OFFER_SELECT_SQUAD_UPDATED": "✅ Сквад обновлён", + "ADMIN_PROMO_OFFER_SENDING": "Начинаем рассылку...", + "ADMIN_PROMO_OFFER_SEND_USER": "👤 Отправка пользователю", + "ADMIN_PROMO_OFFER_SEND_USER_ACTIVE_DISCOUNT": "💸 Активная скидка: {percent}%", + "ADMIN_PROMO_OFFER_SEND_USER_ACTIVE_DISCOUNT_LEFT": " (до {date}, осталось {time})", + "ADMIN_PROMO_OFFER_SEND_USER_ACTIVE_DISCOUNT_NONE": "💸 Активная скидка отсутствует", + "ADMIN_PROMO_OFFER_SEND_USER_ACTIVE_DISCOUNT_SOURCE": " — источник: {source}", + "ADMIN_PROMO_OFFER_SEND_USER_ACTIVE_DISCOUNT_UNTIL": " (до {date})", + "ADMIN_PROMO_OFFER_SEND_USER_ACTIVE_OFFERS": "📨 Активные предложения:", + "ADMIN_PROMO_OFFER_SEND_USER_BACK_TO_LIST": "⬅️ К списку пользователей", + "ADMIN_PROMO_OFFER_SEND_USER_BACK_TO_PROFILE": "👤 К профилю пользователя", + "ADMIN_PROMO_OFFER_SEND_USER_BACK_TO_SEGMENTS": "↩️ К выбору категории", + "ADMIN_PROMO_OFFER_SEND_USER_BALANCE": "Баланс: {amount}", + "ADMIN_PROMO_OFFER_SEND_USER_EMPTY": "Подходящие пользователи не найдены. Измените запрос поиска.", + "ADMIN_PROMO_OFFER_SEND_USER_EMPTY_RESULT": "Отправка не выполнена", + "ADMIN_PROMO_OFFER_SEND_USER_HINT": "Выберите пользователя для отправки промопредложения.", + "ADMIN_PROMO_OFFER_SEND_USER_NO_ACTIVE_OFFERS": "📨 Активных предложений нет", + "ADMIN_PROMO_OFFER_SEND_USER_NO_SUBSCRIPTION": "💳 Подписка отсутствует", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_ACTIVE_DURATION": " После активации: {duration}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_BONUS": "+{bonus}%", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_EXPIRES": " Истекает: {expires}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_ITEM": "• {description} (до {expires})", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_ITEM_HEADER": "• {description}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_NO_EXPIRY": "без срока", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_PERCENT": "{percent}%", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATS_ACCEPTED": "Принято: {count}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATS_ACTIVE": "Активно сейчас: {count}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATS_HEADER": "📊 Статистика предложений", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATS_PENDING": "Не принято: {count}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATS_TOTAL": "Всего отправлено: {count}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATUS": " Статус: {status}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATUS_ACCEPTED": "✅ Принято", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_STATUS_PENDING": "⏳ Не принято", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_TEST": "Тестовый доступ", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_TIME_LEFT": " Осталось: {time}", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_TIME_LEFT_EXPIRED": "истекло", + "ADMIN_PROMO_OFFER_SEND_USER_OFFER_TOTAL_DURATION": " Всего действует: {duration}", + "ADMIN_PROMO_OFFER_SEND_USER_PROFILE": "👤 {name}", + "ADMIN_PROMO_OFFER_SEND_USER_RESET": "❌ Сбросить поиск", + "ADMIN_PROMO_OFFER_SEND_USER_SEARCH": "🔍 Поиск", + "ADMIN_PROMO_OFFER_SEND_USER_SEARCH_PROMPT": "Введите имя, username или ID пользователя для поиска:", + "ADMIN_PROMO_OFFER_SEND_USER_SEARCH_QUERY": "🔍 Поиск: {query}", + "ADMIN_PROMO_OFFER_SEND_USER_SEND_BUTTON": "📬 Отправить предложение", + "ADMIN_PROMO_OFFER_SEND_USER_SKIPPED": "Пропущено: {skipped} (уже есть доступ)", + "ADMIN_PROMO_OFFER_SEND_USER_STATUS": "Статус: {status}", + "ADMIN_PROMO_OFFER_SEND_USER_SUBSCRIPTION": "💳 Подписка", + "ADMIN_PROMO_OFFER_SEND_USER_SUBSCRIPTION_END": "Истекает: {date}", + "ADMIN_PROMO_OFFER_SEND_USER_SUBSCRIPTION_END_UNKNOWN": "не указано", + "ADMIN_PROMO_OFFER_SEND_USER_SUBSCRIPTION_SQUADS": "Подключено сквадов: {count}", + "ADMIN_PROMO_OFFER_SEND_USER_SUBSCRIPTION_STATUS": "Статус: {status}", + "ADMIN_PROMO_OFFER_SEND_USER_SUBSCRIPTION_TRAFFIC": "Трафик: {used}/{limit} ГБ", + "ADMIN_PROMO_OFFER_SEND_USER_SUMMARY_TITLE": "📬 Отправка пользователю {name}", + "ADMIN_PROMO_OFFER_SEND_USER_TELEGRAM": "🆔 {telegram_id}", + "ADMIN_PROMO_OFFER_SEND_USER_TEMPLATE_ACTIVE_DURATION": "После активации действует {hours} ч.", + "ADMIN_PROMO_OFFER_SEND_USER_TEMPLATE_DISCOUNT": "Скидка: {percent}%", + "ADMIN_PROMO_OFFER_SEND_USER_TEMPLATE_HEADER": "📨 Выбранное предложение", + "ADMIN_PROMO_OFFER_SEND_USER_TEMPLATE_TEST_DURATION": "Тестовый доступ: {hours} ч.", + "ADMIN_PROMO_OFFER_SEND_USER_TEMPLATE_TYPE": "Тип: {label}", + "ADMIN_PROMO_OFFER_SEND_USER_TEMPLATE_VALID": "Действует: {hours} ч.", + "ADMIN_PROMO_OFFER_SEND_USER_TEST_ACCESS": "🧪 Активные тестовые доступы:", + "ADMIN_PROMO_OFFER_SEND_USER_TEST_ACCESS_ITEM": "• {squad} (до {expires})", + "ADMIN_PROMO_OFFER_SEND_USER_TITLE": "👤 Отправка пользователю", + "ADMIN_PROMO_OFFER_SEND_USER_USERNAME": "🔗 @{username}", + "ADMIN_PROMO_OFFER_SKIPPED": "Пропущено: {skipped} (уже есть доступ)", + "ADMIN_PROMO_OFFER_STACKABLE_NOTE": "Скидка применяется один раз и добавляется к промогруппе.", + "ADMIN_PROMO_OFFER_TEST_ACCESS": "Тестовые сервера", + "ADMIN_PROMO_OFFER_TEST_DURATION": "Доступ: {hours} ч", + "ADMIN_PROMO_OFFER_TEST_SQUADS": "Сквады: {squads}", + "ADMIN_PROMO_OFFER_TEST_SQUADS_EMPTY": "Сквады: не указаны", + "ADMIN_PROMO_OFFER_TEST_SQUAD_NAME": "Сервер: {name}", + "ADMIN_PROMO_OFFER_TYPE": "Тип: {label}", + "ADMIN_PROMO_OFFER_VALID": "Срок действия: {hours} ч", + "ADMIN_PROMO_SUBMENU_TITLE": "💰 **Промокоды и статистика**\n\n", + "ADMIN_PUBLIC_OFFER_ACTION_PROMPT": "Выберите действие:", + "ADMIN_PUBLIC_OFFER_BACK_BUTTON": "⬅️ К настройкам оферты", + "ADMIN_PUBLIC_OFFER_CANCEL": "❌ Отмена", + "ADMIN_PUBLIC_OFFER_CURRENT_PREVIEW": "Текущий текст (превью):", + "ADMIN_PUBLIC_OFFER_DESCRIPTION": "Публичная оферта отображается в разделе «Инфо».", + "ADMIN_PUBLIC_OFFER_DISABLED": "🚫 Оферта отключена", + "ADMIN_PUBLIC_OFFER_DISABLE_BUTTON": "🚫 Отключить показ", + "ADMIN_PUBLIC_OFFER_EDIT_BUTTON": "✏️ Изменить текст", + "ADMIN_PUBLIC_OFFER_EDIT_CANCELLED": "Редактирование оферты отменено.", + "ADMIN_PUBLIC_OFFER_EDIT_HINT": "Используйте /html_help для справки по тегам.", + "ADMIN_PUBLIC_OFFER_EDIT_PROMPT": "Отправьте новый текст публичной оферты. Допускается HTML-разметка.", + "ADMIN_PUBLIC_OFFER_EDIT_TITLE": "Редактирование оферты", + "ADMIN_PUBLIC_OFFER_ENABLED": "✅ Оферта включена", + "ADMIN_PUBLIC_OFFER_ENABLE_BUTTON": "✅ Включить показ", + "ADMIN_PUBLIC_OFFER_HEADER": "📄 Публичная оферта", + "ADMIN_PUBLIC_OFFER_HTML_ERROR": "❌ Ошибка в HTML: {error}", + "ADMIN_PUBLIC_OFFER_HTML_HELP": "ℹ️ HTML помощь", + "ADMIN_PUBLIC_OFFER_LANGUAGE": "Язык: {lang}", + "ADMIN_PUBLIC_OFFER_PREVIEW_EMPTY": "Текст ещё не задан.", + "ADMIN_PUBLIC_OFFER_PREVIEW_EMPTY_ALERT": "Текст оферты пока не задан.", + "ADMIN_PUBLIC_OFFER_PREVIEW_TITLE": "Превью текста:", + "ADMIN_PUBLIC_OFFER_RETURN_TO_EDIT": "⬅️ Назад к редактированию", + "ADMIN_PUBLIC_OFFER_SAVED": "✅ Публичная оферта обновлена.", + "ADMIN_PUBLIC_OFFER_STATUS_DISABLED": "⚠️ Показ оферты выключен или текст отсутствует.", + "ADMIN_PUBLIC_OFFER_STATUS_ENABLED": "✅ Оферта активна и показывается пользователям.", + "ADMIN_PUBLIC_OFFER_STATUS_ENABLED_EMPTY": "⚠️ Оферта включена, но текст пуст — пользователи её не увидят.", + "ADMIN_PUBLIC_OFFER_TOO_LONG": "❌ Текст оферты слишком длинный. Максимум 4000 символов.", + "ADMIN_PUBLIC_OFFER_UPDATED_AT": "Последнее обновление: {timestamp}", + "ADMIN_PUBLIC_OFFER_VIEW_BUTTON": "👀 Просмотреть текущий текст", + "ADMIN_PUBLIC_OFFER_VIEW_TITLE": "👀 Текущий текст оферты", + "ADMIN_PUBLIC_OFFER_VIEW_TRUNCATED": "\n\n⚠️ Текст сокращён для отображения. Полную версию увидят пользователи в меню.", + "ADMIN_REFERRALS": "🤝 Партнерка", + "ADMIN_REFRESH": "🔄 Обновить", + "ADMIN_REMNAWAVE": "🖥️ Remnawave", + "ADMIN_REMNAWAVE_MANAGE_NODES": "🖥️ Управление нодами", + "ADMIN_REMNAWAVE_MANAGE_SQUADS": "🌐 Управление сквадами", + "ADMIN_REMNAWAVE_MIGRATION": "🚚 Переезд", + "ADMIN_REMNAWAVE_SYNC": "🔄 Синхронизация", + "ADMIN_REMNAWAVE_SYSTEM_STATS": "📊 Системная статистика", + "ADMIN_REMNAWAVE_TRAFFIC": "📈 Трафик", + "ADMIN_REPORTS": "📊 Отчеты", + "ADMIN_REPORTS_LAST_MONTH": "📅 За месяц", + "ADMIN_REPORTS_LAST_WEEK": "🗓️ За неделю", + "ADMIN_REPORTS_PREVIOUS_DAY": "📆 За вчера", + "ADMIN_RULES": "📋 Правила", + "ADMIN_SERVERS_ADD": "➕ Добавить сервер", + "ADMIN_SERVERS_LIST": "📋 Список серверов", + "ADMIN_SERVERS_STATS": "📊 Статистика", + "ADMIN_SERVERS_SYNC": "🔄 Синхронизация", + "ADMIN_SERVER_DELETE": "🗑️ Удалить", + "ADMIN_SERVER_DISABLE": "❌ Отключить", + "ADMIN_SERVER_EDIT_COUNTRY": "🌍 Страна", + "ADMIN_SERVER_EDIT_DESCRIPTION": "📝 Описание", + "ADMIN_SERVER_EDIT_LIMIT": "👥 Лимит", + "ADMIN_SERVER_EDIT_NAME": "✏️ Название", + "ADMIN_SERVER_EDIT_PRICE": "💰 Цена", + "ADMIN_SERVER_ENABLE": "✅ Включить", + "ADMIN_SETTINGS_BOT_CONFIG": "🧩 Конфигурация бота", + "ADMIN_SETTINGS_FAQ": "❓ FAQ", + "ADMIN_SETTINGS_MAINTENANCE": "🔧 Техработы", + "ADMIN_SETTINGS_PRIVACY_POLICY": "🛡️ Политика конф.", + "ADMIN_SETTINGS_PUBLIC_OFFER": "📄 Публичная оферта", + "ADMIN_SETTINGS_SUBMENU_DESCRIPTION": "Управление Remnawave, мониторингом и другими настройками:", + "ADMIN_SETTINGS_SUBMENU_TITLE": "⚙️ **Настройки системы**\n\n", + "ADMIN_SETTINGS_TARIFFS": "📦 Тарифы", + "ADMIN_SQUAD_ADD_ALL": "👥 Добавить всех пользователей", + "ADMIN_SQUAD_DELETE": "🗑️ Удалить сквад", + "ADMIN_SQUAD_EDIT": "✏️ Редактировать", + "ADMIN_SQUAD_EDIT_INBOUNDS": "🔧 Изменить инбаунды", + "ADMIN_SQUAD_MIGRATION_API_ERROR": "❌ Remnawave API не настроен: {error}", + "ADMIN_SQUAD_MIGRATION_BACK_BUTTON": "⬅️ В Remnawave", + "ADMIN_SQUAD_MIGRATION_CANCELLED": "❌ Переезд отменен.", + "ADMIN_SQUAD_MIGRATION_CHANGE_TARGET": "🔄 Изменить сервер назначения", + "ADMIN_SQUAD_MIGRATION_CONFIRM_BUTTON": "✅ Подтвердить", + "ADMIN_SQUAD_MIGRATION_CONFIRM_COUNT": "• Пользователей к переносу: {count}", + "ADMIN_SQUAD_MIGRATION_CONFIRM_DETAILS": "Проверьте параметры переезда:", + "ADMIN_SQUAD_MIGRATION_CONFIRM_PROMPT": "Подтвердите выполнение операции.", + "ADMIN_SQUAD_MIGRATION_CONFIRM_SOURCE": "• Из: {source}", + "ADMIN_SQUAD_MIGRATION_CONFIRM_TARGET": "• В: {target}", + "ADMIN_SQUAD_MIGRATION_ERROR": "❌ Не удалось выполнить переезд (код: {code}). {details}", + "ADMIN_SQUAD_MIGRATION_IN_PROGRESS": "Запускаю переезд...", + "ADMIN_SQUAD_MIGRATION_NEW_BUTTON": "🔁 Новый переезд", + "ADMIN_SQUAD_MIGRATION_NO_OPTIONS": "Нет доступных сквадов. Добавьте новые или отмените операцию.", + "ADMIN_SQUAD_MIGRATION_PAGE": "Стр. {page}/{pages}", + "ADMIN_SQUAD_MIGRATION_PAGE_HINT": "Это текущая страница.", + "ADMIN_SQUAD_MIGRATION_RESULT_PANEL_FAILED": "Не удалось обновить в панели: {count}", + "ADMIN_SQUAD_MIGRATION_RESULT_PANEL_UPDATED": "Обновлено в панели: {count}", + "ADMIN_SQUAD_MIGRATION_RESULT_TOTAL": "Найдено подписок: {count}", + "ADMIN_SQUAD_MIGRATION_RESULT_UPDATED": "Перенесено: {count}", + "ADMIN_SQUAD_MIGRATION_SAME_SQUAD": "Нельзя выбрать тот же сквад.", + "ADMIN_SQUAD_MIGRATION_SELECTED_SOURCE": "Источник: {source}", + "ADMIN_SQUAD_MIGRATION_SELECT_SOURCE": "Выберите сквад, из которого нужно переехать:", + "ADMIN_SQUAD_MIGRATION_SELECT_TARGET": "Выберите сквад, в который нужно переехать:", + "ADMIN_SQUAD_MIGRATION_SERVER_LABEL": "{name} — 👥 {users} ({status})", + "ADMIN_SQUAD_MIGRATION_SQUAD_BUTTON": "🌍 {name} — 👥 {users} ({status})", + "ADMIN_SQUAD_MIGRATION_SQUAD_NOT_FOUND": "Сквад не найден или недоступен.", + "ADMIN_SQUAD_MIGRATION_STATUS_AVAILABLE": "✅ Доступен", + "ADMIN_SQUAD_MIGRATION_STATUS_AVAILABLE_SHORT": "✅", + "ADMIN_SQUAD_MIGRATION_STATUS_UNAVAILABLE": "🚫 Недоступен", + "ADMIN_SQUAD_MIGRATION_STATUS_UNAVAILABLE_SHORT": "🚫", + "ADMIN_SQUAD_MIGRATION_SUCCESS_TITLE": "✅ Переезд завершен", + "ADMIN_SQUAD_MIGRATION_TARGET_EMPTY": "Нет других сквадов для переезда. Отмените операцию или создайте новые сквады.", + "ADMIN_SQUAD_MIGRATION_TITLE": "🚚 Переезд сквадов", + "ADMIN_SQUAD_REMOVE_ALL": "❌ Удалить всех пользователей", + "ADMIN_SQUAD_RENAME": "✏️ Переименовать", + "ADMIN_STATISTICS": "📊 Статистика", + "ADMIN_STATS_BUTTON": "📊 Статистика", + "ADMIN_STATS_REFERRALS": "🤝 Партнерка", + "ADMIN_STATS_REVENUE": "💰 Доходы", + "ADMIN_STATS_SUBSCRIPTIONS": "📱 Подписки", + "ADMIN_STATS_SUMMARY": "📊 Общая сводка", + "ADMIN_STATS_USERS": "👥 Пользователи", + "ADMIN_SUBMENU_SELECT_SECTION": "Выберите нужный раздел:", + "ADMIN_SUBSCRIPTIONS": "📱 Подписки", + "ADMIN_SUBSCRIPTIONS_ALL": "📱 Все подписки", + "ADMIN_SUBSCRIPTIONS_COUNTRIES": "🌍 Управление странами", + "ADMIN_SUBSCRIPTIONS_EXPIRING": "⏰ Истекающие", + "ADMIN_SUBSCRIPTIONS_PRICING": "⚙️ Настройки цен", + "ADMIN_SUPPORT_ASSIGN_MODERATOR_PROMPT": "🧑‍⚖️ Назначение модератора\n\nОтправьте Telegram ID пользователя (число)", + "ADMIN_SUPPORT_AUDIT": "🧾 Аудит модераторов", + "ADMIN_CLOSE_ALL_OPEN_TICKETS": "🔒 Закрыть все открытые", + "ADMIN_CLOSE_ALL_OPEN_TICKETS_EMPTY": "ℹ️ Нет открытых тикетов для закрытия.", + "ADMIN_CLOSE_ALL_OPEN_TICKETS_SUCCESS": "✅ Закрыто открытых тикетов: {count}", + "ADMIN_SUPPORT_AUDIT_ACTION_BLOCK_PERM": "Блокировка (навсегда)", + "ADMIN_SUPPORT_AUDIT_ACTION_BLOCK_TIMED": "Блокировка (время)", + "ADMIN_SUPPORT_AUDIT_ACTION_CLOSE_ALL_TICKETS": "Массовое закрытие тикетов", + "ADMIN_SUPPORT_AUDIT_ACTION_CLOSE_TICKET": "Закрытие тикета", + "ADMIN_SUPPORT_AUDIT_ACTION_UNBLOCK": "Снятие блока", + "ADMIN_SUPPORT_AUDIT_EMPTY": "Пока пусто", + "ADMIN_SUPPORT_AUDIT_ROLE_ADMIN": "Админ", + "ADMIN_SUPPORT_AUDIT_ROLE_MODERATOR": "Модератор", + "ADMIN_SUPPORT_AUDIT_TITLE": "🧾 Аудит модераторов", + "ADMIN_SUPPORT_DESCRIPTION_SENT": "Текст отправлен ниже", + "ADMIN_SUPPORT_DESCRIPTION_UPDATED": "✅ Описание обновлено.", + "ADMIN_SUPPORT_EDIT_DESCRIPTION_CONTACT_HINT": "Добавьте в описание при необходимости.", + "ADMIN_SUPPORT_EDIT_DESCRIPTION_CONTACT_TITLE": "Контакт для режима «Контакт»", + "ADMIN_SUPPORT_EDIT_DESCRIPTION_CURRENT": "Текущее описание:", + "ADMIN_SUPPORT_EDIT_DESCRIPTION_TITLE": "📝 Редактирование описания поддержки", + "ADMIN_SUPPORT_INVALID_TELEGRAM_ID": "❌ Введите корректный Telegram ID (число)", + "ADMIN_SUPPORT_MESSAGE_DELETED": "Сообщение удалено", + "ADMIN_SUPPORT_MODERATION_DESCRIPTION": "Доступ к тикетам поддержки.", + "ADMIN_SUPPORT_MODERATION_TITLE": "🧑‍⚖️ Модерация поддержки", + "ADMIN_SUPPORT_MODERATORS_EMPTY": "Список пуст", + "ADMIN_SUPPORT_MODERATORS_TITLE": "🧑‍⚖️ Модераторы", + "ADMIN_SUPPORT_MODERATOR_ADDED_FAIL": "❌ Не удалось назначить модератора", + "ADMIN_SUPPORT_MODERATOR_ADDED_SUCCESS": "✅ Пользователь {tid} назначен модератором", + "ADMIN_SUPPORT_MODERATOR_REMOVED_FAIL": "❌ Не удалось удалить модератора", + "ADMIN_SUPPORT_MODERATOR_REMOVED_SUCCESS": "✅ Модератор {tid} удалён", + "ADMIN_SUPPORT_REMOVE_MODERATOR_PROMPT": "🧑‍⚖️ Удаление модератора\n\nОтправьте Telegram ID пользователя (число)", + "ADMIN_SUPPORT_SEND_DESCRIPTION": "📨 Прислать текст", + "ADMIN_SUPPORT_SETTINGS": "🛟 Настройки поддержки", + "ADMIN_SUPPORT_SETTINGS_ADD_MODERATOR": "➕ Назначить модератора", + "ADMIN_SUPPORT_SETTINGS_ADMIN_NOTIFICATIONS": "Админ-уведомления", + "ADMIN_SUPPORT_SETTINGS_DESCRIPTION": "Режим работы и видимость в меню. Ниже текущее описание меню поддержки:", + "ADMIN_SUPPORT_SETTINGS_EDIT_DESCRIPTION": "📝 Изменить описание", + "ADMIN_SUPPORT_SETTINGS_MENU_LABEL": "Пункт «Техподдержка» в меню", + "ADMIN_SUPPORT_SETTINGS_MODERATORS_COUNT": "🧑‍⚖️ Модераторы: {count}", + "ADMIN_SUPPORT_SETTINGS_MODE_BOTH": "Оба", + "ADMIN_SUPPORT_SETTINGS_MODE_CONTACT": "Контакт", + "ADMIN_SUPPORT_SETTINGS_MODE_TICKETS": "Тикеты", + "ADMIN_SUPPORT_SETTINGS_REMOVE_MODERATOR": "➖ Удалить модератора", + "ADMIN_SUPPORT_SETTINGS_SLA_LABEL": "SLA", + "ADMIN_SUPPORT_SETTINGS_SLA_TIME": "⏳ Время SLA: {minutes} мин", + "ADMIN_SUPPORT_SETTINGS_STATUS_DISABLED": "Отключены", + "ADMIN_SUPPORT_SETTINGS_STATUS_ENABLED": "Включены", + "ADMIN_SUPPORT_SETTINGS_TITLE": "🛟 Настройки поддержки", + "ADMIN_SUPPORT_SETTINGS_USER_NOTIFICATIONS": "Пользовательские уведомления", + "ADMIN_SUPPORT_SLA_INVALID": "❌ Введите корректное число минут (1-1440)", + "ADMIN_SUPPORT_SLA_SAVED": "✅ Значение SLA сохранено", + "ADMIN_SUPPORT_SLA_SETUP_PROMPT": "⏳ Настройка SLA\n\nВведите количество минут ожидания ответа (целое число > 0):", + "ADMIN_SUPPORT_SUBMENU_DESCRIPTION": "Управление тикетами и настройками поддержки:", + "ADMIN_SUPPORT_SUBMENU_DESCRIPTION_MODERATOR": "Доступ к тикетам.", + "ADMIN_SUPPORT_SUBMENU_TITLE": "🛟 **Поддержка**\n\n", + "ADMIN_SUPPORT_TICKETS": "🎫 Тикеты поддержки", + "ADMIN_SYNC_BACK": "⬅️ К синхронизации", + "ADMIN_SYNC_TO_PANEL": "⬆️ Синхронизация в панель", + "ADMIN_SYNC_CLEANUP": "🧹 Очистка", + "ADMIN_SYNC_CONFIRM": "✅ Подтвердить", + "ADMIN_SYNC_FULL": "🔄 Полная синхронизация", + "ADMIN_SYNC_ONLY_NEW": "🆕 Только новые", + "ADMIN_SYNC_RECOMMENDATIONS": "💡 Рекомендации", + "ADMIN_SYNC_RETRY": "🔄 Повторить", + "ADMIN_SYNC_UPDATE": "📈 Обновить данные", + "ADMIN_SYNC_VALIDATE": "🔍 Валидация", + "ADMIN_SYSTEM_BACKUPS": "🗄️ Резервные копии", + "ADMIN_SYSTEM_LOGS": "🧾 Логи", + "ADMIN_SYSTEM_SUBMENU_DESCRIPTION": "Отчеты, обновления, логи, резервные копии и системные операции:", + "ADMIN_SYSTEM_SUBMENU_TITLE": "🛠️ **Системные функции**\n\n", + "ADMIN_SYSTEM_UPDATES": "📄 Обновления", + "ADMIN_TICKETS_TITLE": "🎫 Все тикеты поддержки:", + "ADMIN_TICKETS_TITLE_CLOSED": "🎫 Закрытые тикеты поддержки:", + "ADMIN_TICKETS_TITLE_OPEN": "🎫 Открытые тикеты поддержки:", + "ADMIN_TICKET_REPLY_INPUT": "Введите ответ от поддержки:", + "ADMIN_TICKET_REPLY_SENT": "✅ Ответ отправлен!", + "ADMIN_USERS": "👥 Пользователи", + "ADMIN_USERS_ALL": "👥 Все пользователи", + "ADMIN_USERS_FILTERS": "⚙️ Фильтры", + "ADMIN_USERS_FILTER_ACTIVITY": "🕒 По активности", + "ADMIN_USERS_FILTER_BALANCE": "💰 По балансу", + "ADMIN_USERS_FILTER_RENEW_READY": "♻️ Готовы к продлению", + "ADMIN_USERS_FILTER_RENEW_READY_TITLE": "♻️ Пользователи готовы к продлению", + "ADMIN_USERS_FILTER_RENEW_READY_DESC": "Подписка истекла, а на балансе осталось {amount} или больше.", + "ADMIN_USERS_FILTER_RENEW_READY_EMPTY": "Сейчас нет пользователей, которые подходят под этот фильтр.", + "ADMIN_USERS_FILTER_POTENTIAL_CUSTOMERS": "💰 Потенциальные клиенты", + "ADMIN_USERS_FILTER_POTENTIAL_CUSTOMERS_TITLE": "💰 Потенциальные клиенты", + "ADMIN_USERS_FILTER_POTENTIAL_CUSTOMERS_DESC": "Нет подписки, но баланс достаточен для покупки.", + "ADMIN_USERS_FILTER_POTENTIAL_CUSTOMERS_EMPTY": "Нет пользователей без подписки с достаточным балансом.", + "ADMIN_USERS_FILTER_CAMPAIGN": "📢 По кампании", + "ADMIN_USERS_FILTER_PURCHASES": "🛒 По количеству покупок", + "ADMIN_USERS_FILTER_SPENDING": "💳 По сумме трат", + "ADMIN_USERS_FILTER_TRAFFIC": "📶 По трафику", + "ADMIN_USERS_INACTIVE": "🗑️ Неактивные", + "ADMIN_USERS_SEARCH": "🔍 Поиск", + "ADMIN_USERS_SUBMENU_TITLE": "👥 **Управление пользователями и подписками**\n\n", + "ADMIN_USER_ALREADY_DELETED": "❌ Пользователь удален", + "ADMIN_USER_BALANCE": "💰 Баланс", + "ADMIN_USER_BLOCK": "🚫 Заблокировать", + "ADMIN_USER_DELETE": "🗑️ Удалить", + "ADMIN_USER_LAST_ACTIVITY_UNKNOWN": "Неизвестно", + "ADMIN_USER_MANAGEMENT_PROFILE": "👤 Управление пользователем\n\nОсновная информация:\n• Имя: {name}\n• ID: {telegram_id}\n• Username: {username}\n• Статус: {status}\n• Язык: {language}\n\nФинансы:\n• Баланс: {balance}\n• Транзакций: {transactions}\n\nАктивность:\n• Регистрация: {registration}\n• Последняя активность: {last_activity}\n• Дней с регистрации: {registration_days}", + "ADMIN_USER_MANAGEMENT_PROMO_GROUP": "Промогруппа:\n• Название: {name}\n• Скидка на сервера: {server_discount}%\n• Скидка на трафик: {traffic_discount}%\n• Скидка на устройства: {device_discount}%", + "ADMIN_USER_MANAGEMENT_PROMO_GROUP_NONE": "Промогруппа: Не назначена", + "ADMIN_USER_MANAGEMENT_SUBSCRIPTION": "Подписка:\n• Тип: {type}\n• Статус: {status}\n• До: {end_date}\n• Трафик: {traffic}\n• Устройства: {devices}\n• Стран: {countries}", + "ADMIN_USER_MANAGEMENT_SUBSCRIPTION_NONE": "Подписка: Отсутствует", + "ADMIN_USER_PROMO_GROUP_ALREADY": "ℹ️ Пользователь уже состоит в этой промогруппе.", + "ADMIN_USER_PROMO_GROUP_BACK": "⬅️ К пользователю", + "ADMIN_USER_PROMO_GROUP_BUTTON": "👥 Промогруппа", + "ADMIN_USER_REFERRALS_BUTTON": "🤝 Рефералы", + "ADMIN_USER_REFERRALS_TITLE": "🤝 Рефералы пользователя", + "ADMIN_USER_REFERRALS_SUMMARY": "👤 {name} (ID: {telegram_id})\n👥 Всего рефералов: {count}", + "ADMIN_USER_REFERRAL_COMMISSION_DEFAULT": "• Процент комиссии: {percent}% (стандартное значение)", + "ADMIN_USER_REFERRAL_COMMISSION_CUSTOM": "• Индивидуальный процент: {percent}% (стандарт: {default_percent}%)", + "ADMIN_USER_REFERRAL_COMMISSION_EDIT_BUTTON": "📈 Изменить процент", + "ADMIN_USER_REFERRAL_COMMISSION_PROMPT": "📈 Индивидуальный процент реферальной комиссии\n\nТекущее значение: {current}%\nСтандартное значение: {default}%\n\nОтправьте новое значение от 0 до 100 или слово 'стандарт' для сброса.", + "ADMIN_USER_REFERRAL_COMMISSION_RESET_BUTTON": "♻️ Сбросить на стандартный", + "ADMIN_USER_REFERRAL_COMMISSION_UPDATED": "✅ Процент обновлён: {percent}%", + "ADMIN_USER_REFERRAL_COMMISSION_INVALID": "❌ Введите число от 0 до 100 или слово 'стандарт'", + "ADMIN_USER_REFERRALS_LIST_HEADER": "Список рефералов:", + "ADMIN_USER_REFERRALS_LIST_ITEM": "• {name} (ID: {telegram_id}{username_part})", + "ADMIN_USER_REFERRALS_LIST_TRUNCATED": "• … и ещё {count} рефералов", + "ADMIN_USER_REFERRALS_EMPTY": "Рефералов пока нет.", + "ADMIN_USER_REFERRALS_EDIT_HINT": "✏️ Чтобы изменить список, нажмите «✏️ Редактировать» ниже.", + "ADMIN_USER_REFERRALS_EDIT_BUTTON": "✏️ Редактировать", + "ADMIN_USER_REFERRALS_EDIT_PROMPT": "✏️ Редактирование рефералов\n\nОтправьте список рефералов для пользователя {name} (ID: {telegram_id}):\n• Используйте TG ID или @username\n• Значения можно указывать через запятую, пробел или с новой строки\n• Чтобы очистить список, отправьте 0 или слово 'нет'\n\nИли нажмите кнопку ниже, чтобы отменить.", + "ADMIN_USER_REFERRALS_STATE_LOST": "❌ Не удалось определить пользователя. Попробуйте начать сначала.", + "ADMIN_USER_REFERRALS_NO_VALID": "❌ Не удалось найти ни одного пользователя по введённым данным.", + "ADMIN_USER_REFERRALS_INVALID_ENTRIES": "Не найдены: {values}", + "ADMIN_USER_REFERRALS_SELF_SKIPPED": "Пропущены значения пользователя: {values}", + "ADMIN_USER_REFERRALS_DUPLICATES": "Игнорированы дубли: {values}", + "ADMIN_USER_REFERRALS_UPDATE_ERROR": "❌ Не удалось обновить рефералов. Попробуйте позже.", + "ADMIN_USER_REFERRALS_UPDATED": "✅ Список рефералов обновлён.", + "ADMIN_USER_REFERRALS_UPDATED_TOTAL": "• Текущий список: {total}", + "ADMIN_USER_REFERRALS_UPDATED_ADDED": "• Добавлено: {count}", + "ADMIN_USER_REFERRALS_UPDATED_REMOVED": "• Удалено: {count}", + "ADMIN_USER_PROMO_GROUP_CURRENT": "Текущая группа: {name}", + "ADMIN_USER_PROMO_GROUP_CURRENT_NONE": "Текущая группа: не назначена", + "ADMIN_USER_PROMO_GROUP_DISCOUNTS": "Скидки — серверы: {servers}%, трафик: {traffic}%, устройства: {devices}%", + "ADMIN_USER_PROMO_GROUP_DISCOUNTS_NONE": "Скидки не заданы.", + "ADMIN_USER_PROMO_GROUP_ERROR": "❌ Не удалось обновить промогруппу пользователя.", + "ADMIN_USER_PROMO_GROUP_SELECT": "Выберите промогруппу для назначения:", + "ADMIN_USER_PROMO_GROUP_TITLE": "👥 Промогруппа пользователя", + "ADMIN_USER_PROMO_GROUP_UPDATED": "✅ Промогруппа пользователя обновлена: «{name}»", + "ADMIN_USER_STATISTICS": "📊 Статистика", + "ADMIN_USER_STATUS_ACTIVE": "✅ Активен", + "ADMIN_USER_STATUS_BLOCKED": "🚫 Заблокирован", + "ADMIN_USER_STATUS_DELETED": "🗑️ Удален", + "ADMIN_USER_STATUS_UNKNOWN": "❓ Неизвестно", + "ADMIN_USER_SUBSCRIPTION_SETTINGS": "📱 Подписка и настройки", + "ADMIN_USER_SUBSCRIPTION_STATUS_ACTIVE": "✅ Активна", + "ADMIN_USER_SUBSCRIPTION_STATUS_INACTIVE": "❌ Неактивна", + "ADMIN_USER_SUBSCRIPTION_TYPE_PAID": "💎 Платная", + "ADMIN_USER_SUBSCRIPTION_TYPE_TRIAL": "🎁 Триал", + "ADMIN_USER_TRAFFIC_USAGE": "{used}/{limit} ГБ", + "ADMIN_USER_TRANSACTIONS": "📋 Транзакции", + "ADMIN_USER_SEND_MESSAGE": "✉️ Отправить сообщение", + "ADMIN_USER_SEND_MESSAGE_PROMPT": "✉️ Отправка сообщения пользователю\n\nВведите текст, который бот отправит пользователю.\n\nМожно отменить командой /cancel или кнопкой ниже.", + "ADMIN_USER_SEND_MESSAGE_SUCCESS": "✅ Сообщение отправлено пользователю", + "ADMIN_USER_SEND_MESSAGE_FORBIDDEN": "⚠️ Пользователь заблокировал бота или не может получать сообщения.", + "ADMIN_USER_SEND_MESSAGE_BAD_REQUEST": "❌ Telegram отклонил сообщение. Проверьте текст и попробуйте ещё раз.", + "ADMIN_USER_SEND_MESSAGE_ERROR": "❌ Не удалось отправить сообщение. Попробуйте позже.", + "ADMIN_USER_SEND_MESSAGE_ERROR_NOT_FOUND": "❌ Пользователь не найден", + "ADMIN_USER_SEND_MESSAGE_EMPTY": "❌ Пожалуйста, введите непустое сообщение", + "ADMIN_USER_UNBLOCK": "✅ Разблокировать", + "ADMIN_USER_USERNAME_NOT_SET": "не указан", + "ADMIN_WELCOME_DISABLE": "🔴 Отключить", + "ADMIN_WELCOME_EDIT": "📝 Изменить текст", + "ADMIN_WELCOME_ENABLE": "🟢 Включить", + "ADMIN_WELCOME_HTML": "🏷️ HTML форматирование", + "ADMIN_WELCOME_PLACEHOLDERS": "💡 Плейсхолдеры", + "ADMIN_WELCOME_PREVIEW": "👁️ Предпросмотр", + "ADMIN_WELCOME_RESET": "🔄 Сбросить", + "ADMIN_WELCOME_SHOW": "👁️ Показать текущий", + "ALREADY_REGISTERED_REFERRAL": "ℹ️ Вы уже зарегистрированы в системе. Реферальная ссылка не может быть применена.", + "ATTACHMENTS_SENT": "✅ Вложения отправлены.", + "AUTOPAY_BUTTON": "💳 Автоплатёж", + "AUTOPAY_DAYS_SET": "✅ Установлено {days} дней!", + "AUTOPAY_DISABLED_TEXT": "Отключен - не забудьте продлить вручную!", + "AUTOPAY_ENABLED_TEXT": "Включен - подписка продлится автоматически", + "AUTOPAY_FAILED": "\n❌ Ошибка автоплатежа\n\nНе удалось списать средства для продления подписки.\nНедостаточно средств на балансе: {balance}\nТребуется: {required}\n\nПополните баланс и продлите подписку вручную.\n", + "AUTOPAY_MENU_TEXT": "💳 Автоплатеж\n\n📊 Статус: {status}\n⏰ Списание за: {days} дн. до окончания\n\nВыберите действие:", + "AUTOPAY_SELECT_DAYS_PROMPT": "⏰ Выберите за сколько дней до окончания списывать средства:", + "AUTOPAY_SET_DAYS_BUTTON": "⚙️ Настроить дни", + "AUTOPAY_STATUS_DISABLED": "выключен", + "AUTOPAY_STATUS_ENABLED": "включен", + "AUTOPAY_SUCCESS": "\n✅ Автоплатеж выполнен\n\nВаша подписка автоматически продлена на {days} дней.\nСписано с баланса: {amount}\n", + "AUTOPAY_TOGGLE_SUCCESS": "✅ Автоплатеж {status}!", + "BACK": "⬅️ Назад", + "BACK_BUTTON": "◀️ Назад", + "BACK_TO_MAIN_MENU_BUTTON": "⬅️ В главное меню", + "BACK_TO_MENU": "🏠 В главное меню", + "BACK_TO_OPEN_TICKETS": "🔴 Открытые тикеты", + "BACK_TO_SUBSCRIPTION": "⬅️ К подписке", + "BACK_TO_SUPPORT": "⬅️ К поддержке", + "BACK_TO_TICKETS": "⬅️ К тикетам", + "BALANCE_BUTTON": "💰 Баланс: {balance}", + "BALANCE_BUTTON_DEFAULT": "💰 Баланс: {balance}", + "BALANCE_BUTTON_ZERO": "💰 Баланс: 0 ₽", + "BALANCE_HISTORY": "📊 История операций", + "BALANCE_INFO": "\n💰 Баланс: {balance}\n\nВыберите действие:\n", + "BALANCE_SUPPORT_REQUEST": "🛠️ Запрос через поддержку", + "BALANCE_TOPUP": "💳 Пополнить баланс", + "BALANCE_TOPUP_CART_REMINDER_DETAILED": "\n💡 Требуется пополнение баланса\n\nВ вашей корзине находятся товары на общую сумму {total_amount}, но на балансе недостаточно средств.\n\n💳 Пополните баланс, чтобы завершить покупку.\n\nВыберите способ пополнения:", + "AUTO_PURCHASE_SUBSCRIPTION_SUCCESS": "✅ Подписка на {period} автоматически оформлена после пополнения баланса.", + "AUTO_PURCHASE_SUBSCRIPTION_EXTENDED": "✅ Подписка автоматически продлена на {period}.", + "AUTO_PURCHASE_SUBSCRIPTION_EXTENDED_DETAILS": "⏰ Новая дата окончания: {date}.", + "AUTO_PURCHASE_SUBSCRIPTION_HINT": "Перейдите в раздел «Моя подписка», чтобы получить ссылку и инструкции.", + "BALANCE_TOP_UP": "💳 Пополнить", + "BLOCK_BY_TIME": "⏳ Блокировка по времени", + "BLOCK_FOREVER": "🚫 Заблокировать", + "BUY_SUBSCRIPTION_START": "\n💎 Настройка подписки\n\nДавайте настроим вашу подписку под ваши потребности.\n\nСначала выберите период подписки:\n", + "CAMPAIGN_BONUS_BALANCE": "🎉 Вы получили {amount} за регистрацию по кампании «{name}»!", + "CAMPAIGN_BONUS_SUBSCRIPTION": "🎉 Вам выдана подписка на {days} д. (трафик: {traffic}, устройств: {devices}) по кампании «{name}»!", + "CAMPAIGN_EXISTING_USER": "ℹ️ Эта рекламная ссылка доступна только новым пользователям.", + "CAMPAIGN_EXISTING_USERL": "ℹ️ Эта рекламная ссылка доступна только новым пользователям.", + "CANCEL": "❌ Отмена", + "CANCEL_REPLY": "❌ Отменить ответ", + "CANCEL_TICKET_CREATION": "❌ Отменить создание тикета", + "CHANGE_DEVICES_BUTTON": "📱 Изменить устройства", + "CHANGE_DEVICES_CONFIRM": "\n 📱 Подтверждение изменения\n\n Текущее количество: {current_devices} устройств\n Новое количество: {new_devices} устройств\n\n Действие: {action}\n 💰 {cost}\n\n Подтвердить изменение?\n ", + "CHANGE_DEVICES_INFO": "\n 📱 Изменение количества устройств\n\n Текущий лимит: {current_devices} устройств\n\n Выберите новое количество устройств:\n\n 💡 Важно:\n • При увеличении - доплата пропорционально оставшемуся времени\n • При уменьшении - возврат средств не производится\n ", + "CHANGE_DEVICES_PROMPT": "📱 Изменение количества устройств\n\nТекущий лимит: {current_devices} устройств\nВыберите новое количество устройств:\n\n💡 Важно:\n• При увеличении - доплата пропорционально оставшемуся времени\n• При уменьшении - возврат средств не производится", + "CHANGE_DEVICES_PROMPT_TARIFF": "📱 Изменение количества устройств\n\nТекущий лимит: {current_devices} устройств\nЦена за доп. устройство: {price}/мес\nВыберите новое количество устройств:\n\n💡 Важно:\n• При увеличении - доплата пропорционально оставшемуся времени\n• При уменьшении - возврат средств не производится", + "CHANGE_DEVICES_SUCCESS_DECREASE": "\n ✅ Количество устройств уменьшено!\n\n 📱 Было: {old_count} → Стало: {new_count}\n ℹ️ Возврат средств не производится\n ", + "CHANGE_DEVICES_SUCCESS_INCREASE": "\n ✅ Количество устройств увеличено!\n\n 📱 Было: {old_count} → Стало: {new_count}\n 💰 Списано: {amount}\n ", + "CHANGE_DEVICES_TITLE": "📱 Изменение количества устройств", + "CHANGE_TARIFF_BUTTON": "📦 Тариф", + "CHANNEL_CHECK_BUTTON": "✅ Я подписался", + "CHANNEL_REQUIRED_TEXT": "🔒 Для использования бота подпишитесь на новостной канал, а затем нажмите кнопку ниже.", + "CHANNEL_SUBSCRIBE_BUTTON": "🔗 Подписаться", + "CHANNEL_SUBSCRIBE_REQUIRED_ALERT": "❌ Вы не подписались на канал!", + "CHANNEL_SUBSCRIBE_THANKS": "✅ Спасибо за подписку", + "CHECK_STATUS_BUTTON": "📊 Проверить статус", + "CHECK_STATUS_NO_CHANGES": "Статус не изменился", + "CHOOSE_ANOTHER_DEVICE": "📱 Выбрать другое устройство", + "CLOSED_TICKETS": "🟢 Закрытые", + "CLOSED_TICKETS_HEADER": "🟢 Закрытые тикеты", + "CLOSED_TICKETS_TITLE": "🟢 Закрытые тикеты:", + "CLOSE_NOTIFICATION": "❌ Закрыть уведомление", + "CLOSE_TICKET": "🔒 Закрыть тикет", + "CONFIRM": "✅ Подтвердить", + "CONFIRM_CHANGE_BUTTON": "✅ Подтвердить изменение", + "CONNECT_BUTTON": "🔗 Подключиться", + "CONTACT_SUPPORT": "💬 Написать в поддержку", + "CONTACT_SUPPORT_BUTTON": "💬 Связаться с поддержкой", + "CONTINUE": "➡️ Продолжить", + "CONTINUE_BUTTON": "✅ Продолжить", + "COPY_SUBSCRIPTION_LINK": "📋 Скопировать ссылку подписки", + "COUNTRY_CHANGES_ACTIVE_COUNT": "🌐 Активных стран: {count}", + "COUNTRY_CHANGES_ADDED_HEADER": "➕ Добавлены страны:\n", + "COUNTRY_CHANGES_CHARGED": "💰 Списано: {amount} (за {months} мес)", + "COUNTRY_CHANGES_DISCOUNT_INFO": " (скидка {percent}%: -{amount})", + "COUNTRY_CHANGES_NOT_FOUND": "⚠️ Изменения не обнаружены", + "COUNTRY_CHANGES_REMOVED_HEADER": "➖ Отключены страны:\n", + "COUNTRY_CHANGES_REMOVED_WARNING": "ℹ️ Повторное подключение будет платным", + "COUNTRY_CHANGES_SUCCESS_HEADER": "✅ Страны успешно обновлены!\n\n", + "COUNTRIES_MINIMUM_REQUIRED": "❌ Нельзя отключить все страны. Должна быть подключена хотя бы одна страна.", + "COUNTRY_MANAGEMENT_NONE": "Нет подключенных стран", + "COUNTRY_MANAGEMENT_PROMPT": "🌍 Управление странами подписки\n\n📋 Текущие страны ({current_count}):\n{current_list}\n\n💡 Инструкция:\n✅ - страна подключена\n➕ - будет добавлена (платно)\n➖ - будет отключена (бесплатно)\n⚪ - не выбрана\n\n⚠️ Важно: Повторное подключение отключенных стран будет платным!", + "COUNTRY_MANAGEMENT_UNAVAILABLE": "ℹ️ Управление серверами недоступно - доступен только один сервер", + "COUNTRY_NOT_AVAILABLE_PROMOGROUP": "❌ Сервер недоступен для вашей промогруппы", + "CREATE_INVITE": "📝 Создать приглашение", + "CREATE_INVITE_BUTTON": "📝 Создать приглашение", + "CREATE_TICKET_BUTTON": "🎫 Создать тикет", + "CUSTOM_MINIAPP_URL_NOT_SET": "⚠ Кастомная ссылка для мини-приложения не настроена", + "DELETE_MESSAGE": "🗑 Удалить", + "DEVICES_INSUFFICIENT_BALANCE": "⚠️ Недостаточно средств!\nТребуется: {required} (за {months} мес)\nУ вас: {balance}", + "DEVICES_LIMIT_EXCEEDED": "⚠️ Превышен максимальный лимит устройств ({limit})", + "DEVICES_MINIMUM_LIMIT": "⚠️ Минимальное количество устройств: {limit}", + "DEVICES_NO_CHANGE": "ℹ️ Количество устройств не изменилось", + "DEVICE_CHANGE_ACTION_DECREASE": "уменьшить до {count}", + "DEVICE_CHANGE_ACTION_INCREASE": "увеличить до {count}", + "DEVICE_CHANGE_CHARGED": "💰 Списано: {amount}", + "DEVICE_CHANGE_CONFIRMATION": "📱 Подтверждение изменения\n\nТекущее количество: {current} устройств\nНовое количество: {new} устройств\n\nДействие: {action}\n💰 {cost}\n\nПодтвердить изменение?", + "DEVICE_CHANGE_DECREASE_SUCCESS": "✅ Количество устройств уменьшено!\n\n", + "DEVICE_CHANGE_DISCOUNT_INFO": " (скидка {percent}%: -{amount})", + "DEVICE_CHANGE_EXTRA_COST": "Доплата: {amount} (за {period})", + "DEVICE_CHANGE_FREE": "Бесплатно", + "DEVICE_CHANGE_INCREASE_SUCCESS": "✅ Количество устройств увеличено!\n\n", + "DEVICE_CHANGE_NO_REFUND": "Возврат средств не производится", + "DEVICE_CHANGE_NO_REFUND_INFO": "ℹ️ Возврат средств не производится", + "DEVICE_CHANGE_RESULT_LINE": "📱 Было: {old} → Стало: {new}\n", + "DEVICES_INVALID_REQUEST": "❌ Некорректный запрос", + "DEVICES_INVALID_COUNT": "❌ Некорректное количество устройств", + "DEVICES_SELECTION_DISABLED": "⚠️ Выбор количества устройств недоступен", + "DEVICE_CONNECTION_HELP": "❓ Как подключить устройство заново?", + "DEVICE_FETCH_ERROR": "❌ Ошибка получения устройств", + "DEVICE_FETCH_INFO_ERROR": "❌ Ошибка получения информации об устройствах", + "DEVICE_GUIDE_ANDROID": "🤖 Android", + "DEVICE_GUIDE_ANDROID_TV": "📺 Android TV", + "DEVICE_GUIDE_APPLE_TV": "📺 Apple TV", + "DEVICE_GUIDE_IOS": "📱 iOS (iPhone/iPad)", + "DEVICE_GUIDE_MAC": "🎯 macOS", + "DEVICE_GUIDE_WINDOWS": "💻 Windows", + "DEVICE_LIST_FETCH_ERROR": "❌ Ошибка получения списка устройств", + "DEVICE_MANAGEMENT_ACTIONS": "\n💡 Действия:\n• Выберите устройство для сброса\n• Или сбросьте все устройства сразу", + "DEVICE_MANAGEMENT_CONNECTED_HEADER": "Подключенные устройства:\n", + "DEVICE_MANAGEMENT_LIST_ITEM": "• {device}\n", + "DEVICE_MANAGEMENT_OVERVIEW": "🔄 Управление устройствами\n\n📊 Всего подключено: {total} устройств\n📄 Страница {page} из {pages}\n\n", + "DEVICE_NONE_CONNECTED": "ℹ️ У вас нет подключенных устройств", + "DEVICE_PAGE_LOAD_ERROR": "❌ Ошибка загрузки страницы", + "DEVICE_RESET_ALL_DONE": "ℹ️ Все устройства сброшены", + "DEVICE_RESET_ALL_FAILED_MESSAGE": "❌ Не удалось сбросить устройства\n\nПопробуйте еще раз позже или обратитесь в техподдержку.\n\nВсего устройств: {total}", + "DEVICE_RESET_ALL_SUCCESS_MESSAGE": "✅ Все устройства успешно сброшены!\n\n🔄 Сброшено: {count} устройств\n📱 Теперь вы можете заново подключить свои устройства\n\n💡 Используйте ссылку из раздела 'Моя подписка' для повторного подключения", + "DEVICE_RESET_ERROR": "❌ Ошибка сброса устройства", + "DEVICE_RESET_ID_FAILED": "❌ Не удалось получить ID устройства", + "DEVICE_RESET_INVALID_REQUEST": "❌ Ошибка: некорректный запрос", + "DEVICE_RESET_NOT_FOUND": "❌ Устройство не найдено", + "DEVICE_RESET_PARSE_ERROR": "❌ Ошибка обработки запроса", + "DEVICE_RESET_PARTIAL_MESSAGE": "⚠️ Частичный сброс устройств\n\n✅ Удалено: {success} устройств\n❌ Не удалось удалить: {failed} устройств\n\nПопробуйте еще раз или обратитесь в поддержку.", + "DEVICE_RESET_SUCCESS": "✅ Устройство {device} успешно сброшено!", + "DEVICE_UUID_NOT_FOUND": "❌ UUID пользователя не найден", + "DISABLE_BUTTON": "❌ Выключить", + "DISCOUNT_BONUS_DESCRIPTION": "Скидка за продление подписки", + "DISCOUNT_CLAIM_ALREADY": "ℹ️ Скидка уже была активирована ранее.", + "DISCOUNT_CLAIM_ERROR": "❌ Не удалось активировать скидку. Попробуйте позже.", + "DISCOUNT_CLAIM_EXPIRED": "⚠️ Время действия предложения истекло.", + "DISCOUNT_CLAIM_NOT_FOUND": "❌ Предложение не найдено.", + "DISCOUNT_CLAIM_SUCCESS": "🎉 Скидка {percent}% активирована! \n\nОна суммируется с другими скидками и автоматически применится при следующей оплате.", + "ENABLE_BUTTON": "✅ Включить", + "ENTER_BLOCK_MINUTES": "Введите количество минут для блокировки пользователя (например, 15):", + "ERROR": "❌ Произошла ошибка", + "ERROR_RULES_RETRY": "Произошла ошибка. Попробуйте принять правила еще раз:", + "ERROR_TRY_AGAIN": "❌ Произошла ошибка. Попробуйте еще раз.", + "FAQ_BACK_TO_LIST": "⬅️ К списку FAQ", + "FAQ_HEADER": "❓ FAQ", + "FAQ_NOT_AVAILABLE": "FAQ временно недоступен.", + "FAQ_PAGES_PROMPT": "Выберите вопрос:", + "FAQ_PAGE_EMPTY": "Текст для этой страницы ещё не добавлен.", + "FAQ_PAGE_FOOTER": "Страница {current} из {total}", + "FAQ_PAGE_NOT_AVAILABLE": "Эта страница FAQ недоступна.", + "FAQ_PAGE_TITLE": "{title}", + "FAQ_PAGE_UNTITLED": "Без названия", + "FREEKASSA_ENTER_AMOUNT": "💳 Пополнение через {name}\n\nВведите сумму пополнения в рублях.\n\nМинимум: {min_amount}\nМаксимум: {max_amount}", + "GO_TO_BALANCE_TOP_UP": "💳 Перейти к пополнению баланса", + "HAPP_DOWNLOAD_BUTTON": "⬇️ Скачать Happ", + "HAPP_DOWNLOAD_LINK_MESSAGE": "⬇️ Скачайте Happ для {platform}:", + "HAPP_DOWNLOAD_LINK_NOT_SET": "❌ Ссылка для этого устройства не настроена", + "HAPP_DOWNLOAD_OPEN_LINK": "🔗 Открыть ссылку", + "HAPP_DOWNLOAD_PROMPT": "📥 Скачать Happ\nВыберите ваше устройство:", + "HAPP_PLATFORM_ANDROID": "🤖 Android", + "HAPP_PLATFORM_IOS": "🍎 iOS", + "HAPP_PLATFORM_MACOS": "🖥️ Mac OS", + "HAPP_PLATFORM_PC": "💻 ПК", + "HAPP_PLATFORM_WINDOWS": "💻 Windows", + "INSUFFICIENT_BALANCE": "❌ Недостаточно средств на балансе. \n \n Пополните баланс на {amount} и попробуйте снова.\n ", + "INVALID_AMOUNT": "❌ Неверная сумма", + "LANGUAGE_PROMPT": "🌐 زبان رابط را انتخاب کنید:", + "LANGUAGE_SELECTED": "🌐 زبان رابط انتخاب شد: فارسی", + "LANGUAGE_SELECTION_DISABLED": "⚙️ Выбор языка временно недоступен. Используем язык по умолчанию.", + "LOADING": "⏳ Загрузка...", + "MAINTENANCE_MODE_ACTIVE": "\n🔧 Технические работы!\n\nСервис временно недоступен. Ведутся технические работы по улучшению качества обслуживания.\n\n⏰ Ориентировочное время завершения: неизвестно\n🔄 Попробуйте позже\n\nПриносим извинения за временные неудобства.\n", + "MAINTENANCE_MODE_API_ERROR": "\n🔧 Технические работы!\n\nСервис временно недоступен из-за проблем с подключением к серверам.\n\n⏰ Мы работаем над восстановлением. Попробуйте через несколько минут.\n\n🔄 Последняя проверка: {last_check}\n", + "MAIN_MENU": "👤 {user_name}\n \n📱 Подписка: {subscription_status}\n\nВыберите действие:\n", + "MAIN_MENU_ACTION_PROMPT": "Выберите действие:", + "MAIN_MENU_BUTTON": "🏠 Главное меню", + "MAIN_MENU_TEST_ACCESS_HEADER": "🧪 Тестовые сервера активны: {servers}", + "MAIN_MENU_TEST_ACCESS_TIMER": "⏳ Доступ действует ещё: {time_left}\n{bar}", + "MANAGE_DEVICES_BUTTON": "🔧 Управление устройствами", + "MARK_AS_ANSWERED": "✅ Отметить как отвеченный", + "MENU_ADMIN": "⚙️ Админ-панель", + "MENU_BALANCE": "💰 Баланс", + "MENU_BUY_SUBSCRIPTION": "💎 Купить подписку", + "MENU_EXTEND_SUBSCRIPTION": "⏰ Продлить подписку", + "MENU_FAQ": "❓ FAQ", + "MENU_INFO": "ℹ️ Инфо", + "MENU_INFO_HEADER": "ℹ️ Инфо", + "MENU_INFO_PROMPT": "Выберите раздел:", + "MENU_LANGUAGE": "🌐 زبان", + "MENU_PRIVACY_POLICY": "🛡️ Политика конф.", + "MENU_PROFILE": "👤 Личный кабинет", + "MENU_PROFILE_UNAVAILABLE": "❗️ Личный кабинет пока недоступен. Попробуйте позже.", + "MENU_PROMOCODE": "🎫 Промокод", + "MENU_PROMO_GROUPS_INFO": "🎯 Скидки за траты", + "MENU_PUBLIC_OFFER": "📄 Оферта", + "MENU_REFERRALS": "🤝 Партнерка", + "MENU_RULES": "📋 Правила сервиса", + "MENU_SERVER_STATUS": "📊 Статус серверов", + "MENU_SUBSCRIPTION": "📱 Подписка", + "MENU_SUPPORT": "🛠️ Техподдержка", + "MENU_TRIAL": "🧪 Тестовая подписка", + "MINIAPP_PURCHASE_BREAKDOWN_BASE": "Базовый план", + "MINIAPP_PURCHASE_BREAKDOWN_DEVICES": "Устройства", + "MINIAPP_PURCHASE_BREAKDOWN_DISCOUNT_NOTE": "Скидка: -{amount} ({percent}%)", + "MINIAPP_PURCHASE_BREAKDOWN_PROMO": "Промо скидка", + "MINIAPP_PURCHASE_BREAKDOWN_SERVERS": "Серверы", + "MINIAPP_PURCHASE_BREAKDOWN_TRAFFIC": "Трафик", + "MINIAPP_PURCHASE_DISCOUNT_DEVICES": "Скидка на устройства: -{amount} ({percent}%)", + "MINIAPP_PURCHASE_DISCOUNT_PERIOD": "Скидка на период: -{amount} ({percent}%)", + "MINIAPP_PURCHASE_DISCOUNT_PROMO": "Промо-предложение: -{amount} ({percent}%)", + "MINIAPP_PURCHASE_DISCOUNT_SERVERS": "Скидка на серверы: -{amount} ({percent}%)", + "MINIAPP_PURCHASE_DISCOUNT_TRAFFIC": "Скидка на трафик: -{amount} ({percent}%)", + "MINIAPP_PURCHASE_STATUS_INSUFFICIENT": "Недостаточно средств на балансе", + "MINIAPP_PURCHASE_SUMMARY_DISCOUNT": "Экономия {amount}", + "MULENPAY_PAYMENT_ERROR": "❌ Ошибка создания платежа {mulenpay_name}. Попробуйте позже или обратитесь в поддержку.", + "MULENPAY_PAYMENT_INSTRUCTIONS": "💳 Оплата через {mulenpay_name_html}\n\n💰 Сумма: {amount}\n🆔 ID платежа: {payment_id}\n\n📱 Инструкция:\n1. Нажмите кнопку ‘Оплатить через {mulenpay_name}’\n2. Следуйте подсказкам платежной системы\n3. Подтвердите перевод\n4. Средства зачислятся автоматически\n\n❓ Если возникнут проблемы, обратитесь в {support}", + "MULENPAY_PAY_BUTTON": "💳 Оплатить через {mulenpay_name}", + "MULENPAY_TOPUP_PROMPT": "💳 Оплата через {mulenpay_name_html}\n\nВведите сумму для пополнения от 100 до 100 000 ₽.\nОплата происходит через защищенную платформу {mulenpay_name}.", + "MY_BALANCE_BUTTON": "💰 Мой баланс", + "MY_SUBSCRIPTION_BUTTON": "📱 Моя подписка", + "MY_TICKETS_BUTTON": "📋 Мои тикеты", + "MY_TICKETS_TITLE": "📋 Ваши тикеты:", + "NO": "❌ Нет", + "NOTIFICATION_CLOSED": "Уведомление закрыто.", + "NOTIFICATION_VALUE_INVALID": "❌ Некорректное значение, укажите число.", + "NOTIFICATION_VALUE_UPDATED": "✅ Настройки обновлены.", + "NOTIFY_PROMPT_SECOND_HOURS": "Введите количество часов действия скидки (1-168):", + "NOTIFY_PROMPT_SECOND_PERCENT": "Введите новый процент скидки для уведомления через 2-3 дня (0-100):", + "NOTIFY_PROMPT_THIRD_DAYS": "Через сколько дней после истечения отправлять предложение? (минимум 2):", + "NOTIFY_PROMPT_THIRD_HOURS": "Введите количество часов действия скидки (1-168):", + "NOTIFY_PROMPT_THIRD_PERCENT": "Введите новый процент скидки для позднего предложения (0-100):", + "NO_ATTACHMENTS": "Вложений нет.", + "NO_CLOSED_TICKETS": "Закрытых тикетов пока нет.", + "NO_SERVERS_AVAILABLE": "❌ Нет доступных серверов", + "NO_TICKETS": "У вас пока нет тикетов.", + "NO_TICKETS_ADMIN": "Нет тикетов для отображения.", + "NO_TRAFFIC_PACKAGES": "❌ Нет доступных пакетов", + "OPEN_TICKETS": "🔴 Открытые", + "OPEN_TICKETS_HEADER": "🔴 Открытые тикеты", + "OPERATION_CANCELLED": "❌ Операция отменена", + "OTHER_APPS_BUTTON": "📋 Другие приложения", + "PAGINATION_NEXT": "➡️", + "PAGINATION_PREV": "⬅️", + "PAID_FEATURE_ONLY": "⚠ Эта функция доступна только для платных подписок", + "PAID_FEATURE_ONLY_SHORT": "⚠ Только для платных подписок", + "PAL24_CARD_PAY_BUTTON": "💳 Оплатить банковской картой (PayPalych)", + "PAL24_INSTRUCTION_BUTTON": "{step}. Нажмите кнопку «{button}»", + "PAL24_INSTRUCTION_COMPLETE": "{step}. Средства зачислятся автоматически", + "PAL24_INSTRUCTION_CONFIRM": "{step}. Подтвердите перевод", + "PAL24_INSTRUCTION_FOLLOW": "{step}. Следуйте подсказкам платёжной системы", + "PAL24_PAYMENT_ERROR": "❌ Ошибка создания платежа PayPalych. Попробуйте позже или обратитесь в поддержку.", + "PAL24_PAYMENT_INSTRUCTIONS": "🏦 Оплата через PayPalych (СБП)\n\n💰 Сумма: {amount}\n🆔 ID счета: {bill_id}\n\n📱 Инструкция:\n1. Нажмите кнопку ‘Оплатить через PayPalych (СБП)’\n2. Следуйте подсказкам платежной системы\n3. Подтвердите перевод\n4. Средства зачислятся автоматически\n\n❓ Если возникнут проблемы, обратитесь в {support}", + "PAL24_SBP_PAY_BUTTON": "🏦 Оплатить через PayPalych (СБП)", + "PAL24_SELECT_PAYMENT_METHOD": "Выберите способ оплаты PayPalych:", + "PAL24_TOPUP_PROMPT": "🏦 Оплата через PayPalych (СБП)\n\nВведите сумму для пополнения от 100 до 1 000 000 ₽.\nОплата проходит через систему быстрых платежей PayPalych.", + "PAYMENTS_TEMPORARILY_UNAVAILABLE": "⚠️ Способы оплаты временно недоступны", + "PAYMENT_CARD_MULENPAY": "💳 Банковская карта ({mulenpay_name})", + "PAYMENT_CARD_PAL24": "🏦 СБП (PayPalych)", + "PAYMENT_CARD_TRIBUTE": "💳 Банковская карта (Tribute)", + "PAYMENT_CARD_WATA": "💳 Банковская карта (WATA)", + "PAYMENT_CARD_YOOKASSA": "💳 Банковская карта (YooKassa)", + "PAYMENT_PLATEGA": "💳 Platega", + "PAYMENT_CHARGE_ERROR": "⚠️ Ошибка списания средств", + "PAYMENT_CREATE_ERROR": "❌ Не удалось создать платёж. Попробуйте позже.", + "PAYMENT_CRYPTOBOT": "🪙 Криптовалюта (CryptoBot)", + "PAYMENT_HELEKET": "🪙 Криптовалюта (Heleket)", + "HELEKET_PAYMENT_ALREADY_PAID": "✅ Платёж уже зачислен", + "HELEKET_PAYMENT_SUCCESS": "✅ Платёж зачислен на баланс", + "HELEKET_STATUS_CHECK": "⏳ Ожидаем оплату", + "HELEKET_STATUS_PROCESS": "⚙️ Платёж обрабатывается", + "HELEKET_STATUS_CONFIRM_CHECK": "⛓ Ожидание подтверждений сети", + "HELEKET_STATUS_WRONG_AMOUNT": "❗️ Оплачена неверная сумма", + "HELEKET_STATUS_WRONG_AMOUNT_WAITING": "❗️ Недостаточная сумма, ожидаем доплату", + "HELEKET_STATUS_PAID_OVER": "✅ Платёж зачислен (с переплатой)", + "HELEKET_STATUS_PAID": "✅ Платёж зачислен", + "HELEKET_STATUS_CANCEL": "🚫 Платёж отменён", + "HELEKET_STATUS_FAIL": "❌ Ошибка при оплате", + "HELEKET_STATUS_SYSTEM_FAIL": "❌ Системная ошибка Heleket", + "HELEKET_STATUS_REFUND_PROCESS": "↩️ Возврат обрабатывается", + "HELEKET_STATUS_REFUND_FAIL": "⚠️ Ошибка возврата", + "HELEKET_STATUS_REFUND_PAID": "✅ Возврат выполнен", + "HELEKET_STATUS_LOCKED": "🔒 Средства заблокированы", + "HELEKET_STATUS_UNKNOWN": "ℹ️ Статус платежа: {status}", + "PAYMENT_METHODS_FOOTER": "Выберите способ пополнения:", + "PAYMENT_METHODS_ONLY_SUPPORT": "💳 Способы пополнения баланса\n\n⚠️ В данный момент автоматические способы оплаты временно недоступны.\nОбратитесь в техподдержку для пополнения баланса.\n\nВыберите способ пополнения:", + "PAYMENT_METHODS_PROMPT": "Выберите удобный для вас способ оплаты:", + "PAYMENT_METHODS_TITLE": "💳 Способы пополнения баланса", + "PAYMENT_METHODS_UNAVAILABLE_ALERT": "⚠️ В данный момент автоматические способы оплаты временно недоступны. Для пополнения баланса обратитесь в техподдержку.", + "PAYMENT_METHOD_CRYPTOBOT_DESCRIPTION": "через CryptoBot", + "PAYMENT_METHOD_CRYPTOBOT_NAME": "🪙 Криптовалюта", + "PAYMENT_METHOD_MULENPAY_DESCRIPTION": "через {mulenpay_name}", + "PAYMENT_METHOD_MULENPAY_NAME": "💳 Банковская карта ({mulenpay_name})", + "PAYMENT_METHOD_PLATEGA_DESCRIPTION": "через {platega_name} (карты + СБП)", + "PAYMENT_METHOD_PLATEGA_NAME": "💳 Банковская карта ({platega_name})", + "PAYMENT_METHOD_STARS_DESCRIPTION": "быстро и удобно", + "PAYMENT_METHOD_STARS_NAME": "⭐ Telegram Stars", + "PAYMENT_METHOD_SUPPORT_DESCRIPTION": "другие способы", + "PAYMENT_METHOD_SUPPORT_NAME": "🛠️ Через поддержку", + "PAYMENT_METHOD_TRIBUTE_DESCRIPTION": "через Tribute", + "PAYMENT_METHOD_TRIBUTE_NAME": "💳 Банковская карта", + "PAYMENT_METHOD_HELEKET_DESCRIPTION": "через Heleket", + "PAYMENT_METHOD_HELEKET_NAME": "🪙 Криптовалюта (Heleket)", + "PAYMENT_METHOD_YOOKASSA_DESCRIPTION": "через YooKassa", + "PAYMENT_METHOD_YOOKASSA_NAME": "💳 Банковская карта", + "PAYMENT_METHOD_YOOKASSA_SBP_DESCRIPTION": "через систему быстрых платежей YooKassa", + "PAYMENT_METHOD_YOOKASSA_SBP_NAME": "🏦 СБП (YooKassa)", + "PAYMENT_METHOD_WATA_DESCRIPTION": "через WATA", + "PAYMENT_METHOD_WATA_NAME": "💳 Банковская карта (WATA)", + "PAYMENT_HELEKET_MARKUP_LABEL": "Наценка провайдера", + "PAYMENT_HELEKET_DISCOUNT_LABEL": "Скидка провайдера", + "PAYMENT_RETURN_HOME_BUTTON": "🏠 На главную", + "PAYMENT_SBP_YOOKASSA": "🏬 Оплатить по СБП (YooKassa)", + "PAYMENT_TELEGRAM_STARS": "⭐ Telegram Stars", + "PAYMENT_VIA_SUPPORT": "🛠️ Через поддержку", + "PLATEGA_TOPUP_PROMPT": "💳 Оплата через Platega ({method_name})\n\nВведите сумму для пополнения от {min_amount} до {max_amount}.\nОплата происходит через Platega.", + "PLATEGA_SELECT_PAYMENT_METHOD": "Выберите способ оплаты Platega:", + "PLATEGA_TEMPORARILY_UNAVAILABLE": "❌ Оплата через Platega временно недоступна", + "PLATEGA_METHODS_NOT_CONFIGURED": "⚠️ На стороне Platega нет доступных методов оплаты", + "PLATEGA_METHOD_SELECTION_REQUIRED": "⚠️ Выберите способ оплаты Platega перед вводом суммы", + "PLATEGA_AMOUNT_TOO_LOW": "Минимальная сумма для оплаты через Platega: {amount}", + "PLATEGA_AMOUNT_TOO_HIGH": "Максимальная сумма для оплаты через Platega: {amount}", + "PLATEGA_PAYMENT_ERROR": "❌ Ошибка создания платежа Platega. Попробуйте позже или обратитесь в поддержку.", + "PLATEGA_PAYMENT_INSTRUCTIONS": "💳 Оплата через Platega ({method})\n\n💰 Сумма: {amount}\n🆔 ID транзакции: {transaction}\n\n📱 Инструкция:\n1. Нажмите кнопку «Оплатить»\n2. Следуйте подсказкам платёжной системы\n3. Подтвердите перевод\n4. Средства зачислятся автоматически\n\n❓ Если возникнут проблемы, обратитесь в {support}", + "PLATEGA_PAY_BUTTON": "💳 Оплатить через {method}", + "PLATEGA_PAYMENT_ALREADY_CONFIRMED": "✅ Платёж уже зачислен", + "PLATEGA_PAYMENT_STATUS": "Текущий статус платежа: {status}", + "PAY_NOW_BUTTON": "💳 Оплатить", + "PAY_WITH_COINS_BUTTON": "🪙 Оплатить", + "PENDING_CANCEL_BUTTON": "⌛ Отмена", + "PERIOD_14_DAYS": "📅 14 дней - {settings.format_price(settings.PRICE_14_DAYS)}", + "PERIOD_180_DAYS": "📅 180 дней - {settings.format_price(settings.PRICE_180_DAYS)}", + "PERIOD_30_DAYS": "📅 30 дней - {settings.format_price(settings.PRICE_30_DAYS)}", + "PERIOD_360_DAYS": "📅 360 дней - {settings.format_price(settings.PRICE_360_DAYS)}", + "PERIOD_60_DAYS": "📅 60 дней - {settings.format_price(settings.PRICE_60_DAYS)}", + "PERIOD_90_DAYS": "📅 90 дней - {settings.format_price(settings.PRICE_90_DAYS)}", + "POST_REGISTRATION_TRIAL_BUTTON": "🚀 Подключиться бесплатно 🚀", + "PRIVACY_POLICY_EMPTY_ALERT": "Политика конфиденциальности ещё не заполнена.", + "PRIVACY_POLICY_HEADER": "🛡️ Политика конфиденциальности", + "PRIVACY_POLICY_NOT_AVAILABLE": "Политика конфиденциальности временно недоступна.", + "PRIVACY_POLICY_PAGE_INFO": "Страница {current} из {total}", + "PRIVACY_RESTRICTED_BUTTON_HINT": "⚠️ Telegram не позволяет боту запросить контакт из-за ваших настроек приватности.\n\nРазрешите отправку контакта в настройках Telegram или поделитесь данными вручную в ответ на сообщение.", + "PROMOCODE_EMPTY_INPUT": "❌ Введите корректный промокод", + "PROMOCODE_ENTER": "🎫 Введите промокод:", + "PROMOCODE_EXPIRED": "❌ Промокод истек", + "PROMOCODE_INVALID": "❌ Неверный промокод", + "PROMOCODE_SUCCESS": "🎉 Промокод активирован! {description}", + "PROMOCODE_USED": "❌ Промокод уже использован", + "PROMOCODE_ACTIVE_DISCOUNT_EXISTS": "❌ У вас уже есть активная скидка. Используйте её перед активацией новой.", + "PROMO_GROUPS_INFO_CURRENT_LEVEL": "🏆 Текущий уровень: {name}", + "PROMO_GROUPS_INFO_EMPTY": "Промогруппы с автовыдачей ещё не настроены.", + "PROMO_GROUPS_INFO_HEADER": "🎯 Скидки за траты", + "PROMO_GROUPS_INFO_LEVELS_HEADER": "📋 Уровни с автовыдачей:", + "PROMO_GROUPS_INFO_LEVEL_LINE": "{status} {name} — от {amount}", + "PROMO_GROUPS_INFO_MAX_LEVEL": "🏆 Вы уже получили максимальный уровень скидок!", + "PROMO_GROUPS_INFO_NEXT_LEVEL": "📈 До уровня «{name}»: осталось {amount}", + "PROMO_GROUPS_INFO_NO_LEVEL": "🏆 Текущий уровень: пока не получен", + "PROMO_GROUPS_INFO_TOTAL_SPENT": "💰 Потрачено в боте: {amount}", + "PROMO_GROUP_DISCOUNTS_HEADER": "🎁 Скидки вашей промогруппы", + "PROMO_GROUP_DISCOUNT_DEVICES": "📱 Доп. устройства: {percent}%", + "PROMO_GROUP_DISCOUNT_SERVERS": "🌍 Серверы: {percent}%", + "PROMO_GROUP_DISCOUNT_TRAFFIC": "📊 Трафик: {percent}%", + "PROMO_GROUP_PERIOD_DISCOUNTS_HEADER": "⏳ Скидки за длительный период:", + "PROMO_GROUP_PERIOD_DISCOUNT_ITEM": "{period} — {percent}%", + "PROMO_OFFER_CLOSE": "❌ Закрыть", + "PUBLIC_OFFER_EMPTY_ALERT": "Публичная оферта ещё не заполнена.", + "PUBLIC_OFFER_HEADER": "📄 Публичная оферта", + "PUBLIC_OFFER_NOT_AVAILABLE": "Публичная оферта временно недоступна.", + "PUBLIC_OFFER_PAGE_INFO": "Страница {current} из {total}", + "REFERRAL_ANALYTICS_BUTTON": "📊 Аналитика", + "REFERRAL_ANALYTICS_EARNINGS_HEADER": "💰 Доходы по периодам:", + "REFERRAL_ANALYTICS_EARNINGS_MONTH": "• За месяц: {amount}", + "REFERRAL_ANALYTICS_EARNINGS_QUARTER": "• За квартал: {amount}", + "REFERRAL_ANALYTICS_EARNINGS_TODAY": "• Сегодня: {amount}", + "REFERRAL_ANALYTICS_EARNINGS_WEEK": "• За неделю: {amount}", + "REFERRAL_ANALYTICS_FOOTER": "📈 Продолжайте развивать свою реферальную сеть!", + "REFERRAL_ANALYTICS_TITLE": "📊 Аналитика рефералов", + "REFERRAL_ANALYTICS_TOP_ITEM": "{index}. {name}: {amount} ({count} начислений)", + "REFERRAL_ANALYTICS_TOP_TITLE": "🏆 Топ-{count} рефералов:", + "REFERRAL_CODE_ACCEPTED": "✅ Реферальный код принят!", + "REFERRAL_CODE_APPLIED": "🎁 Реферальный код применен! Вы получите бонус после первой покупки.", + "REFERRAL_CODE_INVALID": "❌ Неверный реферальный код", + "REFERRAL_CODE_INVALID_HELP": "❌ Неверный реферальный код.\n\n💡 Если у вас есть реферальный код, убедитесь что он введен правильно.\n⏭️ Для продолжения регистрации без реферального кода используйте команду /start", + "REFERRAL_CODE_QUESTION": "\n🤝 У вас есть реферальный код или промокод?\n\nЕсли у вас есть промокод или реферальная ссылка от друга, введите её сейчас, чтобы получить бонус!\n\nВведите код или нажмите \"Пропустить\":\n", + "REFERRAL_OR_PROMO_CODE_INVALID": "❌ Неверный реферальный код или промокод", + "REFERRAL_OR_PROMO_CODE_INVALID_HELP": "❌ Неверный реферальный код или промокод.\n\n💡 Если у вас есть реферальный код или промокод, убедитесь что он введен правильно.\n⏭️ Для продолжения регистрации без кода используйте команду /start", + "PROMOCODE_ACTIVATED_AT_REGISTRATION": "✅ Промокод активирован!\n\n{description}", + "PROMOCODE_ACCEPTED_WILL_ACTIVATE": "✅ Промокод принят! Он будет активирован после завершения регистрации.", + "REFERRAL_CODE_SKIP": "⏭️ Пропустить", + "REFERRAL_CODE_TITLE": "🆔 Ваш код: {code}", + "REFERRAL_EARNINGS_BY_TYPE_HEADER": "📈 Доходы по типам:", + "REFERRAL_EARNINGS_FIRST_TOPUPS": "• Бонусы за первые пополнения: {count} ({amount})", + "REFERRAL_EARNINGS_PURCHASES": "• Комиссии с покупок: {count} ({amount})", + "REFERRAL_EARNINGS_TOPUPS": "• Комиссии с пополнений: {count} ({amount})", + "REFERRAL_EARNING_REASON_COMMISSION_PURCHASE": "💰 Комиссия с покупки", + "REFERRAL_EARNING_REASON_COMMISSION_TOPUP": "💰 Комиссия с пополнения", + "REFERRAL_EARNING_REASON_FIRST_TOPUP": "🎉 Первое пополнение", + "REFERRAL_INFO": "\n🤝 Реферальная программа\n\n👥 Приглашено: {referrals_count} друзей\n💰 Заработано: {earned_amount}\n\n🔗 Ваша реферальная ссылка:\n{referral_link}\n\n🎫 Ваш промокод:\n{referral_code}\n\n💰 Условия:\n• За каждого друга: {registration_bonus}\n• Процент с пополнений: {commission_percent}%\n", + "REFERRAL_INVITE_BONUS": "💎 При первом пополнении от {minimum} ты получишь {bonus} бонусом на баланс!", + "REFERRAL_INVITE_CREATED_INSTRUCTION": "Нажмите кнопку «📤 Поделиться» чтобы отправить приглашение в любой чат, или скопируйте текст ниже:", + "REFERRAL_INVITE_CREATED_TITLE": "📝 Приглашение создано!", + "REFERRAL_INVITE_FEATURE_FAST": "🚀 Быстрое подключение", + "REFERRAL_INVITE_FEATURE_SECURE": "🔒 Надежная защита", + "REFERRAL_INVITE_FEATURE_SERVERS": "🌍 Серверы по всему миру", + "REFERRAL_INVITE_FOOTER": "📢 Приглашайте друзей и зарабатывайте!", + "REFERRAL_INVITE_LINK_PROMPT": "👇 Переходи по ссылке:", + "REFERRAL_INVITE_MESSAGE": "\n🎯 Приглашение в VPN сервис\n\nПривет! Приглашаю тебя в отличный VPN сервис!\n\n🎁 По моей ссылке ты получишь бонус: {bonus}\n\n🔗 Переходи: {link}\n🎫 Или используй промокод: {code}\n\n💪 Быстро, надежно, недорого!\n", + "REFERRAL_INVITE_TITLE": "🎉 Присоединяйся к VPN сервису!", + "REFERRAL_LINK_CAPTION": "🔗 Ваша реферальная ссылка:\n{link}", + "REFERRAL_LINK_TITLE": "🔗 Ваша реферальная ссылка:", + "REFERRAL_LIST_BUTTON": "👥 Список рефералов", + "REFERRAL_LIST_EMPTY": "📋 У вас пока нет рефералов.\n\nПоделитесь своей реферальной ссылкой, чтобы начать зарабатывать!", + "REFERRAL_LIST_HEADER": "👥 Ваши рефералы (стр. {current}/{total})", + "REFERRAL_LIST_ITEM_ACTIVITY": " 🕐 Активность: {days} дн. назад", + "REFERRAL_LIST_ITEM_ACTIVITY_LONG_AGO": " 🕐 Активность: давно", + "REFERRAL_LIST_ITEM_EARNED": " 💎 Заработано с него: {amount}", + "REFERRAL_LIST_ITEM_HEADER": "{index}. {status} {name}", + "REFERRAL_LIST_ITEM_REGISTERED": " 📅 Регистрация: {days} дн. назад", + "REFERRAL_LIST_ITEM_TOPUPS": " {emoji} Пополнений: {count}", + "REFERRAL_LIST_NEXT_PAGE": "Вперед ➡️", + "REFERRAL_LIST_PREV_PAGE": "⬅️ Назад", + "REFERRAL_PROGRAM_TITLE": "👥 Реферальная программа", + "REFERRAL_RECENT_EARNINGS_HEADER": "💰 Последние начисления:", + "REFERRAL_RECENT_EARNINGS_ITEM": "• {reason}: {amount} от {referral_name}", + "REFERRAL_REWARDS_HEADER": "🎁 Как работают награды:", + "REFERRAL_REWARD_COMMISSION": "• Комиссия с каждого пополнения реферала: {percent}%", + "REFERRAL_REWARD_INVITER": "• Вы получаете при первом пополнении реферала: {bonus}", + "REFERRAL_REWARD_NEW_USER": "• Новый пользователь получает: {bonus} при первом пополнении от {minimum}", + "REFERRAL_SHARE_BUTTON": "📤 Поделиться", + "REFERRAL_STATS_ACTIVE": "• Активных рефералов: {count}", + "REFERRAL_STATS_CONVERSION": "• Конверсия: {rate}%", + "REFERRAL_STATS_FIRST_TOPUPS": "• Сделали первое пополнение: {count}", + "REFERRAL_STATS_HEADER": "📊 Ваша статистика:", + "REFERRAL_STATS_INVITED": "• Приглашено пользователей: {count}", + "REFERRAL_STATS_MONTH_EARNED": "• За последний месяц: {amount}", + "REFERRAL_STATS_TOTAL_EARNED": "• Заработано всего: {amount}", + "REGISTRATION_COMPLETING": "✅ Завершаем регистрацию...", + "REPLY_TO_TICKET": "💬 Ответить", + "REPORT_CLOSE": "❌ Закрыть", + "REPORT_CLOSED": "✅ Отчет закрыт.", + "REPORT_CLOSE_ERROR": "❌ Не удалось закрыть отчет.", + "RESET_ALL_DEVICES_BUTTON": "🔄 Сбросить все устройства", + "RESET_DEVICE_CONFIRM_BUTTON": "✅ Да, сбросить это устройство", + "RESET_TRAFFIC_BUTTON": "🔄 Сбросить трафик", + "NO_SAVED_SUBSCRIPTION_ORDER": "❗️ Сохраненный заказ не найден.", + "RETURN_TO_SUBSCRIPTION_CHECKOUT": "⬅️ Вернуться к оформлению подписки", + "RULES_ACCEPT": "✅ Принимаю правила", + "RULES_ACCEPTED_PROCESSING": "✅ Правила приняты! Завершаем регистрацию...", + "RULES_DECLINE": "❌ Не принимаю", + "RULES_HEADER": "📋 Правила сервиса", + "PRIVACY_POLICY_ACCEPT": "✅ Принять", + "PRIVACY_POLICY_DECLINE": "❌ Отклонить", + "PRIVACY_POLICY_REQUIRED": "Для использования бота необходимо принять политику конфиденциальности.", + "PRIVACY_POLICY_ACCEPTED_PROCESSING": "✅ Политика конфиденциальности принята! Продолжаем регистрацию...", + "ERROR_PRIVACY_POLICY_RETRY": "Произошла ошибка. Попробуйте принять политику конфиденциальности еще раз:", + "RULES_REQUIRED": "❗️ Для использования сервиса необходимо принять правила!", + "RULES_TEXT_DEFAULT": "📋 Правила использования сервиса\n\n1. Запрещено использовать сервис для противоправной деятельности\n2. Не распространяйте пиратский или вредоносный контент\n3. Запрещены спам и фишинг\n4. Нельзя использовать сервис для DDoS-атак\n5. Один аккаунт предназначен для одного пользователя\n6. Возвраты возможны только в исключительных случаях\n7. Администрация может заблокировать аккаунт при нарушении правил\n\nИспользуя сервис, вы подтверждаете согласие с этими правилами.", + "PRIVACY_POLICY_TEXT_DEFAULT": "🔒 Политика конфиденциальности\n\nМы обязуемся защищать вашу конфиденциальность и личные данные.\n\nСбор данных:\n• Мы собираем только необходимую информацию для предоставления услуг\n• Данные используются исключительно для работы сервиса\n\nЗащита данных:\n• Ваши данные защищены современными методами шифрования\n• Мы не передаем данные третьим лицам без вашего согласия\n\nВаши права:\n• Вы можете запросить информацию о хранимых данных\n• Вы можете запросить удаление ваших данных\n\nИспользуя сервис, вы соглашаетесь с политикой конфиденциальности.", + "SELECT_COUNTRIES": "Выберите страны:", + "SELECT_DEVICES": "Количество устройств:", + "SELECT_PERIOD": "Выберите период:", + "SELECT_TRAFFIC": "Выберите пакет трафика:", + "SENDING_ATTACHMENTS": "📎 Отправляю вложения...", + "SEND_CONTACT_BUTTON": "📱 Отправить контакт", + "SEND_LOCATION_BUTTON": "📍 Отправить геолокацию", + "SERVER_STATUS_AVAILABLE": "✅ Доступны", + "SERVER_STATUS_ERROR_SHORT": "Не удалось получить данные", + "SERVER_STATUS_LATENCY": "{latency} мс", + "SERVER_STATUS_LATENCY_UNKNOWN": "нет данных", + "SERVER_STATUS_NEXT_PAGE": "Вперед ➡️", + "SERVER_STATUS_NOT_CONFIGURED": "Функция недоступна.", + "SERVER_STATUS_NO_SERVERS": "Нет данных о серверах.", + "SERVER_STATUS_OFFLINE": "нет ответа", + "SERVER_STATUS_PAGINATION": "Страница {current} из {total}", + "SERVER_STATUS_PREV_PAGE": "⬅️ Назад", + "SERVER_STATUS_REFRESH": "🔄 Обновить", + "SERVER_STATUS_SUMMARY": "Всего серверов: {total} (в сети: {online}, вне сети: {offline})", + "SERVER_STATUS_TITLE": "📊 Статус серверов", + "SERVER_STATUS_UNAVAILABLE": "❌ Недоступны", + "SERVER_STATUS_UPDATED_AT": "⏱ Обновлено: {time}", + "SHOW_QR_BUTTON": "📱 Показать QR код", + "SHOW_SUBSCRIPTION_LINK": "📋 Показать ссылку подписки", + "SKIP_BUTTON": "⏭️ Пропустить", + "STARS_PAYMENT_ENROLLMENT_ERROR": "❌ Произошла ошибка при зачислении средств. Обратитесь в поддержку, платеж будет проверен вручную.", + "STARS_PAYMENT_PROCESSING_ERROR": "❌ Техническая ошибка при обработке платежа. Обратитесь в поддержку для решения проблемы.", + "STARS_PAYMENT_SUCCESS": "🎉 Платеж успешно обработан!\n\n⭐ Потрачено звезд: {stars_spent}\n💰 Зачислено на баланс: {amount} ₽\n\n🆔 ID транзакции: {transaction_id}...\n\n⚠️ Важно: Пополнение баланса не активирует подписку автоматически. Обязательно активируйте подписку отдельно!\n\n🔄 При наличии сохранённой корзины подписки и включенной автопокупке, подписка будет приобретена автоматически после пополнения баланса.\n\nСпасибо за пополнение! 🚀", + "STARS_PAYMENT_USER_NOT_FOUND": "❌ Ошибка: пользователь не найден. Обратитесь в поддержку.", + "STARS_PRECHECK_INVALID_PAYLOAD": "Ошибка валидации платежа. Попробуйте еще раз.", + "STARS_PRECHECK_TECHNICAL_ERROR": "Техническая ошибка. Попробуйте позже.", + "STARS_PRECHECK_USER_NOT_FOUND": "Пользователь не найден. Обратитесь в поддержку.", + "SUBSCRIPTION_ACTIVE": "✅ Активна", + "SUBSCRIPTION_ACTIVE_REQUIRED": "⚠️ У вас нет активной подписки!", + "SUBSCRIPTION_ADDITIONAL_STEP_TITLE": "{title}:", + "SUBSCRIPTION_APPS_PROMPT": "Выберите приложение для подключения:", + "SUBSCRIPTION_APPS_TITLE": "📱 Приложения для {device_name}", + "SUBSCRIPTION_APP_NOT_FOUND": "❌ Приложение не найдено", + "SUBSCRIPTION_CONNECTED_DEVICES_FOOTER": "", + "SUBSCRIPTION_CONNECTED_DEVICES_TITLE": "
📱 Подключенные устройства:\n", + "SUBSCRIPTION_CONNECT_CUSTOM_MESSAGE": "🚀 Подключить подписку\n\n📱 Нажмите кнопку ниже, чтобы открыть приложение:", + "SUBSCRIPTION_CONNECT_DEVICE_MESSAGE": "📱 Подключить подписку\n\n🔗 Ссылка подписки:\n{subscription_url}\n\n💡 Выберите ваше устройство для получения подробной инструкции по настройке:", + "SUBSCRIPTION_CONNECT_DEVICE_MESSAGE_HIDDEN": "📱 Подключить подписку\n\nℹ️ Ссылка подписки доступна по кнопкам ниже или в разделе «Моя подписка».\n\n💡 Выберите ваше устройство для получения подробной инструкции по настройке:", + "SUBSCRIPTION_CONNECT_LINK_MESSAGE": "🚀 Подключить подписку\n\n🔗 Нажмите кнопку ниже, чтобы открыть ссылку подписки:", + "SUBSCRIPTION_CONNECT_LINK_PROMPT": "📱 Скопируйте ссылку и добавьте в ваше VPN приложение", + "SUBSCRIPTION_CONNECT_LINK_SECTION": "🔗 Ссылка для подключения:\n{subscription_url}", + "SUBSCRIPTION_CONNECT_MINIAPP_MESSAGE": "📱 Подключить подписку\n\n🚀 Нажмите кнопку ниже, чтобы открыть подписку в мини-приложении Telegram:", + "SUBSCRIPTION_DEVICE_APPS_NOT_FOUND": "❌ Приложения для этого устройства не найдены", + "SUBSCRIPTION_DEVICE_FEATURED_APP": "📋 Рекомендуемое приложение: {app_name}", + "SUBSCRIPTION_DEVICE_GUIDE_TITLE": "📱 Настройка для {device_name}", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP1": "1. Установите приложение по ссылке выше", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. Нажмите кнопку \"Подключиться\" ниже", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP3": "3. Откройте приложение и вставьте ссылку", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP4": "4. Подключитесь к серверу", + "SUBSCRIPTION_DEVICE_HOW_TO_TITLE": "💡 Как подключить:", + "SUBSCRIPTION_DEVICE_LINK_TITLE": "🔗 Ссылка подписки:", + "SUBSCRIPTION_DEVICE_OTHER_APPS": "📦 Другие приложения: {app_list}", + "SUBSCRIPTION_DEVICE_OTHER_APPS_HINT": "Нажмите кнопку \"Другие приложения\" ниже, чтобы выбрать приложение.", + "SUBSCRIPTION_DEVICE_STEP_ADD_TITLE": "Шаг 2 - Добавление подписки:", + "SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE": "Шаг 3 - Подключение:", + "SUBSCRIPTION_DEVICE_STEP_INSTALL_TITLE": "Шаг 1 - Установка:", + "SUBSCRIPTION_EXPIRED": "\n❌ Подписка истекла\n\nВаша подписка истекла. Для восстановления доступа продлите подписку.\n", + "SUBSCRIPTION_EXPIRED_1D": "⛔ Подписка закончилась\n\nДоступ был отключён {end_date}. Продлите подписку, чтобы вернуть полный доступ.\n\n💎 Стоимость продления: {price}", + "SUBSCRIPTION_EXPIRED_SECOND_WAVE": "🔥 Скидка {percent}% на продление\n\nАктивируйте предложение, чтобы получить дополнительную скидку. Она суммируется с вашей промогруппой и действует до {expires_at}.", + "SUBSCRIPTION_EXPIRED_THIRD_WAVE": "🎁 Индивидуальная скидка {percent}%\n\nПрошло {trigger_days} дней без подписки. Вернитесь и активируйте дополнительную скидку — она суммируется с промогруппой и действует до {expires_at}.", + "SUBSCRIPTION_EXPIRING": "\n⚠️ Подписка истекает!\n\nВаша подписка истекает через {days} дней.\n\nНе забудьте продлить подписку, чтобы не потерять доступ к серверам.\n", + "SUBSCRIPTION_EXPIRING_PAID": "\n⚠️ Подписка истекает через {days_text}!\n\nВаша платная подписка истекает {end_date}.\n\n💳 Автоплатеж: {autopay_status}\n\n{action_text}\n", + "SUBSCRIPTION_EXTEND": "💎 Продлить", + "SUBSCRIPTION_HAPP_CRYPTOLINK_BLOCK": "
{crypto_link}
", + "SUBSCRIPTION_HAPP_LINK_PROMPT": "🔒 Ссылка на подписку создана. Нажмите кнопку \"Подключиться\" ниже, чтобы открыть её в Happ.", + "SUBSCRIPTION_HAPP_OPEN_BUTTON_HINT": "▶️ Нажмите кнопку \"Подключиться\" ниже, чтобы открыть Happ и добавить подписку автоматически.", + "SUBSCRIPTION_HAPP_OPEN_HINT": "💡 Если ссылка не открывается автоматически, скопируйте её вручную:", + "SUBSCRIPTION_HAPP_OPEN_LINK": "🔓 Открыть ссылку в Happ", + "SUBSCRIPTION_HAPP_OPEN_TITLE": "🔗 Подключение через Happ", + "SUBSCRIPTION_IMPORT_INSTRUCTION_PROMPT": "📱 Нажмите кнопку ниже, чтобы получить инструкцию по настройке VPN на вашем устройстве", + "SUBSCRIPTION_IMPORT_LINK_SECTION": "🔗 Ваша ссылка для импорта в VPN приложение:\n{subscription_url}", + "SUBSCRIPTION_INFO": "\n📱 Информация о подписке\n\n📊 Статус: {status}\n🎭 Тип: {type}\n📅 Действует до: {end_date}\n⏰ Осталось дней: {days_left}\n\n📈 Трафик: {traffic_used} / {traffic_limit}\n🌍 Серверы: {countries_count} стран\n📱 Устройства: {devices_used} / {devices_limit}\n\n💳 Автоплатеж: {autopay_status}\n", + "SUBSCRIPTION_LINK_GENERATING_NOTICE": "{purchase_text}\n\nСсылка генерируется, перейдите в раздел 'Моя подписка' через несколько секунд.", + "SUBSCRIPTION_LINK_HIDDEN_NOTICE": "ℹ️ Ссылка подписки доступна по кнопкам ниже или в разделе «Моя подписка».", + "SUBSCRIPTION_LINK_HINT": "💡 Если ссылка не скопировалась, выделите её вручную и скопируйте.", + "SUBSCRIPTION_LINK_STEP1": "1. Нажмите на ссылку выше чтобы её скопировать", + "SUBSCRIPTION_LINK_STEP2": "2. Откройте ваше VPN приложение", + "SUBSCRIPTION_LINK_STEP3": "3. Найдите функцию \"Добавить подписку\" или \"Import\"", + "SUBSCRIPTION_LINK_STEP4": "4. Вставьте скопированную ссылку", + "SUBSCRIPTION_LINK_UNAVAILABLE": "❌ Ссылка подписки недоступна", + "SUBSCRIPTION_LINK_USAGE_TITLE": "📱 Как использовать:", + "SUBSCRIPTION_NONE": "❌ Нет активной подписки", + "SUBSCRIPTION_NOT_FOUND": "❌ Подписка не найдена", + "SUBSCRIPTION_NO_ACTIVE_LINK": "⚠ У вас нет активной подписки или ссылка еще генерируется", + "SUBSCRIPTION_NO_SERVERS": "Нет серверов", + "SUBSCRIPTION_OVERVIEW_TEMPLATE": "👤 {full_name}\n💰 Баланс: {balance}\n📱 Подписка: {status_emoji} {status_display}{warning}{tariff_info_block}\n\n📱 Информация о подписке\n🎭 Тип: {subscription_type}\n📅 Действует до: {end_date}\n⏰ Осталось: {time_left}\n📈 Трафик: {traffic}\n🌍 Серверы: {servers}\n📱 Устройства: {devices_used} / {device_limit}", + "SUBSCRIPTION_DAILY_OVERVIEW_TEMPLATE": "👤 {full_name}\n💰 Баланс: {balance}\n📱 Подписка: {status_emoji} {status_display}{warning}{tariff_info_block}\n\n📱 Информация о подписке\n🎭 Тип: {subscription_type}\n📈 Трафик: {traffic}\n🌍 Серверы: {servers}\n📱 Устройства: {devices_used} / {device_limit}", + "SUBSCRIPTION_PROMO_DISCOUNT_HINT": "⚡ Активирована доп. скидка {percent}%. \n\nСуммируется с другими скидками!", + "SUBSCRIPTION_PROMO_DISCOUNT_NOTE": "⚡ Доп. скидка {percent}%: -{amount}", + "SUBSCRIPTION_PROMO_DISCOUNT_TIMER": "⏳ Скидка действует ещё: {time_left}\n{bar}", + "SUBSCRIPTION_PURCHASED": "🎉 Подписка успешно приобретена!", + "SUBSCRIPTION_SETTINGS_BUTTON": "⚙️ Настройки", + "SUBSCRIPTION_SETTINGS_OVERVIEW": "⚙️ Настройки подписки\n\n📊 Текущие параметры:\n🌐 Стран: {countries_count}\n📈 Трафик: {traffic_used} / {traffic_limit}\n📱 Устройства: {devices_used} / {devices_limit}\n\nВыберите что хотите изменить:", + "SUBSCRIPTION_SETTINGS_PAID_ONLY": "⚠️ Настройки доступны только для платных подписок", + "SUBSCRIPTION_SPECIFIC_APP_TITLE": "📱 {app_name} - {device_name}", + "SUBSCRIPTION_STATUS_ACTIVE": "Активна", + "SUBSCRIPTION_STATUS_EXPIRED": "Истекла", + "SUBSCRIPTION_STATUS_TRIAL": "Тестовая", + "SUBSCRIPTION_STATUS_UNKNOWN": "Неизвестно", + "SUBSCRIPTION_SUMMARY": "\n📋 Итоговая конфигурация\n\n📅 Период: {period} дней\n📈 Трафик: {traffic}\n🌍 Страны: {countries}\n📱 Устройства: {devices}\n\n💰 Итого к оплате: {total_price}\n\nПодтвердить покупку?\n", + "SUBSCRIPTION_SUMMARY_PROMO_DISCOUNT": "- Промо-предложение: -{amount} ({percent}% дополнительно)", + "SUBSCRIPTION_TIME_LEFT_DAYS": "{days} дн.", + "SUBSCRIPTION_TIME_LEFT_EXPIRED": "истёк", + "SUBSCRIPTION_TIME_LEFT_HOURS": "{hours} ч.", + "SUBSCRIPTION_TIME_LEFT_MINUTES": "{minutes} мин.", + "SUBSCRIPTION_TRAFFIC_LIMITED": "{used} / {limit} ГБ", + "SUBSCRIPTION_TRAFFIC_UNLIMITED": "∞ (безлимит) | Использовано: {used} ГБ", + "SUBSCRIPTION_TRIAL": "🧪 Тестовая подписка", + "SUBSCRIPTION_TYPE_PAID": "Платная", + "SUBSCRIPTION_TYPE_TRIAL": "Триал", + "SUBSCRIPTION_WARNING_MINUTES": "\n🔴 истекает через несколько минут!", + "SUBSCRIPTION_WARNING_TODAY": "\n⚠️ истекает сегодня!", + "SUBSCRIPTION_WARNING_TOMORROW": "\n⚠️ истекает завтра!", + "SUB_STATUS_ACTIVE_FEW_DAYS": "💎 Активна\n⚠️ истекает через {days} дн.", + "SUB_STATUS_ACTIVE_LONG": "💎 Активна\n📅 до {end_date} ({days} дн.)", + "SUB_STATUS_ACTIVE_TODAY": "💎 Активна\n⚠️ истекает сегодня!", + "SUB_STATUS_ACTIVE_TOMORROW": "💎 Активна\n⚠️ истекает завтра!", + "SUB_STATUS_DAILY_ACTIVE": "💎 Активна", + "SUB_STATUS_EXPIRED": "🔴 Истекла\n📅 {end_date}", + "SUB_STATUS_DISABLED": "⚫ Отключена", + "SUB_STATUS_PENDING": "⏳ Ожидает активации", + "SUB_STATUS_NONE": "❌ Отсутствует", + "SUB_STATUS_TRIAL_ACTIVE": "🎁 Тестовая подписка\n📅 до {end_date} ({days} дн.)", + "SUB_STATUS_TRIAL_TODAY": "🎁 Тестовая подписка\n⚠️ истекает сегодня!", + "SUB_STATUS_TRIAL_TOMORROW": "🎁 Тестовая подписка\n⚠️ истекает завтра!", + "SUCCESS": "✅ Успешно", + "SUPPORT_BUTTON": "🆘 Поддержка", + "SUPPORT_INFO": "\n🛠️ Техническая поддержка\n\nПо всем вопросам обращайтесь к нашей поддержке:\n\n👤 {settings.SUPPORT_USERNAME}\n\nМы поможем с:\n• Настройкой подключения\n• Решением технических проблем \n• Вопросами по оплате\n• Другими вопросами\n\n⏰ Время ответа: обычно в течение 1-2 часов\n", + "SUSPICIOUS_DISPLAY_NAME_BLOCKED": "🚫 Мы обнаружили, что ваше отображаемое имя похоже на ссылку или служебный аккаунт. Пожалуйста, измените имя в профиле Telegram и повторите попытку.", + "SWITCH_TRAFFIC_BUTTON": "🔄 Переключить трафик", + "SWITCH_TRAFFIC_CONFIRM": "\n🔄 Подтверждение переключения трафика\n\nТекущий лимит: {current_traffic}\nНовый лимит: {new_traffic}\n\nДействие: {action}\n💰 {cost}\n\nПодтвердить переключение?\n", + "SWITCH_TRAFFIC_INFO": "\n🔄 Переключение лимита трафика\n\nТекущий лимит: {current_traffic}\nВыберите новый лимит трафика:\n\n💡 Важно:\n• При увеличении - доплата за разницу пропорционально оставшемуся времени\n• При уменьшении - возврат средств не производится\n• Счетчик использованного трафика НЕ сбрасывается\n", + "SWITCH_TRAFFIC_SUCCESS_DECREASE": "\n✅ Лимит трафика уменьшен!\n\n📊 Было: {old_traffic} → Стало: {new_traffic}\nℹ️ Возврат средств не производится\n", + "SWITCH_TRAFFIC_SUCCESS_INCREASE": "\n✅ Лимит трафика увеличен!\n\n📊 Было: {old_traffic} → Стало: {new_traffic}\n💰 Списано: {amount}\n", + "SWITCH_TRAFFIC_TITLE": "🔄 Переключение лимита трафика", + "TEST_ACCESS_ACTIVATED_MESSAGE": "🎉 Тестовые сервера подключены! Доступ активен до {expires_at}.", + "TEST_ACCESS_ACTIVATED_POPUP": "✅ Доступ выдан!", + "TEST_ACCESS_ALREADY_CONNECTED": "ℹ️ Этот сервер уже подключен к вашей подписке.", + "TEST_ACCESS_NO_SQUADS": "❌ Не удалось определить список серверов для теста. Обратитесь к администратору.", + "TEST_ACCESS_NO_SUBSCRIPTION": "❌ Для активации предложения необходима действующая подписка.", + "TEST_ACCESS_REMNAWAVE_ERROR": "❌ Не удалось подключить серверы. Попробуйте позже или обратитесь в поддержку.", + "TEST_ACCESS_UNKNOWN_ERROR": "❌ Не удалось активировать предложение. Попробуйте позже.", + "TICKET_ALREADY_OPEN": "У вас уже есть незакрытый тикет. Сначала закройте его.", + "TICKET_ATTACHMENTS": "📎 Вложения", + "TICKET_CLOSED": "✅ Тикет закрыт.", + "TICKET_CLOSED_NO_REPLY": "❌ Тикет закрыт, ответить невозможно.", + "TICKET_CLOSE_ERROR": "❌ Ошибка при закрытии тикета.", + "TICKET_CREATED_SUCCESS": "✅ Тикет #{ticket_id} успешно создан!\n\nЗаголовок: {title}\n\nМы ответим вам в ближайшее время.", + "TICKET_CREATE_ERROR": "❌ Произошла ошибка при создании тикета. Попробуйте позже.", + "TICKET_CREATION_CANCELLED": "Создание тикета отменено.", + "TICKET_CREATION_ERROR": "❌ Произошла ошибка при создании тикета. Попробуйте позже.", + "TICKET_MARKED_ANSWERED": "✅ Тикет отмечен как отвеченный.", + "TICKET_MESSAGE_INPUT": "Опишите проблему (до 500 символов) или отправьте фото c подписью:", + "TICKET_MESSAGE_TOO_SHORT": "Сообщение должно содержать минимум 10 символов. Попробуйте еще раз:", + "TICKET_NOT_FOUND": "Тикет не найден.", + "TICKET_PRIORITY_HIGH": "🟠 Высокий", + "TICKET_PRIORITY_LOW": "🟢 Низкий", + "TICKET_PRIORITY_NORMAL": "🟡 Обычный", + "TICKET_PRIORITY_SELECT": "Выберите приоритет тикета:", + "TICKET_PRIORITY_URGENT": "🔴 Срочный", + "TICKET_REPLY_CANCELLED": "Ответ отменен.", + "TICKET_REPLY_ERROR": "❌ Произошла ошибка при отправке ответа. Попробуйте позже.", + "TICKET_REPLY_INPUT": "Введите ваш ответ:", + "TICKET_REPLY_NOTIFICATION": "🎫 Получен ответ по тикету #{ticket_id}\n\n{reply_preview}\n\nНажмите кнопку ниже, чтобы перейти к тикету:", + "TICKET_REPLY_SENT": "✅ Ваш ответ отправлен!", + "TICKET_REPLY_TOO_SHORT": "Ответ должен содержать минимум 5 символов. Попробуйте еще раз:", + "TICKET_STATUS_ANSWERED": "Отвечен", + "TICKET_STATUS_CLOSED": "Закрыт", + "TICKET_STATUS_OPEN": "Открыт", + "TICKET_STATUS_PENDING": "В ожидании", + "TICKET_TITLE_INPUT": "Введите заголовок тикета:", + "TICKET_TITLE_TOO_LONG": "Заголовок слишком длинный. Максимум 255 символов. Попробуйте еще раз:", + "TICKET_TITLE_TOO_SHORT": "Заголовок должен содержать минимум 5 символов. Попробуйте еще раз:", + "TICKET_UPDATE_ERROR": "❌ Ошибка при обновлении тикета.", + "TOPUP_BALANCE_BUTTON": "💳 Пополнить баланс", + "TOP_UP_AMOUNT": "💳 Введите сумму для пополнения (в рублях):", + "TOP_UP_METHODS": "\n💳 Выберите способ оплаты\n\nСумма: {amount}\n", + "TOP_UP_STARS": "⭐ Telegram Stars", + "TOP_UP_TRIBUTE": "💎 Банковская карта", + "TRAFFIC_100GB": "📊 100 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_100GB)}", + "TRAFFIC_10GB": "📊 10 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_10GB)}", + "TRAFFIC_250GB": "📊 250 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_250GB)}", + "TRAFFIC_25GB": "📊 25 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_25GB)}", + "TRAFFIC_50GB": "📊 50 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_50GB)}", + "TRAFFIC_5GB": "📊 5 ГБ - {settings.format_price(settings.PRICE_TRAFFIC_5GB)}", + "TRAFFIC_ALREADY_UNLIMITED": "⚠ У вас уже безлимитный трафик", + "TRAFFIC_FIXED_MODE": "⚠️ В текущем режиме трафик фиксированный и не может быть изменен", + "TRAFFIC_TOPUP_DISABLED": "⚠️ Функция докупки трафика отключена", + "TRAFFIC_INSUFFICIENT_BALANCE": "⚠️ Недостаточно средств!\nТребуется: {required} (за {months} мес)\nУ вас: {balance}", + "TRAFFIC_NO_CHANGE": "ℹ️ Лимит трафика не изменился", + "TRAFFIC_PACKAGES_NOT_CONFIGURED": "⚠️ Пакеты трафика не настроены", + "TRAFFIC_UNLIMITED": "📊 Безлимит - {settings.format_price(settings.PRICE_TRAFFIC_UNLIMITED)}", + "TRAFFIC_UNLIMITED_SHORT": "Безлимит", + "TRIAL_ACTIVATED": "🎉 Тестовая подписка активирована!", + "TRIAL_ACTIVATE_BUTTON": "🎁 Активировать", + "TRIAL_ALREADY_USED": "❌ Тестовая подписка уже была использована", + "TRIAL_AVAILABLE": "\n🎁 Тестовая подписка\n\nВы можете получить тестовую подписку{price_line}:\n\n⏰ Период: {days} дней\n📈 Трафик: {traffic}{devices_line}\n🌍 Сервер: {server_name}\n\nАктивировать тестовую подписку?\n", + "TRIAL_AVAILABLE_DEVICES_LINE": "\n📱 Устройства: {devices} шт.", + "TRIAL_PAYMENT_PRICE_LINE": "\n💳 Стоимость активации: {price}", + "TRIAL_PAYMENT_INSUFFICIENT_FUNDS": "⚠️ Недостаточно средств для активации триала.\nНеобходимо: {required}\nНа балансе: {balance}\nНе хватает: {missing}\n\nПополните баланс и попробуйте снова.", + "TRIAL_PAYMENT_FAILED": "Не удалось списать средства для активации триала. Попробуйте позже.", + "TRIAL_PROVISIONING_FAILED": "Не удалось завершить активацию триала. Средства возвращены на баланс. Попробуйте позже.", + "TRIAL_ROLLBACK_FAILED": "Не удалось отменить активацию триала после ошибки списания. Свяжитесь с поддержкой и попробуйте позже.", + "TRIAL_REFUND_FAILED": "Не удалось вернуть оплату за активацию триала. Немедленно свяжитесь с поддержкой.", + "TRIAL_PAYMENT_CHARGED_NOTE": "💳 С вашего баланса списано {amount}.", + "TRIAL_CHANNEL_UNSUBSCRIBED": "\n🚫 Доступ приостановлен\n\nМы не нашли вашу подписку на наш канал, поэтому тестовая подписка отключена.\n\nПодпишитесь на канал и нажмите «{check_button}», чтобы вернуть доступ.", + "TRIAL_ENDING_SOON": "\n🎁 Тестовая подписка скоро закончится!\n\nВаша тестовая подписка истекает через несколько часов.\n\n💎 Не хотите остаться без VPN?\nПереходите на полную подписку!\n\n🔥 Специальное предложение:\n• 30 дней всего за {price}\n• Безлимитный трафик \n• Все серверы доступны\n• Скорость до 1ГБит/сек\n\n⚡️ Успейте оформить до окончания тестового периода!\n", + "TRIAL_INACTIVE_1H": "⏳ Прошёл час, а подключение не выполнено\n\nЕсли возникли сложности — откройте инструкцию и следуйте шагам. Мы всегда готовы помочь!", + "TRIAL_INACTIVE_24H": "⏳ Прошли сутки с начала теста\n\nМы не видим трафика по вашей подписке. Загляните в инструкцию или напишите в поддержку — поможем подключиться!", + "TRIAL_SERVER_DEFAULT_NAME": "🎯 Тестовый сервер", + "TRIAL_SERVER_RANDOM_POOL": "🎲 Случайный из {count} серверов", + "PAID_TRIAL_HEADER": "⚡ Пробная подписка", + "PAID_TRIAL_SELECT_PAYMENT": "Выберите подходящий способ оплаты:", + "PAID_TRIAL_CAN_PAY_BALANCE": "Вы можете оплатить пробную подписку с баланса или выбрать другой способ оплаты.", + "PAID_TRIAL_PAYMENT_DESC": "Пробная подписка на {days} дней", + "PAID_TRIAL_INVOICE_TITLE": "Пробная подписка на {days} дней", + "PAID_TRIAL_STARS_LABEL": "Пробная подписка", + "PAID_TRIAL_STARS_WAITING": "⭐ Для оплаты пробной подписки нажмите кнопку оплаты в сообщении выше.\n\nПосле успешной оплаты подписка будет активирована автоматически.", + "PAID_TRIAL_YOOKASSA_SBP": "🏦 Оплата через СБП\n\nОтсканируйте QR-код или перейдите по ссылке для оплаты.\n\n💰 Сумма: {amount}", + "PAID_TRIAL_YOOKASSA_CARD": "💳 Оплата картой\n\nНажмите кнопку ниже для перехода к оплате.\n\n💰 Сумма: {amount}", + "PAID_TRIAL_CRYPTOBOT": "🪙 Оплата через CryptoBot\n\nНажмите кнопку ниже для перехода к оплате.\n\n💰 Сумма: {amount}", + "PAID_TRIAL_HELEKET": "🪙 Оплата через Heleket\n\nНажмите кнопку ниже для перехода к оплате.\n\n💰 Сумма: {amount}", + "PAID_TRIAL_MULENPAY": "💳 Оплата через {name}\n\nНажмите кнопку ниже для перехода к оплате.\n\n💰 Сумма: {amount}", + "PAID_TRIAL_PAL24": "💳 Оплата через PayPalych\n\nНажмите кнопку ниже для перехода к оплате.\n\n💰 Сумма: {amount}", + "PAID_TRIAL_WATA": "💳 Оплата через WATA\n\nНажмите кнопку ниже для перехода к оплате.\n\n💰 Сумма: {amount}", + "PAID_TRIAL_PAY_BALANCE": "💳 Оплатить с баланса", + "PAID_TRIAL_BALANCE_SUCCESS": "✅ Пробная подписка успешно оплачена!\n\nАктивация выполняется...", + "PERIOD": "Период", + "TRAFFIC": "Трафик", + "DEVICES": "Устройства", + "PRICE": "Стоимость", + "YOUR_BALANCE": "Ваш баланс", + "UNBLOCK": "✅ Разблокировать", + "UNKNOWN_CALLBACK_ALERT": "❓ Неизвестная команда. Попробуйте ещё раз.", + "UNKNOWN_COMMAND_MESSAGE": "❓ Не понимаю эту команду. Используйте кнопки меню.", + "USER_BLOCKED_FOREVER": "Вы заблокированы для обращений в поддержку.", + "USER_BLOCKED_UNTIL": "Вы заблокированы до {time}", + "USER_NOT_FOUND": "❌ Пользователь не найден", + "VIEW_CLOSED_TICKETS": "🟢 Закрытые тикеты", + "VIEW_TICKET": "👁️ Посмотреть тикет", + "WATA_AMOUNT_TOO_HIGH": "Максимальная сумма пополнения: {amount}", + "WATA_AMOUNT_TOO_LOW": "Минимальная сумма пополнения: {amount}", + "WATA_PAYMENT_ERROR": "❌ Ошибка создания платежа WATA. Попробуйте позже или обратитесь в поддержку.", + "WATA_PAYMENT_INSTRUCTIONS": "💳 Оплата через WATA\n\n💰 Сумма: {amount}\n🆔 ID платежа: {payment_id}\n\n📱 Инструкция:\n1. Нажмите кнопку 'Оплатить через WATA'\n2. Следуйте подсказкам платежной системы\n3. Подтвердите перевод\n4. Средства зачислятся автоматически\n\n❓ Если возникнут проблемы, обратитесь в {support}", + "WATA_PAY_BUTTON": "💳 Оплатить через WATA", + "WATA_STATUS_CLOSED": "Обрабатывается", + "WATA_STATUS_DECLINED": "Отклонен", + "WATA_STATUS_OPENED": "Ожидает оплаты", + "WATA_STATUS_PAID": "Оплачен", + "WATA_STATUS_TITLE": "💳 Статус платежа WATA", + "WATA_STATUS_UNKNOWN": "Неизвестно", + "WATA_TOPUP_PROMPT": "💳 Оплата через WATA\n\nВведите сумму пополнения. Минимальная сумма — {min_amount}, максимальная — {max_amount}.\nОплата происходит через защищенную форму WATA.", + "WELCOME": "\n🎉 Добро пожаловать в VPN сервис!\n\nНаш сервис предоставляет быстрый и безопасный доступ к интернету без ограничений.\n\n🔐 Преимущества:\n• Высокая скорость подключения\n• Серверы в разных странах\n• Надежная защита данных\n• Круглосуточная поддержка\n\nДля начала работы выберите язык интерфейса:\n", + "WELCOME_FALLBACK": "Добро пожаловать, {user_name}!", + "YES": "✅ Да", + "SIMPLE_SUBSCRIPTION_TRIAL_NOTICE_ACTIVE": "ℹ️ У вас уже есть активная триальная подписка. Она будет действовать ещё {days} дн. После покупки к сроку добавится оплаченный период.", + "SIMPLE_SUBSCRIPTION_TRIAL_NOTICE_TRIAL": "ℹ️ У вас сейчас триальная подписка. Она истекает через {days} дн. Покупка новой продлит срок автоматически.", + "SIMPLE_SUBSCRIPTION_SERVER_ANY": "Любой доступный", + "SIMPLE_SUBSCRIPTION_SERVER_SELECTED": "Выбранный", + "SIMPLE_SUBSCRIPTION_SERVER_ASSIGNED": "Назначен автоматически", + "MENU_SIMPLE_SUBSCRIPTION": "⚡ Простая покупка", + "ADMIN_COMMUNICATIONS_POLLS": "🗳️ Опросы", + "ADMIN_POLLS_CREATE": "➕ Создать опрос", + "ADMIN_POLLS_REWARD_ENABLED": "Награда: {amount}", + "ADMIN_POLLS_REWARD_DISABLED": "Награда отключена", + "ADMIN_POLLS_SEND": "📤 Отправить", + "ADMIN_POLLS_STATS": "📊 Статистика", + "ADMIN_POLLS_DELETE": "🗑️ Удалить", + "ADMIN_POLLS_BACK": "⬅️ К списку", + "ADMIN_POLLS_CUSTOM_TARGET": "⚙️ По критериям", + "ADMIN_POLLS_SEND_CONFIRM_BUTTON": "✅ Отправить", + "ADMIN_POLLS_LIST_TITLE": "🗳️ Опросы", + "ADMIN_POLLS_LIST_EMPTY": "Опросов пока нет.", + "ADMIN_POLLS_QUESTIONS_COUNT": "Вопросов: {count}", + "ADMIN_POLLS_CREATION_TITLE_PROMPT": "🗳️ Создание опроса\n\nВведите заголовок опроса:", + "ADMIN_POLLS_CREATION_CANCELLED": "❌ Создание опроса отменено.", + "ADMIN_POLLS_CREATION_DESCRIPTION_PROMPT": "Введите описание опроса. HTML разрешён.\nОтправьте /skip, чтобы пропустить.", + "ADMIN_POLLS_CREATION_DESCRIPTION_SKIPPED": "Описание пропущено.", + "ADMIN_POLLS_CREATION_INVALID_HTML": "❌ Ошибка в HTML: {error}", + "ADMIN_POLLS_CREATION_REWARD_PROMPT": "Введите сумму награды в рублях. Отправьте 0 чтобы отключить награду.", + "ADMIN_POLLS_CREATION_REWARD_INVALID": "❌ Некорректная сумма. Попробуйте ещё раз.", + "ADMIN_POLLS_CREATION_QUESTION_PROMPT": "Введите вопрос и варианты ответов.\nКаждая строка — отдельный вариант.\nПервая строка — текст вопроса.\nОтправьте /done, когда вопросы будут добавлены.", + "ADMIN_POLLS_CREATION_NEEDS_QUESTION": "❌ Добавьте хотя бы один вопрос.", + "ADMIN_POLLS_CREATION_FINISHED": "✅ Опрос «{title}» создан. Вопросов: {count}. {reward}", + "ADMIN_POLLS_CREATION_MIN_OPTIONS": "❌ Нужен вопрос и минимум два варианта ответа.", + "ADMIN_POLLS_CREATION_ADDED_QUESTION": "Вопрос добавлен: «{question}». Добавьте следующий вопрос или отправьте /done.", + "ADMIN_POLLS_QUESTION_LIST_HEADER": "Вопросы:", + "ADMIN_POLLS_OPTION_BULLET": " • {option}", + "ADMIN_POLLS_SEND_CHOOSE_TARGET": "🎯 Выберите аудиторию для отправки опроса:", + "ADMIN_POLLS_CUSTOM_PROMPT": "Выберите дополнительный критерий аудитории:", + "ADMIN_POLLS_SEND_CONFIRM": "📤 Отправить опрос «{title}» аудитории «{audience}»? Пользователей: {count}", + "ADMIN_POLLS_SENDING": "📤 Запускаю отправку опроса...", + "ADMIN_POLLS_SEND_RESULT": "📤 Отправка завершена\nУспешно: {sent}\nОшибок: {failed}\nПропущено: {skipped}\nВсего: {total}", + "ADMIN_POLLS_STATS_HEADER": "📊 Статистика опроса", + "ADMIN_POLLS_STATS_OVERVIEW": "Всего приглашено: {total}\nЗавершили: {completed}\nВыплачено наград: {reward}", + "ADMIN_POLLS_STATS_OPTION_LINE": "• {option}: {count}", + "ADMIN_POLLS_CONFIRM_DELETE": "Вы уверены, что хотите удалить опрос «{title}»?", + "ADMIN_POLLS_DELETED": "🗑️ Опрос удалён.", + "POLL_INVITATION_REWARD": "🎁 За участие вы получите {amount}.", + "POLL_INVITATION_START": "Нажмите кнопку ниже, чтобы пройти опрос.", + "POLL_START_BUTTON": "📝 Пройти опрос", + "POLL_QUESTION_HEADER": "Вопрос {current}/{total}", + "POLL_ALREADY_COMPLETED": "Вы уже прошли этот опрос.", + "POLL_EMPTY": "Опрос пока недоступен.", + "POLL_ERROR": "Не удалось обработать опрос. Попробуйте позже.", + "POLL_COMPLETED": "🙏 Спасибо за участие в опросе!", + "POLL_REWARD_GRANTED": "Награда {amount} зачислена на ваш баланс.", + "ADMIN_USERS_BULK_BAN": "🛑 Массовый бан", + "ADMIN_USERS_BLACKLIST": "🔐 Черный список", + "ADMIN_USERS_BLOCKED_CHECK": "🔒 Заблокировавшие бота", + "CONTEST_START_ANNOUNCEMENT": "Стартует игра", + "CONTEST_PRIZE": "Приз", + "DAYS": "дн. подписки", + "CONTEST_WINNERS": "Победителей", + "CONTEST_ATTEMPTS": "Попыток/польз", + "CONTEST_ELIGIBILITY": "Участвовать могут только с активной или триальной подпиской", + "REMINDER": "Напоминание", + "CONTEST_REMINDER_TEXT": "Не забудьте участвовать в конкурсах для получения бонусов", + "MODEM_BUTTON": "📡 Модем", + "MODEM_ENABLE_BUTTON": "✅ Подключить модем", + "MODEM_DISABLE_BUTTON": "❌ Отключить модем", + "MODEM_CONFIRM_BUTTON": "✅ Подтвердить подключение", + "MODEM_STATUS_ENABLED": "✅ Подключен", + "MODEM_STATUS_DISABLED": "❌ Не подключен", + "MODEM_PAID_ONLY": "⚠️ Модем доступен только для платных подписок", + "MODEM_DISABLED": "⚠️ Функция модема отключена", + "MODEM_ALREADY_ENABLED": "ℹ️ Модем уже подключен", + "MODEM_NOT_ENABLED": "ℹ️ Модем не подключен", + "MODEM_INFO_ENABLED": "📡 Модем\n\nСтатус: {status}\n\nМодем подключен к вашей подписке.\nЕжемесячная плата: {price}\n\nПри отключении модема возврат средств не производится.", + "MODEM_INFO_DISABLED": "📡 Модем\n\nСтатус: {status}\n\nПодключите модем к вашей подписке.\nЕжемесячная плата: {price}\n\nПри подключении модема будет добавлено дополнительное устройство.", + "MODEM_INSUFFICIENT_FUNDS": "⚠️ Недостаточно средств\n\nСтоимость подключения модема: {required}\nНа балансе: {balance}\nНе хватает: {missing}\n\nВыберите способ пополнения.", + "MODEM_CONFIRM_ENABLE": "📡 Подтверждение подключения модема\n\nСтоимость: {price} (за {months} мес)\n\nПри подключении модема:\n• К подписке добавится дополнительное устройство\n• Ежемесячная плата увеличится на {monthly_price}\n\nПодтвердить подключение?", + "MODEM_ENABLED_SUCCESS": "✅ Модем успешно подключен!\n\n📡 Модем активирован\n📱 Добавлено устройство для модема\n", + "MODEM_CHARGED": "💰 Списано: {amount}", + "MODEM_DISABLED_SUCCESS": "✅ Модем отключен\n\n📡 Модем деактивирован\nℹ️ Возврат средств не производится", + "MODEM_PERIOD_INFO": "\n📅 Модем действует до: {end_date} ({days} дн.)", + "MODEM_SHORT_PERIOD_WARNING": "\n⚠️ Внимание! До окончания подписки осталось всего {days} дн.\nПосле продления подписки модем нужно будет оплатить заново!", + "MODEM_PERIOD_NOTE": "\nℹ️ До окончания подписки: {days} дн.\nПосле продления модем нужно будет оплатить заново.", + "MODEM_PRICE_WITH_DISCOUNT": "Стоимость: {base_price} {final_price} (за {months} мес)\n🎁 Скидка {discount}%: -{discount_amount}", + "MODEM_PRICE_NO_DISCOUNT": "Стоимость: {price} (за {months} мес)", + "MODEM_CONFIRM_ENABLE_BASE": "📡 Подтверждение подключения модема\n\n{price_text}\n\nПри подключении модема:\n• К подписке добавится дополнительное устройство\n• Ежемесячная плата увеличится на {monthly_price}\n\nПодтвердить подключение?", + + "ADMIN_USER_RESTRICTIONS": "⚠️ Ограничить", + "USER_RESTRICTION_TOPUP_BLOCKED": "🚫 Пополнение ограничено\n\n{reason}\n\nЕсли вы считаете это ошибкой, вы можете обжаловать решение.", + "USER_RESTRICTION_SUBSCRIPTION_BLOCKED": "🚫 Покупка/продление подписки ограничено\n\n{reason}\n\nЕсли вы считаете это ошибкой, вы можете обжаловать решение.", + "USER_RESTRICTION_APPEAL_BUTTON": "🆘 Обжаловать", + + "PAUSE_DAILY_BUTTON": "⏸️ Приостановить подписку", + "RESUME_DAILY_BUTTON": "▶️ Возобновить подписку", + "DAILY_SWITCH_WARNING": "⚠️ Внимание! У вас осталось {days} дн. подписки.\nПри смене на суточный тариф они будут утеряны!", + "DAILY_SUBSCRIPTION_PAUSED": "⏸️ Подписка приостановлена", + "DAILY_SUBSCRIPTION_RESUMED": "▶️ Подписка возобновлена!" +} diff --git a/app/localization/texts.py b/app/localization/texts.py index eeacd4ad..61e96cc1 100644 --- a/app/localization/texts.py +++ b/app/localization/texts.py @@ -35,6 +35,18 @@ _DYNAMIC_LANGUAGE_CONFIGS = { 'Старайтесь использовать тикеты — так мы быстрее поможем и ничего не потеряется.\n' ), }, + 'fa': { + 'traffic_pattern': '📊 {size} گیگابایت - {price}', + 'unlimited_pattern': '📊 نامحدود - {price}', + 'support_info': ( + '\n🛟 پشتیبانی\n\n' + 'برای هرگونه سؤال به پشتیبانی پیام دهید:\n\n' + '👤 {support_username}\n\n' + '• 🎫 ایجاد تیکت\n' + '• 📋 تیکت‌های من\n' + '• 💬 تماس مستقیم\n' + ), + }, 'en': { 'traffic_pattern': '📊 {size} GB - {price}', 'unlimited_pattern': '📊 Unlimited - {price}', diff --git a/app/utils/formatters.py b/app/utils/formatters.py index 3ee01038..664b1c42 100644 --- a/app/utils/formatters.py +++ b/app/utils/formatters.py @@ -87,7 +87,8 @@ def format_time_ago(dt: datetime | str, language: str = 'ru') -> str: def format_days_declension(days: int, language: str = 'ru') -> str: - if language != 'ru': + language_code = (language or 'ru').split('-')[0].lower() + if language_code not in {'ru', 'fa'}: return f'{days} day{"s" if days != 1 else ""}' if days % 10 == 1 and days % 100 != 11: @@ -180,42 +181,49 @@ def format_subscription_status(is_active: bool, is_trial: bool, end_date: dateti except (ValueError, AttributeError): end_date = datetime.now() + language_code = (language or 'ru').split('-')[0].lower() + use_russian_fallback = language_code in {'ru', 'fa'} + if not is_active: - return '❌ Неактивна' if language == 'ru' else '❌ Inactive' + return '❌ Неактивна' if use_russian_fallback else '❌ Inactive' if is_trial: - status = '🎁 Тестовая' if language == 'ru' else '🎁 Trial' + status = '🎁 Тестовая' if use_russian_fallback else '🎁 Trial' else: - status = '✅ Активна' if language == 'ru' else '✅ Active' + status = '✅ Активна' if use_russian_fallback else '✅ Active' now = datetime.utcnow() if end_date > now: days_left = (end_date - now).days if days_left > 0: - status += f' ({days_left} дн.)' if language == 'ru' else f' ({days_left} days)' + status += f' ({days_left} дн.)' if use_russian_fallback else f' ({days_left} days)' else: hours_left = (end_date - now).seconds // 3600 - status += f' ({hours_left} ч.)' if language == 'ru' else f' ({hours_left} hrs)' + status += f' ({hours_left} ч.)' if use_russian_fallback else f' ({hours_left} hrs)' else: - status = '⏰ Истекла' if language == 'ru' else '⏰ Expired' + status = '⏰ Истекла' if use_russian_fallback else '⏰ Expired' return status def format_traffic_usage(used_gb: float, limit_gb: int, language: str = 'ru') -> str: + language_code = (language or 'ru').split('-')[0].lower() + use_russian_fallback = language_code in {'ru', 'fa'} + if limit_gb == 0: - if language == 'ru': + if use_russian_fallback: return f'{used_gb:.1f} ГБ / ∞' return f'{used_gb:.1f} GB / ∞' percentage = (used_gb / limit_gb) * 100 if limit_gb > 0 else 0 - if language == 'ru': + if use_russian_fallback: return f'{used_gb:.1f} ГБ / {limit_gb} ГБ ({percentage:.1f}%)' return f'{used_gb:.1f} GB / {limit_gb} GB ({percentage:.1f}%)' def format_boolean(value: bool, language: str = 'ru') -> str: - if language == 'ru': + language_code = (language or 'ru').split('-')[0].lower() + if language_code in {'ru', 'fa'}: return '✅ Да' if value else '❌ Нет' return '✅ Yes' if value else '❌ No' diff --git a/app/utils/pricing_utils.py b/app/utils/pricing_utils.py index 93099882..5993f4bd 100644 --- a/app/utils/pricing_utils.py +++ b/app/utils/pricing_utils.py @@ -307,7 +307,8 @@ def _pluralize_days_ru(n: int) -> str: def format_period_description(days: int, language: str = 'ru') -> str: - if language == 'ru': + language_code = (language or 'ru').split('-')[0].lower() + if language_code in {'ru', 'fa'}: if days == 30: return '1 месяц' if days == 60: diff --git a/app/webapi/routes/miniapp.py b/app/webapi/routes/miniapp.py index 7e44a304..d1e3f0e5 100644 --- a/app/webapi/routes/miniapp.py +++ b/app/webapi/routes/miniapp.py @@ -4054,7 +4054,7 @@ async def activate_subscription_trial_endpoint( language_code = _normalize_language_code(user) charged_amount_label = settings.format_price(charged_amount) if charged_amount > 0 else None - if language_code == 'ru': + if language_code in {'ru', 'fa'}: if duration_days: message = f'Триал активирован на {duration_days} дн. Приятного пользования!' else: @@ -4065,7 +4065,7 @@ async def activate_subscription_trial_endpoint( message = 'Trial activated successfully. Enjoy!' if charged_amount_label: - if language_code == 'ru': + if language_code in {'ru', 'fa'}: message = f'{message}\n\n💳 С вашего баланса списано {charged_amount_label}.' else: message = f'{message}\n\n💳 {charged_amount_label} has been deducted from your balance.' @@ -4476,7 +4476,7 @@ def _normalize_language_code(user: User | None) -> str: def _build_renewal_status_message(user: User | None) -> str: language_code = _normalize_language_code(user) - if language_code == 'ru': + if language_code in {'ru', 'fa'}: return 'Стоимость указана с учётом ваших текущих серверов, трафика и устройств.' return 'Prices already include your current servers, traffic, and devices.' @@ -4493,7 +4493,7 @@ def _build_promo_offer_payload(user: User | None) -> dict[str, Any] | None: payload['expires_at'] = expires_at language_code = _normalize_language_code(user) - if language_code == 'ru': + if language_code in {'ru', 'fa'}: payload['message'] = 'Дополнительная скидка применяется автоматически.' else: payload['message'] = 'Extra discount is applied automatically.' @@ -4527,7 +4527,7 @@ def _build_renewal_success_message( amount_label = settings.format_price(max(0, charged_amount)) date_label = format_local_datetime(subscription.end_date, '%d.%m.%Y %H:%M') if subscription.end_date else '' - if language_code == 'ru': + if language_code in {'ru', 'fa'}: if charged_amount > 0: message = ( f'Подписка продлена до {date_label}. ' if date_label else 'Подписка продлена. ' @@ -4543,7 +4543,7 @@ def _build_renewal_success_message( if promo_discount_value > 0: discount_label = settings.format_price(promo_discount_value) - if language_code == 'ru': + if language_code in {'ru', 'fa'}: message += f' Применена дополнительная скидка {discount_label}.' else: message += f' Promo discount applied: {discount_label}.' @@ -4560,7 +4560,7 @@ def _build_renewal_pending_message( amount_label = settings.format_price(max(0, missing_amount)) method_title = _format_payment_method_title(method) - if language_code == 'ru': + if language_code in {'ru', 'fa'}: if method_title: return ( f'Недостаточно средств на балансе. Доплатите {amount_label} через {method_title}, ' diff --git a/tests/test_config_languages.py b/tests/test_config_languages.py new file mode 100644 index 00000000..8b062449 --- /dev/null +++ b/tests/test_config_languages.py @@ -0,0 +1,16 @@ +from app.config import settings + + +def test_available_languages_default_contains_fa(monkeypatch): + monkeypatch.setattr(settings, 'AVAILABLE_LANGUAGES', '', raising=False) + languages = settings.get_available_languages() + assert 'fa' in languages + + +def test_available_languages_normalizes_and_deduplicates(monkeypatch): + monkeypatch.setattr(settings, 'AVAILABLE_LANGUAGES', 'ru,en,fa,FA,fa-IR', raising=False) + languages = settings.get_available_languages() + assert languages[0] == 'ru' + assert 'en' in languages + assert 'fa' in languages + assert 'FA' not in languages diff --git a/tests/utils/test_formatters_basic.py b/tests/utils/test_formatters_basic.py index cf255b40..604301e0 100644 --- a/tests/utils/test_formatters_basic.py +++ b/tests/utils/test_formatters_basic.py @@ -31,6 +31,12 @@ def test_format_days_declension_handles_russian_rules() -> None: assert formatters.format_days_declension(10) == '10 дней' +def test_format_days_declension_uses_russian_fallback_for_fa() -> None: + """Для fa используем fallback на русские формы до полной локализации.""" + assert formatters.format_days_declension(1, language='fa') == '1 день' + assert formatters.format_days_declension(3, language='fa') == '3 дня' + + def test_format_duration_switches_units() -> None: """В зависимости от длины интервала выбирается подходящая единица измерения.""" assert formatters.format_duration(45) == '45 сек.' @@ -102,3 +108,9 @@ def test_format_boolean_localises_output() -> None: """Булевые значения отображаются локализованными словами.""" assert formatters.format_boolean(True, language='ru') == '✅ Да' assert formatters.format_boolean(False, language='en') == '❌ No' + + +def test_format_boolean_uses_russian_fallback_for_fa() -> None: + """Для fa булевы значения пока используют базовый ru fallback.""" + assert formatters.format_boolean(True, language='fa') == '✅ Да' + assert formatters.format_boolean(False, language='fa') == '❌ Нет'