diff --git a/app/handlers/subscription.py b/app/handlers/subscription.py index 9454217b..bb68b9a6 100644 --- a/app/handlers/subscription.py +++ b/app/handlers/subscription.py @@ -1,7 +1,9 @@ +import base64 import json import logging from datetime import datetime, timedelta from typing import Dict, List, Any, Tuple, Optional +from urllib.parse import quote from aiogram import Dispatcher, types, F from aiogram.fsm.context import FSMContext @@ -5556,6 +5558,20 @@ async def handle_device_guide( + f"\n{subscription_link}\n\n" ) + installation_description = get_step_description(featured_app, "installationStep", db_user.language) + add_description = get_step_description(featured_app, "addSubscriptionStep", db_user.language) + connect_description = get_step_description(featured_app, "connectAndUseStep", db_user.language) + additional_before_text = format_additional_section( + featured_app.get("additionalBeforeAddSubscriptionStep"), + texts, + db_user.language, + ) + additional_after_text = format_additional_section( + featured_app.get("additionalAfterAddSubscriptionStep"), + texts, + db_user.language, + ) + guide_text = ( texts.t( "SUBSCRIPTION_DEVICE_GUIDE_TITLE", @@ -5566,17 +5582,26 @@ async def handle_device_guide( + texts.t( "SUBSCRIPTION_DEVICE_FEATURED_APP", "πŸ“‹ Π Π΅ΠΊΠΎΠΌΠ΅Π½Π΄ΡƒΠ΅ΠΌΠΎΠ΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅: {app_name}", - ).format(app_name=featured_app['name']) - + "\n\n" - + texts.t("SUBSCRIPTION_DEVICE_STEP_INSTALL_TITLE", "Π¨Π°Π³ 1 - Установка:") - + f"\n{featured_app['installationStep']['description'][db_user.language]}\n\n" - + texts.t("SUBSCRIPTION_DEVICE_STEP_ADD_TITLE", "Π¨Π°Π³ 2 - Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ подписки:") - + f"\n{featured_app['addSubscriptionStep']['description'][db_user.language]}\n\n" - + texts.t("SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE", "Π¨Π°Π³ 3 - ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅:") - + f"\n{featured_app['connectAndUseStep']['description'][db_user.language]}\n\n" - + texts.t("SUBSCRIPTION_DEVICE_HOW_TO_TITLE", "πŸ’‘ Как ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ:") - + "\n" - + "\n".join( + ).format(app_name=featured_app.get('name', '')) + ) + + guide_text += "\n\n" + texts.t("SUBSCRIPTION_DEVICE_STEP_INSTALL_TITLE", "Π¨Π°Π³ 1 - Установка:") + if installation_description: + guide_text += f"\n{installation_description}" + + if additional_before_text: + guide_text += f"\n\n{additional_before_text}" + + guide_text += "\n\n" + texts.t("SUBSCRIPTION_DEVICE_STEP_ADD_TITLE", "Π¨Π°Π³ 2 - Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ подписки:") + if add_description: + guide_text += f"\n{add_description}" + + guide_text += "\n\n" + texts.t("SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE", "Π¨Π°Π³ 3 - ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅:") + if connect_description: + guide_text += f"\n{connect_description}" + + guide_text += "\n\n" + texts.t("SUBSCRIPTION_DEVICE_HOW_TO_TITLE", "πŸ’‘ Как ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ:") + guide_text += "\n" + "\n".join( [ texts.t( "SUBSCRIPTION_DEVICE_HOW_TO_STEP1", @@ -5584,7 +5609,7 @@ async def handle_device_guide( ), texts.t( "SUBSCRIPTION_DEVICE_HOW_TO_STEP2", - "2. Π‘ΠΊΠΎΠΏΠΈΡ€ΡƒΠΉΡ‚Π΅ ссылку подписки (Π½Π°ΠΆΠΌΠΈΡ‚Π΅ Π½Π° Π½Π΅Ρ‘)", + "2. НаТмитС ΠΊΠ½ΠΎΠΏΠΊΡƒ \"ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ\" Π½ΠΈΠΆΠ΅", ), texts.t( "SUBSCRIPTION_DEVICE_HOW_TO_STEP3", @@ -5596,7 +5621,9 @@ async def handle_device_guide( ), ] ) - ) + + if additional_after_text: + guide_text += f"\n\n{additional_after_text}" await callback.message.edit_text( guide_text, @@ -5691,31 +5718,46 @@ async def handle_specific_app_guide( + f"\n{subscription_link}\n\n" ) + installation_description = get_step_description(app, "installationStep", db_user.language) + add_description = get_step_description(app, "addSubscriptionStep", db_user.language) + connect_description = get_step_description(app, "connectAndUseStep", db_user.language) + additional_before_text = format_additional_section( + app.get("additionalBeforeAddSubscriptionStep"), + texts, + db_user.language, + ) + additional_after_text = format_additional_section( + app.get("additionalAfterAddSubscriptionStep"), + texts, + db_user.language, + ) + guide_text = ( texts.t( "SUBSCRIPTION_SPECIFIC_APP_TITLE", "πŸ“± {app_name} - {device_name}", - ).format(app_name=app['name'], device_name=get_device_name(device_type, db_user.language)) + ).format(app_name=app.get('name', ''), device_name=get_device_name(device_type, db_user.language)) + "\n\n" + link_section - + texts.t("SUBSCRIPTION_DEVICE_STEP_INSTALL_TITLE", "Π¨Π°Π³ 1 - Установка:") - + f"\n{app['installationStep']['description'][db_user.language]}\n\n" - + texts.t("SUBSCRIPTION_DEVICE_STEP_ADD_TITLE", "Π¨Π°Π³ 2 - Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ подписки:") - + f"\n{app['addSubscriptionStep']['description'][db_user.language]}\n\n" - + texts.t("SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE", "Π¨Π°Π³ 3 - ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅:") - + f"\n{app['connectAndUseStep']['description'][db_user.language]}" ) - if 'additionalAfterAddSubscriptionStep' in app: - additional = app['additionalAfterAddSubscriptionStep'] - guide_text += ( - "\n\n" - + texts.t( - "SUBSCRIPTION_ADDITIONAL_STEP_TITLE", - "{title}:", - ).format(title=additional['title'][db_user.language]) - + f"\n{additional['description'][db_user.language]}" - ) + guide_text += texts.t("SUBSCRIPTION_DEVICE_STEP_INSTALL_TITLE", "Π¨Π°Π³ 1 - Установка:") + if installation_description: + guide_text += f"\n{installation_description}" + + if additional_before_text: + guide_text += f"\n\n{additional_before_text}" + + guide_text += "\n\n" + texts.t("SUBSCRIPTION_DEVICE_STEP_ADD_TITLE", "Π¨Π°Π³ 2 - Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ подписки:") + if add_description: + guide_text += f"\n{add_description}" + + guide_text += "\n\n" + texts.t("SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE", "Π¨Π°Π³ 3 - ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅:") + if connect_description: + guide_text += f"\n{connect_description}" + + if additional_after_text: + guide_text += f"\n\n{additional_after_text}" await callback.message.edit_text( guide_text, @@ -5858,14 +5900,119 @@ def load_app_config() -> Dict[str, Any]: config_path = settings.get_app_config_path() with open(config_path, 'r', encoding='utf-8') as f: - return json.load(f) + data = json.load(f) + if isinstance(data, dict): + return data + logger.error("НСкоррСктный Ρ„ΠΎΡ€ΠΌΠ°Ρ‚ app-config.json: оТидаСтся ΠΎΠ±ΡŠΠ΅ΠΊΡ‚") except Exception as e: logger.error(f"Ошибка Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠΈ ΠΊΠΎΠ½Ρ„ΠΈΠ³Π° ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠΉ: {e}") - return {} + + return {} + + +def get_localized_value(values: Any, language: str, default_language: str = "en") -> str: + if not isinstance(values, dict): + return "" + + candidates: List[str] = [] + normalized_language = (language or "").strip().lower() + + if normalized_language: + candidates.append(normalized_language) + if "-" in normalized_language: + candidates.append(normalized_language.split("-")[0]) + + default_language = (default_language or "").strip().lower() + if default_language and default_language not in candidates: + candidates.append(default_language) + + for candidate in candidates: + if not candidate: + continue + value = values.get(candidate) + if isinstance(value, str) and value.strip(): + return value + + for value in values.values(): + if isinstance(value, str) and value.strip(): + return value + + return "" + + +def get_step_description(app: Dict[str, Any], step_key: str, language: str) -> str: + if not isinstance(app, dict): + return "" + + step = app.get(step_key) + if not isinstance(step, dict): + return "" + + description = step.get("description") + return get_localized_value(description, language) + + +def format_additional_section(additional: Any, texts, language: str) -> str: + if not isinstance(additional, dict): + return "" + + title = get_localized_value(additional.get("title"), language) + description = get_localized_value(additional.get("description"), language) + + parts: List[str] = [] + + if title: + parts.append( + texts.t( + "SUBSCRIPTION_ADDITIONAL_STEP_TITLE", + "{title}:", + ).format(title=title) + ) + + if description: + parts.append(description) + + return "\n".join(parts) + + +def build_redirect_link(target_link: Optional[str], template: Optional[str]) -> Optional[str]: + if not target_link or not template: + return None + + normalized_target = str(target_link).strip() + normalized_template = str(template).strip() + + if not normalized_target or not normalized_template: + return None + + encoded_target = quote(normalized_target, safe="") + result = normalized_template + replaced = False + + replacements = [ + ("{subscription_link}", encoded_target), + ("{link}", encoded_target), + ("{subscription_link_raw}", normalized_target), + ("{link_raw}", normalized_target), + ] + + for placeholder, replacement in replacements: + if placeholder in result: + result = result.replace(placeholder, replacement) + replaced = True + + if not replaced: + result = f"{result}{encoded_target}" + + return result def get_apps_for_device(device_type: str, language: str = "ru") -> List[Dict[str, Any]]: - config = load_app_config()['platforms'] + config = load_app_config() + platforms = config.get("platforms", {}) if isinstance(config, dict) else {} + + if not isinstance(platforms, dict): + return [] device_mapping = { 'ios': 'ios', @@ -5876,32 +6023,49 @@ def get_apps_for_device(device_type: str, language: str = "ru") -> List[Dict[str } config_key = device_mapping.get(device_type, device_type) - return config.get(config_key, []) + apps = platforms.get(config_key, []) + return apps if isinstance(apps, list) else [] def get_device_name(device_type: str, language: str = "ru") -> str: - if language == "en": - names = { - 'ios': 'iPhone/iPad', - 'android': 'Android', - 'windows': 'Windows', - 'mac': 'macOS', - 'tv': 'Android TV' - } - else: - names = { - 'ios': 'iPhone/iPad', - 'android': 'Android', - 'windows': 'Windows', - 'mac': 'macOS', - 'tv': 'Android TV' - } + names = { + 'ios': 'iPhone/iPad', + 'android': 'Android', + 'windows': 'Windows', + 'mac': 'macOS', + 'tv': 'Android TV' + } return names.get(device_type, device_type) -def create_deep_link(app: Dict[str, Any], subscription_url: str) -> str: - return subscription_url +def create_deep_link(app: Dict[str, Any], subscription_url: str) -> Optional[str]: + if not subscription_url: + return None + + if not isinstance(app, dict): + return subscription_url + + scheme = str(app.get("urlScheme", "")).strip() + payload = subscription_url + + if app.get("isNeedBase64Encoding"): + try: + payload = base64.b64encode(subscription_url.encode("utf-8")).decode("utf-8") + except Exception as exc: + logger.warning( + "НС ΡƒΠ΄Π°Π»ΠΎΡΡŒ Π·Π°ΠΊΠΎΠ΄ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку подписки Π² base64 для прилоТСния %s: %s", + app.get("id"), + exc, + ) + payload = subscription_url + + scheme_link = f"{scheme}{payload}" if scheme else None + + template = settings.get_happ_cryptolink_redirect_template() + redirect_link = build_redirect_link(scheme_link, template) if scheme_link and template else None + + return redirect_link or scheme_link or subscription_url def get_reset_devices_confirm_keyboard(language: str = "ru") -> InlineKeyboardMarkup: diff --git a/app/keyboards/inline.py b/app/keyboards/inline.py index b6cb2212..9a051e75 100644 --- a/app/keyboards/inline.py +++ b/app/keyboards/inline.py @@ -17,6 +17,64 @@ import logging logger = logging.getLogger(__name__) + +def _get_localized_value(values, language: str, default_language: str = "en") -> str: + if not isinstance(values, dict): + return "" + + candidates = [] + normalized_language = (language or "").strip().lower() + + if normalized_language: + candidates.append(normalized_language) + if "-" in normalized_language: + candidates.append(normalized_language.split("-")[0]) + + default_language = (default_language or "").strip().lower() + if default_language and default_language not in candidates: + candidates.append(default_language) + + for candidate in candidates: + if not candidate: + continue + value = values.get(candidate) + if isinstance(value, str) and value.strip(): + return value + + for value in values.values(): + if isinstance(value, str) and value.strip(): + return value + + return "" + + +def _build_additional_buttons(additional_section, language: str) -> List[InlineKeyboardButton]: + if not isinstance(additional_section, dict): + return [] + + buttons = additional_section.get("buttons") + if not isinstance(buttons, list): + return [] + + localized_buttons: List[InlineKeyboardButton] = [] + + for button in buttons: + if not isinstance(button, dict): + continue + + button_text = _get_localized_value(button.get("buttonText"), language) + button_link = button.get("buttonLink") + + if not button_text or not button_link: + continue + + localized_buttons.append( + InlineKeyboardButton(text=button_text, url=button_link) + ) + + return localized_buttons + + _LANGUAGE_DISPLAY_NAMES = { "ru": "πŸ‡·πŸ‡Ί Русский", "en": "πŸ‡¬πŸ‡§ English", @@ -1564,42 +1622,70 @@ def get_device_selection_keyboard(language: str = DEFAULT_LANGUAGE) -> InlineKey def get_connection_guide_keyboard( - subscription_url: str, - app: dict, + subscription_url: str, + app: dict, language: str = DEFAULT_LANGUAGE ) -> InlineKeyboardMarkup: from app.handlers.subscription import create_deep_link texts = get_texts(language) - + keyboard = [] - + if 'installationStep' in app and 'buttons' in app['installationStep']: app_buttons = [] for button in app['installationStep']['buttons']: - button_text = button['buttonText'].get(language, button['buttonText']['en']) + button_text = _get_localized_value(button.get('buttonText'), language) + button_link = button.get('buttonLink') + + if not button_text or not button_link: + continue + app_buttons.append( - InlineKeyboardButton(text=f"πŸ“₯ {button_text}", url=button['buttonLink']) + InlineKeyboardButton(text=f"πŸ“₯ {button_text}", url=button_link) ) if len(app_buttons) == 2: keyboard.append(app_buttons) app_buttons = [] - + if app_buttons: keyboard.append(app_buttons) - - if settings.is_happ_cryptolink_mode(): - copy_button = InlineKeyboardButton( - text=texts.t("COPY_SUBSCRIPTION_LINK", "πŸ“‹ Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку подписки"), + + additional_before_buttons = _build_additional_buttons( + app.get('additionalBeforeAddSubscriptionStep'), + language, + ) + + for button in additional_before_buttons: + keyboard.append([button]) + + connect_link = create_deep_link(app, subscription_url) + + if connect_link: + connect_button = InlineKeyboardButton( + text=texts.t("CONNECT_BUTTON", "πŸ”— ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ"), + url=connect_link, + ) + elif settings.is_happ_cryptolink_mode(): + connect_button = InlineKeyboardButton( + text=texts.t("CONNECT_BUTTON", "πŸ”— ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ"), callback_data="open_subscription_link", ) else: - copy_button = InlineKeyboardButton( - text=texts.t("COPY_SUBSCRIPTION_LINK", "πŸ“‹ Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку подписки"), + connect_button = InlineKeyboardButton( + text=texts.t("CONNECT_BUTTON", "πŸ”— ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ"), url=subscription_url, ) - keyboard.append([copy_button]) - + keyboard.append([connect_button]) + + additional_after_buttons = _build_additional_buttons( + app.get('additionalAfterAddSubscriptionStep'), + language, + ) + + for button in additional_after_buttons: + keyboard.append([button]) + keyboard.extend([ [ InlineKeyboardButton(text=texts.t("CHOOSE_ANOTHER_DEVICE", "πŸ“± Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΎΠ΅ устройство"), callback_data="subscription_connect") @@ -1652,43 +1738,64 @@ def get_specific_app_keyboard( ) -> InlineKeyboardMarkup: from app.handlers.subscription import create_deep_link texts = get_texts(language) - + keyboard = [] - + if 'installationStep' in app and 'buttons' in app['installationStep']: app_buttons = [] for button in app['installationStep']['buttons']: - button_text = button['buttonText'].get(language, button['buttonText']['en']) + button_text = _get_localized_value(button.get('buttonText'), language) + button_link = button.get('buttonLink') + + if not button_text or not button_link: + continue + app_buttons.append( - InlineKeyboardButton(text=f"πŸ“₯ {button_text}", url=button['buttonLink']) + InlineKeyboardButton(text=f"πŸ“₯ {button_text}", url=button_link) ) if len(app_buttons) == 2: keyboard.append(app_buttons) app_buttons = [] - + if app_buttons: keyboard.append(app_buttons) - - if settings.is_happ_cryptolink_mode(): - copy_button = InlineKeyboardButton( - text=texts.t("COPY_SUBSCRIPTION_LINK", "πŸ“‹ Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку подписки"), + + additional_before_buttons = _build_additional_buttons( + app.get('additionalBeforeAddSubscriptionStep'), + language, + ) + + for button in additional_before_buttons: + keyboard.append([button]) + + connect_link = create_deep_link(app, subscription_url) + + if connect_link: + connect_button = InlineKeyboardButton( + text=texts.t("CONNECT_BUTTON", "πŸ”— ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ"), + url=connect_link, + ) + elif settings.is_happ_cryptolink_mode(): + connect_button = InlineKeyboardButton( + text=texts.t("CONNECT_BUTTON", "πŸ”— ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ"), callback_data="open_subscription_link", ) else: - copy_button = InlineKeyboardButton( - text=texts.t("COPY_SUBSCRIPTION_LINK", "πŸ“‹ Π‘ΠΊΠΎΠΏΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ссылку подписки"), + connect_button = InlineKeyboardButton( + text=texts.t("CONNECT_BUTTON", "πŸ”— ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ"), url=subscription_url, ) - keyboard.append([copy_button]) - - if 'additionalAfterAddSubscriptionStep' in app and 'buttons' in app['additionalAfterAddSubscriptionStep']: - for button in app['additionalAfterAddSubscriptionStep']['buttons']: - button_text = button['buttonText'].get(language, button['buttonText']['en']) - keyboard.append([ - InlineKeyboardButton(text=button_text, url=button['buttonLink']) - ]) - + keyboard.append([connect_button]) + + additional_after_buttons = _build_additional_buttons( + app.get('additionalAfterAddSubscriptionStep'), + language, + ) + + for button in additional_after_buttons: + keyboard.append([button]) + keyboard.extend([ [ InlineKeyboardButton(text=texts.t("OTHER_APPS_BUTTON", "πŸ“‹ Π”Ρ€ΡƒΠ³ΠΈΠ΅ прилоТСния"), callback_data=f"app_list_{device_type}") diff --git a/app/localization/locales/en.json b/app/localization/locales/en.json index 8b1cdb3a..c1535d15 100644 --- a/app/localization/locales/en.json +++ b/app/localization/locales/en.json @@ -440,7 +440,7 @@ "SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE": "Step 3 - Connect:", "SUBSCRIPTION_DEVICE_HOW_TO_TITLE": "πŸ’‘ How to connect:", "SUBSCRIPTION_DEVICE_HOW_TO_STEP1": "1. Install the app from the link above", - "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. Copy the subscription link (tap on it)", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. Tap the \"Connect\" button below", "SUBSCRIPTION_DEVICE_HOW_TO_STEP3": "3. Open the app and paste the link", "SUBSCRIPTION_DEVICE_HOW_TO_STEP4": "4. Connect to a server", "SUBSCRIPTION_APPS_TITLE": "πŸ“± Apps for {device_name}", diff --git a/app/localization/locales/ru.json b/app/localization/locales/ru.json index ca6ba4fd..2896470b 100644 --- a/app/localization/locales/ru.json +++ b/app/localization/locales/ru.json @@ -450,7 +450,7 @@ "SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE": "Π¨Π°Π³ 3 - ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅:", "SUBSCRIPTION_DEVICE_HOW_TO_TITLE": "πŸ’‘ Как ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ:", "SUBSCRIPTION_DEVICE_HOW_TO_STEP1": "1. УстановитС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎ ссылкС Π²Ρ‹ΡˆΠ΅", - "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. Π‘ΠΊΠΎΠΏΠΈΡ€ΡƒΠΉΡ‚Π΅ ссылку подписки (Π½Π°ΠΆΠΌΠΈΡ‚Π΅ Π½Π° Π½Π΅Ρ‘)", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. НаТмитС ΠΊΠ½ΠΎΠΏΠΊΡƒ \"ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ\" Π½ΠΈΠΆΠ΅", "SUBSCRIPTION_DEVICE_HOW_TO_STEP3": "3. ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π²ΡΡ‚Π°Π²ΡŒΡ‚Π΅ ссылку", "SUBSCRIPTION_DEVICE_HOW_TO_STEP4": "4. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ΡΡŒ ΠΊ сСрвСру", "SUBSCRIPTION_APPS_TITLE": "πŸ“± ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ для {device_name}", diff --git a/locales/en.json b/locales/en.json index e4b12469..aa17d574 100644 --- a/locales/en.json +++ b/locales/en.json @@ -480,7 +480,7 @@ "SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE": "Step 3 - Connect:", "SUBSCRIPTION_DEVICE_HOW_TO_TITLE": "πŸ’‘ How to connect:", "SUBSCRIPTION_DEVICE_HOW_TO_STEP1": "1. Install the app from the link above", - "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. Copy the subscription link (tap on it)", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. Tap the \"Connect\" button below", "SUBSCRIPTION_DEVICE_HOW_TO_STEP3": "3. Open the app and paste the link", "SUBSCRIPTION_DEVICE_HOW_TO_STEP4": "4. Connect to a server", "SUBSCRIPTION_APPS_TITLE": "πŸ“± Apps for {device_name}", diff --git a/locales/ru.json b/locales/ru.json index 31d2704e..11666b7b 100644 --- a/locales/ru.json +++ b/locales/ru.json @@ -482,7 +482,7 @@ "SUBSCRIPTION_DEVICE_STEP_CONNECT_TITLE": "Π¨Π°Π³ 3 - ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅:", "SUBSCRIPTION_DEVICE_HOW_TO_TITLE": "πŸ’‘ Как ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ:", "SUBSCRIPTION_DEVICE_HOW_TO_STEP1": "1. УстановитС ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΠΎ ссылкС Π²Ρ‹ΡˆΠ΅", - "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. Π‘ΠΊΠΎΠΏΠΈΡ€ΡƒΠΉΡ‚Π΅ ссылку подписки (Π½Π°ΠΆΠΌΠΈΡ‚Π΅ Π½Π° Π½Π΅Ρ‘)", + "SUBSCRIPTION_DEVICE_HOW_TO_STEP2": "2. НаТмитС ΠΊΠ½ΠΎΠΏΠΊΡƒ \"ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒΡΡ\" Π½ΠΈΠΆΠ΅", "SUBSCRIPTION_DEVICE_HOW_TO_STEP3": "3. ΠžΡ‚ΠΊΡ€ΠΎΠΉΡ‚Π΅ ΠΏΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΈ Π²ΡΡ‚Π°Π²ΡŒΡ‚Π΅ ссылку", "SUBSCRIPTION_DEVICE_HOW_TO_STEP4": "4. ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚Π΅ΡΡŒ ΠΊ сСрвСру", "SUBSCRIPTION_APPS_TITLE": "πŸ“± ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΡ для {device_name}",