from telegram import Update, InlineKeyboardButton,...

Created on: February 8, 2025

Answered using O1 by Chat01

Question

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Application, CommandHandler, CallbackQueryHandler,
ContextTypes, MessageHandler, filters
)
import uuid

BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo"
ADMIN_USER_ID = 6883576176

user_balances = {}
user_deal_steps = {}
active_deals = {}
username_to_id = {}
user_language = {}

TEXTS = {
"en": {
"welcome": (
"<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n"
"<b>Buy and sell anything – safely!</b>\n\n"
"From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n"
"🔹 Convenient wallet management\n"
"🔹 Referral system\n\n"
"<b>Please select a section below:</b>"
),
"btn_add_wallet": "🪙 Add Wallet",
"btn_create_deal": "🤝 Create a Deal",
"btn_profile": "👤 Profile",
"btn_change_language": "🌐 Change Language",
"btn_support": "📞 Support",
"add_wallet_placeholder": (
"🪙 This is a placeholder for the 'Add Wallet' section.\n"
"Here you would guide users to link or manage their wallets."
),
"ask_second_username": (
"<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:"
),
"profile_view": (
"👤 <b>Your Profile</b>\n\n"
"• Name: {first_name} {last_name}\n"
"• Username: @{username}\n"
"• Balance: {balance} USDT\n"
"• Preferred Language: {lang}\n"
),
"language_changed": (
"Language changed to: <b>{lang}</b>\n"
"(In a real bot, you’d reload text in that language.)"
),
"deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):",
"deal_step_amount": "Now, please enter the amount (in USDT) for this deal:",
"deal_confirm_msg": (
"<b>You are about to create a deal with @{second_user}.</b>\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"<b>Confirm creation?</b>"
),
"deal_insufficient_balance": (
"<b> You do not have enough balance to create this deal. Cancelled.</b>"
),
"deal_created": (
"✅ Deal created! Deal ID: {deal_id}\n\n"
"Waiting for @{second_user} to accept."
),
"deal_canceled": "Deal creation canceled.",
"deal_notify_second_user": (
"👋 You have a new deal request from @{creator_username}!\n\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"Deal ID: {deal_id}"
),
"deal_notify_username_not_found": (
"⚠️ We do not have a record of @{username}'s user ID. "
"They need to start the bot first so we can notify them."
),
"deal_accepted": (
"✅ You have accepted the deal {deal_id}.\n\n"
"Funds are now in escrow. Please proceed with the exchange of the item."
),
"deal_insufficient_after_accept": (
"Creator does not have sufficient funds. Deal canceled."
),
"deal_creator_notified_accepted": (
"Your deal {deal_id} was accepted by @{second_username}. "
"{amount} USDT is now frozen in escrow."
),
"deal_declined": "❌ You have declined the deal {deal_id}.",
"deal_creator_notified_declined": (
"Your deal {deal_id} was declined by @{second_username}."
),
"deal_prompt_received": (
"Once you receive the item, press the button below to release escrow to the seller.\n"
"If there's a problem, please contact support."
),
"deal_received_confirmed": (
"✅ You have confirmed receipt. Deal {deal_id} is completed!\n"
"You received {amount} USDT from escrow."
),
"deal_creator_notified_completed": (
"The buyer confirmed receipt. Deal {deal_id} is completed!\n"
"Your {amount} USDT has been released to them."
),
"not_authorized": "You are not authorized to perform this action.",
"add_money_success": "Added {amount} USDT to user {target_id}'s balance.",
"balance_increased_notification": (
"Good news! You've received {amount} USDT. "
"Your new balance is {new_balance} USDT."
),
"deal_not_found": "This deal no longer exists or was not found.",
"deal_not_waiting": "This deal is not awaiting acceptance.",
"deal_not_accepted_state": "This deal is not in an active (accepted) state.",
"not_second_user": "You are not the second participant of this deal.",
"not_in_deal_flow": "Use the main menu or /start to begin creating a deal.",
"invalid_amount": "Invalid amount. Please enter a number.",
},
"ru": {
"welcome": (
"<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n"
"<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n"
"От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n"
"🔹 Удобное управление кошельками\n"
"🔹 Реферальная система\n\n"
"<b>Пожалуйста, выберите раздел ниже:</b>"
),
"btn_add_wallet": "🪙 Добавить кошелек",
"btn_create_deal": "🤝 Создать сделку",
"btn_profile": "👤 Профиль",
"btn_change_language": "🌐 Сменить язык",
"btn_support": "📞 Поддержка",
"add_wallet_placeholder": (
"🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n"
"Здесь вы можете связать или управлять своими кошельками."
),
"ask_second_username": (
"Пожалуйста, введите <b>@username</b> второго участника сделки "
"(можете не писать '@'):"
),
"profile_view": (
"👤 <b>Ваш профиль</b> \n\n"
"• Имя: {first_name} {last_name}\n"
"• Логин: @{username}\n"
"• Баланс: {balance} USDT\n"
"• Предпочитаемый язык: {lang}\n"
),
"language_changed": (
"Язык изменен на: <b>{lang}</b>\n"
),
"deal_step_topic": "<b>Отлично! Теперь введите тему сделки</b> (например, 'Подарок NFT'):",
"deal_step_amount": "Теперь укажите сумму сделки (в USDT):",
"deal_confirm_msg": (
"Вы собираетесь создать сделку с @{second_user}.\n"
"Тема: {topic}\n"
"Сумма: {amount} USDT\n\n"
"Подтвердить создание?"
),
"deal_insufficient_balance": (
"У вас недостаточно средств для создания сделки. Отменено."
),
"deal_created": (
"✅ Сделка создана! ID сделки: {deal_id}\n\n"
"Ожидаем подтверждения от @{second_user}."
),
"deal_canceled": "Создание сделки отменено.",
"deal_notify_second_user": (
"👋 У вас новый запрос на сделку от @{creator_username}!\n\n"
"Тема: {topic}\n"
"Сумма: {amount} USDT\n\n"
"ID сделки: {deal_id}"
),
"deal_notify_username_not_found": (
"⚠️ У нас нет данных о пользователе @{username}. "
"Он должен сначала запустить бота, чтобы мы могли уведомить его."
),
"deal_accepted": (
"✅ Вы приняли сделку {deal_id}.\n\n"
"Средства заморожены. Пожалуйста, проведите обмен товаром."
),
"deal_insufficient_after_accept": (
"У создателя больше недостаточно средств. Сделка отменена."
),
"deal_creator_notified_accepted": (
"Ваша сделка {deal_id} была принята пользователем @{second_username}. "
"{amount} USDT заморожено в эскроу."
),
"deal_declined": "❌ Вы отклонили сделку {deal_id}.",
"deal_creator_notified_declined": (
"Ваша сделка {deal_id} была отклонена пользователем @{second_username}."
),
"deal_prompt_received": (
"Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n"
"Если что-то не так, свяжитесь со службой поддержки."
),
"deal_received_confirmed": (
"✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n"
"Вы получили {amount} USDT из эскроу."
),
"deal_creator_notified_completed": (
"Покупатель подтвердил получение. Сделка {deal_id} завершена!\n"
"Ваши {amount} USDT были переведены ему."
),
"not_authorized": "У вас нет прав для этого действия.",
"add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.",
"balance_increased_notification": (
"Отличные новости! Вы получили {amount} USDT.\n"
"Ваш новый баланс: {new_balance} USDT."
),
"deal_not_found": "Сделка не найдена или уже не существует.",
"deal_not_waiting": "Сделка не ожидает подтверждения.",
"deal_not_accepted_state": "Сделка находится не в статусе 'принята'.",
"not_second_user": "Вы не являетесь вторым участником данной сделки.",
"not_in_deal_flow": "Используйте главное меню или /start для создания сделки.",
"invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.",
}
}

def t(user_id: int, key: str) -> str:
lang = user_language.get(user_id, "en")
return TEXTS[lang].get(key, f"Missing translation for {key}")

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
if user.username:
username_to_id[user.username.lower()] = user.id
if user.id not in user_language:
user_language[user.id] = "en"
lang = user_language[user.id]
welcome_text = t(user.id, "welcome")
buttons = [
[InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')],
[InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')],
[InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')],
[InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')],
[InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')]
]
reply_markup = InlineKeyboardMarkup(buttons)
photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png"
await update.message.reply_photo(
photo=photo_url,
caption=welcome_text,
reply_markup=reply_markup,
parse_mode="HTML"
)

async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
if user.username:
username_to_id[user.username.lower()] = user_id
lang = user_language.get(user_id, "en")
if query.data == 'add_wallet':
await query.edit_message_caption(
caption=t(user_id, "add_wallet_placeholder"),
parse_mode="HTML"
)
elif query.data == 'create_deal':
user_deal_steps[user_id] = 'waiting_for_second_username'
await query.edit_message_caption(
caption=t(user_id, "ask_second_username"),
parse_mode="HTML"
)
elif query.data == 'profile':
balance = user_balances.get(user_id, 0.0)
profile_text = t(user_id, "profile_view").format(
first_name=user.first_name if user.first_name else "",
last_name=user.last_name if user.last_name else "",
username=(user.username if user.username else "N/A"),
balance=balance,
lang=lang
)
await query.edit_message_caption(caption=profile_text, parse_mode="HTML")
elif query.data == 'change_language':
new_lang = "ru" if lang == "en" else "en"
user_language[user_id] = new_lang
await query.edit_message_caption(
caption=t(user_id, "language_changed").format(lang=new_lang.upper()),
parse_mode="HTML"
)

async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE):
user_id = update.effective_user.id
if user_id != ADMIN_USER_ID:
await update.message.reply_text(t(user_id, "not_authorized"))
return
try:
target_user_id = int(context.args[0])
amount = float(context.args[1])
except (IndexError, ValueError):
await update.message.reply_text("Usage: /add_money <user_id> <amount>")
return
if target_user_id not in user_balances:
user_balances[target_user_id] = 0.0
user_balances[target_user_id] += amount
await update.message.reply_text(
t(user_id, "add_money_success").format(
amount=amount,
target_id=target_user_id
)
)
try:
target_lang = user_language.get(target_user_id, "en")
await context.bot.send_message(
chat_id=target_user_id,
text=TEXTS[target_lang]["balance_increased_notification"].format(
amount=amount,
new_balance=user_balances[target_user_id]
)
)
except Exception:
pass

async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
user = update.effective_user
user_id = user.id
text = update.message.text.strip()
if user.username:
username_to_id[user.username.lower()] = user_id
if user_id in user_deal_steps:
step = user_deal_steps[user_id]
if step == 'waiting_for_second_username':
context.user_data['deal_second_username'] = text.lstrip('@').lower()
user_deal_steps[user_id] = 'waiting_for_topic'
await update.message.reply_text(t(user_id, "deal_step_topic"))
return
elif step == 'waiting_for_topic':
context.user_data['deal_topic'] = text
user_deal_steps[user_id] = 'waiting_for_amount'
await update.message.reply_text(t(user_id, "deal_step_amount"))
return
elif step == 'waiting_for_amount':
try:
amount = float(text)
except ValueError:
await update.message.reply_text(t(user_id, "invalid_amount"))
return
context.user_data['deal_amount'] = amount
second_user_username = context.user_data.get('deal_second_username')
topic = context.user_data.get('deal_topic')
msg = t(user_id, "deal_confirm_msg").format(
second_user=second_user_username,
topic=topic,
amount=amount
)
reply_markup = InlineKeyboardMarkup([
[
InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"),
InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation")
]
])
await update.message.reply_text(msg, reply_markup=reply_markup)
user_deal_steps[user_id] = 'waiting_for_creation_confirmation'
return
else:
await update.message.reply_text(t(user_id, "not_in_deal_flow"))

async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()
if user.username:
username_to_id[user.username.lower()] = user_id
lang = user_language.get(user_id, "en")
if query.data == 'confirm_deal_creation':
if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation':
await query.edit_message_text("No active deal creation to confirm.")
return
second_user_username = context.user_data['deal_second_username']
topic = context.user_data['deal_topic']
amount = context.user_data['deal_amount']
creator_balance = user_balances.get(user_id, 0.0)
if creator_balance < amount:
await query.edit_message_text(t(user_id, "deal_insufficient_balance"))
user_deal_steps.pop(user_id, None)
return
deal_id = uuid.uuid4().hex
second_user_id = username_to_id.get(second_user_username)
active_deals[deal_id] = {
'creator': user_id,
'second_user': second_user_id,
'topic': topic,
'amount': amount,
'status': 'waiting_for_accept'
}
user_deal_steps.pop(user_id, None)
await query.edit_message_text(
t(user_id, "deal_created").format(
deal_id=deal_id,
second_user=second_user_username
)
)
if second_user_id:
second_user_lang = user_language.get(second_user_id, "en")
deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format(
creator_username=user.username,
topic=topic,
amount=amount,
deal_id=deal_id
)
btns = [
[
InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"),
InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}")
]
]
try:
await context.bot.send_message(
chat_id=second_user_id,
text=deal_info,
reply_markup=InlineKeyboardMarkup(btns)
)
except Exception:
await context.bot.send_message(
chat_id=user_id,
text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username)
)
else:
await context.bot.send_message(
chat_id=user_id,
text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username)
)
elif query.data == 'cancel_deal_creation':
user_deal_steps.pop(user_id, None)
await query.edit_message_text(t(user_id, "deal_canceled"))
elif query.data.startswith('accept_') or query.data.startswith('decline_'):
deal_id = query.data.split('', 1)[1]
if deal_id not in active_deals:
await query.edit_message_text(t(user_id, "deal_not_found"))
return
deal = active_deals[deal_id]
if user_id != deal['second_user']:
await query.edit_message_text(t(user_id, "not_second_user"))
return
if deal['status'] != 'waiting_for_accept':
await query.edit_message_text(t(user_id, "deal_not_waiting"))
return
if query.data.startswith('accept
'):
deal['status'] = 'accepted'
creator_id = deal['creator']
amount = deal['amount']
if user_balances.get(creator_id, 0.0) < amount:
deal['status'] = 'canceled'
await query.edit_message_text(t(user_id, "deal_insufficient_after_accept"))
return
user_balances[creator_id] -= amount
deal['frozen_amount'] = amount
await query.edit_message_text(
t(user_id, "deal_accepted").format(deal_id=deal_id)
)
creator_lang = user_language.get(creator_id, "en")
try:
await context.bot.send_message(
chat_id=creator_id,
text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format(
deal_id=deal_id,
second_username=user.username,
amount=amount
)
)
except Exception:
pass
final_btns = [
[
InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}")
]
]
prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"]
await context.bot.send_message(
chat_id=user_id,
text=prompt_text,
reply_markup=InlineKeyboardMarkup(final_btns)
)
else:
deal['status'] = 'declined'
await query.edit_message_text(
t(user_id, "deal_declined").format(deal_id=deal_id)
)
creator_id = deal['creator']
creator_lang = user_language.get(creator_id, "en")
try:
await context.bot.send_message(
chat_id=creator_id,
text=TEXTS[creator_lang]["deal_creator_notified_declined"].format(
deal_id=deal_id,
second_username=user.username
)
)
except Exception:
pass
elif query.data.startswith('received_'):
deal_id = query.data.split('_', 1)[1]
if deal_id not in active_deals:
await query.edit_message_text(t(user_id, "deal_not_found"))
return
deal = active_deals[deal_id]
if deal['status'] != 'accepted':
await query.edit_message_text(t(user_id, "deal_not_accepted_state"))
return
if user_id != deal['second_user']:
await query.edit_message_text(t(user_id, "not_second_user"))
return
amount = deal.get('frozen_amount', 0.0)
creator_id = deal['creator']
second_user_id = deal['second_user']
if amount > 0:
user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount
deal['status'] = 'completed'
deal['frozen_amount'] = 0.0
await query.edit_message_text(
t(user_id, "deal_received_confirmed").format(
deal_id=deal_id,
amount=amount
)
)
creator_lang = user_language.get(creator_id, "en")
try:
await context.bot.send_message(
chat_id=creator_id,
text=TEXTS[creator_lang]["deal_creator_notified_completed"].format(
deal_id=deal_id,
amount=amount
)
)
except Exception:
pass

def main():
application = Application.builder().token(BOT_TOKEN).build()
application.add_handler(CommandHandler("start", start))
application.add_handler(CommandHandler("add_money", add_money))
application.add_handler(
CallbackQueryHandler(
handle_main_menu_callback,
pattern='^(add_wallet|create_deal|profile|change_language)$'
)
)
application.add_handler(
CallbackQueryHandler(
handle_deal_callback,
pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)'
)
)
application.add_handler(
MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text)
)
application.run_polling()

if name == 'main':
main()

can u make Назад button under Язык изменен на: text

Thought

Crafting the "Back" button

I’m working on adding a "Back" button to the language change code. This button will lead users back to the main menu, improving navigation.

Revisiting exceptions and logic

I’m refining the logic to handle the "Назад" button, ensuring it reverts to the main menu screen with the inline keyboard. This involves updating patterns and callbacks for seamless navigation.

Finalizing the implementation

I’m mapping out how to handle the "main_menu" button, focusing on displaying a text-based main menu instead of a photo, to simplify the process and avoid media message issues.

Crafting the solution

I’m developing a "show_main_menu" function to simplify the process of displaying the main menu, ensuring it’s efficient and user-friendly.

Reasoned for 9 seconds

Answer

Below is an example of how you can add a "Назад" (Back) button after changing the language. The idea is:

  1. After the user taps "change_language", you switch their language.
  2. You edit the same message caption with the text indicating the language was changed.
  3. Underneath, you provide an inline keyboard with a "Назад" button that, when pressed, takes the user back to the main menu.

Step 1: Add 'main_menu' to the callback pattern

In the CallbackQueryHandler for the main menu callbacks, we should include main_menu in the pattern:

python
application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) )

Step 2: Edit handle_main_menu_callback to handle the "Назад" case

We add an elif query.data == 'main_menu': block that effectively re-displays the main menu:

python
async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Switch language new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Show the "Language changed" text with a "Назад" button back_button = InlineKeyboardMarkup([ [InlineKeyboardButton("Назад", callback_data="main_menu")] ]) await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # If the original message is a photo with a caption, # you can edit the caption instead of text: await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup )

With these changes:

  • When a user taps Change Language, the bot updates their language.
  • It then shows them the "Language changed…" text plus a Назад button.
  • Tapping Назад calls the callback with data='main_menu', which simply re-displays the main menu.

Question

integrate it into my text please

Thought

Integrating the "Назад" button

I’m working through incorporating the "Назад" button for language change, ensuring it includes 'main_menu' in the callback pattern and elif query.data == 'main_menu' for navigating back to the main menu.

Avoiding recursion

I’m ensuring code consistency by replicating it instead of calling start() from 'main_menu', to prevent potential recursion or message collision.

Integrating logic

I’m incorporating the 'main_menu' callback pattern and updating the logic to ensure seamless transitions between language changes and the main menu.

Reasoned for 10 seconds

Answer

Below is the updated code with the "Назад" (Back) button integrated right after changing the language. The main changes are:

  1. Added |main_menu to the callback query pattern.
  2. Added an elif query.data == 'main_menu' block that restores the main menu.
  3. In the 'change_language' section, we now display a "Назад" button that sends the user back to the main menu.

python
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" "(In a real bot, you’d reload text in that language.)" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" "• Имя: {first_name} {last_name}\n" "• Логин: @{username}\n" "• Баланс: {balance} USDT\n" "• Предпочитаемый язык: {lang}\n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки</b> (например, 'Подарок NFT'):", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") return TEXTS[lang].get(key, f"Missing translation for {key}") async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): """Start command, shows the main menu with a welcome message and buttons.""" user = update.effective_user if user.username: username_to_id[user.username.lower()] = user.id # Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path in your code). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" ) async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.).""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Show the "Language changed" text with a "Назад" button back_button = InlineKeyboardMarkup([ [InlineKeyboardButton("Назад", callback_data="main_menu")] ]) await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup ) async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE): """Admin-only command to add money to a user's balance.""" user_id = update.effective_user.id if user_id != ADMIN_USER_ID: await update.message.reply_text(t(user_id, "not_authorized")) return try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handle free-text input from the user for the multi-step deal creation flow.""" user = update.effective_user user_id = user.id text = update.message.text.strip() if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow")) async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles deal-related callbacks: confirming creation, accepting, declining, etc.""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance (in case it changed) if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from the creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm when they've received the item final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass def main(): application = Application.builder().token(BOT_TOKEN).build() # Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (now includes "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling() if __name__ == '__main__': main()

Explanation of Key Changes

  1. pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$'
    We expanded the pattern to include "main_menu", so when the user taps the “Назад” button, the callback data equals "main_menu", which our bot can handle.

  2. Inside elif query.data == 'change_language':

    • We switch the user’s language.
    • We create an inline keyboard with one button labeled "Назад", which points to "main_menu".
  3. Inside elif query.data == 'main_menu':
    We rebuild the main menu buttons (in the user’s current language) and use edit_message_caption to restore the original welcome text and menu inline keyboard.

With this, after the user changes the language, they see the text indicating it has changed plus a Назад button. Pressing that button takes them back to the main menu.

Question

Can you make it so if its Language changed to: EN
(In a real bot, you’d reload text in that language.) button is gonna be Back and if its on russian its gonna be назад

Thought

Enhancing localization

I’m thinking through how to label the back button based on the user's language preference, either "Назад" for Russian or "Back" for English.

Switching languages

I’m detailing how to toggle the language between Russian and English, updating the back button label accordingly. This involves setting and using the new_lang variable to control the label.

Updating the language

I’m working through the language change logic, ensuring the back button label is adjusted to "Назад" for Russian and "Back" for English, aligning with the user's preference.

Reasoned for 7 seconds

Answer

Below is a modified version of the code where the Back button text depends on the newly selected language:

  • If the new language is English, the button says "Back".
  • If the new language is Russian, the button says "Назад".

All other logic remains the same.

python
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" "(In a real bot, you’d reload text in that language.)" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" "• Имя: {first_name} {last_name}\n" "• Логин: @{username}\n" "• Баланс: {balance} USDT\n" "• Предпочитаемый язык: {lang}\n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки</b> (например, 'Подарок NFT'):", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") return TEXTS[lang].get(key, f"Missing translation for {key}") async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): """Start command, shows the main menu with a welcome message and buttons.""" user = update.effective_user if user.username: username_to_id[user.username.lower()] = user.id # Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" ) async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.).""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup ) async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE): """Admin-only command to add money to a user's balance.""" user_id = update.effective_user.id if user_id != ADMIN_USER_ID: await update.message.reply_text(t(user_id, "not_authorized")) return try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handle free-text input from the user for the multi-step deal creation flow.""" user = update.effective_user user_id = user.id text = update.message.text.strip() if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow")) async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles deal-related callbacks: confirming creation, accepting, declining, etc.""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance (in case it changed) if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from the creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm when they've received the item final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass def main(): application = Application.builder().token(BOT_TOKEN).build() # Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (now includes "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling() if __name__ == '__main__': main()

What Changed?

  • In the elif query.data == 'change_language': block, after we switch the user’s language, we now set:
    python
    back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ])
    This ensures the button label is "Назад" for Russian and "Back" for English.

Question

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Application, CommandHandler, CallbackQueryHandler,
ContextTypes, MessageHandler, filters
)
import uuid

BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo"
ADMIN_USER_ID = 6883576176

user_balances = {}
user_deal_steps = {}
active_deals = {}
username_to_id = {}
user_language = {}

TEXTS = {
"ru": {
"deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:",
"deal_step_amount": "Теперь укажите сумму сделки (в USDT):",
# дальше код без изменений
},
"en": {
"deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):",
"deal_step_amount": "Now, please enter the amount (in USDT) for this deal:",
# дальше код без изменений
}
}

def t(user_id: int, key: str) -> str:
"""Helper to get a translated string for a given user and key."""
lang = user_language.get(user_id, "en")
return TEXTS.get(lang, {}).get(key, f"Missing translation for {key}")

async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle free-text input from the user for the multi-step deal creation flow."""
user = update.effective_user
user_id = user.id
text = update.message.text.strip()

text
if user.username: username_to_id[user.username.lower()] = user_id if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' print(f"LANG: {user_language.get(user_id)}, TEXT: {t(user_id, 'deal_step_topic')}") await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return else: await update.message.reply_text(t(user_id, "not_in_deal_flow")) "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" " <b>• Имя: {first_name} {last_name}</b> \n" "• <b>Логин: @{username}</b> \n" "• <b>Баланс: {balance} USDT</b> \n" "• <b>Предпочитаемый язык: {lang}</b> \n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": " <b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b> :", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", }

def t(user_id: int, key: str) -> str:
"""Helper to get a translated string for a given user and key."""
lang = user_language.get(user_id, "en")
return TEXTS[lang].get(key, f"Missing translation for {key}")

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Start command, shows the main menu with a welcome message and buttons."""
user = update.effective_user
if user.username:
username_to_id[user.username.lower()] = user.id

text
# Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" )

async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.)."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()

text
if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup )

async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Admin-only command to add money to a user's balance."""
user_id = update.effective_user.id
if user_id != ADMIN_USER_ID:
await update.message.reply_text(t(user_id, "not_authorized"))
return

text
try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass

async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle free-text input from the user for the multi-step deal creation flow."""
user = update.effective_user
user_id = user.id
text = update.message.text.strip()

text
if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow"))

async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles deal-related callbacks: confirming creation, accepting, declining, etc."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()

text
if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance (in case it changed) if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from the creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm when they've received the item final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass

def main():
application = Application.builder().token(BOT_TOKEN).build()

text
# Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (now includes "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling()

if name == 'main':
main()


C:\Users\1234\AppData\Local\Programs\Python\Python313\python.exe "C:\Users\1234\Downloads\12 29\New folder\yabloko (2).py"
File "C:\Users\1234\Downloads\12 29\New folder\yabloko (2).py", line 62
"en": {
^^^^
SyntaxError: illegal target for annotation

Process finished with exit code 1

fix pls

Thought

Identifying syntax issues

I’m piecing together an error with a dictionary definition in line 62 of the code. This snippet seems to have multiple dictionary definitions or misplaced indentations.

Streamlining the code

OK, let me see. The issue stems from a partial dictionary in line 62. Removing this or merging it with the top dictionary simplifies things and avoids errors.

Cleaning up the code

Identifying extraneous lines and removing duplicates, particularly the second dictionary definition and repeated t() function. This will streamline the dictionary to a single, unified version.

Reasoned for 9 seconds

Answer

Below is a fixed version of your code. The main issue was that there was a second "en": { ... } dictionary declaration inside the code, causing Python to throw SyntaxError: illegal target for annotation.

You only need one TEXTS dictionary that includes both "ru" and "en" translations. Also, you only need one definition of the def t(user_id: int, key: str) -> str: function.

Here’s a merged/fixed code snippet:

python
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} # Single unified TEXTS dictionary TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_change_language": "🌐 Change Language", "btn_support": "📞 Support", "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b> You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_change_language": "🌐 Сменить язык", "btn_support": "📞 Поддержка", "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" " <b>• Имя: {first_name} {last_name}</b> \n" "• <b>Логин: @{username}</b> \n" "• <b>Баланс: {balance} USDT</b> \n" "• <b>Предпочитаемый язык: {lang}</b> \n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") # Return the requested key from the correct language dictionary return TEXTS[lang].get(key, f"Missing translation for {key}") async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): """Start command, shows the main menu with a welcome message and buttons.""" user = update.effective_user if user.username: username_to_id[user.username.lower()] = user.id # Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" ) async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.).""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup ) async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE): """Admin-only command to add money to a user's balance.""" user_id = update.effective_user.id if user_id != ADMIN_USER_ID: await update.message.reply_text(t(user_id, "not_authorized")) return try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handle free-text input from the user for the multi-step deal creation flow.""" user = update.effective_user user_id = user.id text = update.message.text.strip() if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow")) async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE): """Handles deal-related callbacks: confirming creation, accepting, declining, etc.""" query = update.callback_query user = query.from_user user_id = user.id await query.answer() if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm receipt final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass def main(): application = Application.builder().token(BOT_TOKEN).build() # Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (including "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling() if __name__ == '__main__': main()

Key Fixes

  1. Removed the extra "en": { ... } definition that was floating in the middle of the file.
  2. Combined all translations under the single top-level TEXTS dictionary.
  3. Kept only one def t(user_id: int, key: str): function.

With this structure, Python will no longer see the syntax error, and your bot code should run without the illegal target for annotation issue.

Question

from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup
from telegram.ext import (
Application, CommandHandler, CallbackQueryHandler,
ContextTypes, MessageHandler, filters
)
import uuid

BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo"
ADMIN_USER_ID = 6883576176

user_balances = {}
user_deal_steps = {}
active_deals = {}
username_to_id = {}
user_language = {}

Single unified TEXTS dictionary

TEXTS = {
"en": {
"welcome": (
"<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n"
"<b>Buy and sell anything – safely!</b>\n\n"
"From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n"
"🔹 Convenient wallet management\n"
"🔹 Referral system\n\n"
"<b>Please select a section below:</b>"
),
"btn_add_wallet": "🪙 Add Wallet",
"btn_create_deal": "🤝 Create a Deal",
"btn_profile": "👤 Profile",
"btn_change_language": "🌐 Change Language",
"btn_support": "📞 Support",
"add_wallet_placeholder": (
"🪙 This is a placeholder for the 'Add Wallet' section.\n"
"Here you would guide users to link or manage their wallets."
),
"ask_second_username": (
"<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:"
),
"profile_view": (
"👤 <b>Your Profile</b>\n\n"
"• Name: {first_name} {last_name}\n"
"• Username: @{username}\n"
"• Balance: {balance} USDT\n"
"• Preferred Language: {lang}\n"
),
"language_changed": (
"Language changed to: <b>{lang}</b>\n"
),
"deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):",
"deal_step_amount": "Now, please enter the amount (in USDT) for this deal:",
"deal_confirm_msg": (
"<b>You are about to create a deal with @{second_user}.</b>\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"<b>Confirm creation?</b>"
),
"deal_insufficient_balance": (
"<b> You do not have enough balance to create this deal. Cancelled.</b>"
),
"deal_created": (
"✅ Deal created! Deal ID: {deal_id}\n\n"
"Waiting for @{second_user} to accept."
),
"deal_canceled": "Deal creation canceled.",
"deal_notify_second_user": (
"👋 You have a new deal request from @{creator_username}!\n\n"
"Topic: {topic}\n"
"Amount: {amount} USDT\n\n"
"Deal ID: {deal_id}"
),
"deal_notify_username_not_found": (
"⚠️ We do not have a record of @{username}'s user ID. "
"They need to start the bot first so we can notify them."
),
"deal_accepted": (
"✅ You have accepted the deal {deal_id}.\n\n"
"Funds are now in escrow. Please proceed with the exchange of the item."
),
"deal_insufficient_after_accept": (
"Creator does not have sufficient funds. Deal canceled."
),
"deal_creator_notified_accepted": (
"Your deal {deal_id} was accepted by @{second_username}. "
"{amount} USDT is now frozen in escrow."
),
"deal_declined": "❌ You have declined the deal {deal_id}.",
"deal_creator_notified_declined": (
"Your deal {deal_id} was declined by @{second_username}."
),
"deal_prompt_received": (
"Once you receive the item, press the button below to release escrow to the seller.\n"
"If there's a problem, please contact support."
),
"deal_received_confirmed": (
"✅ You have confirmed receipt. Deal {deal_id} is completed!\n"
"You received {amount} USDT from escrow."
),
"deal_creator_notified_completed": (
"The buyer confirmed receipt. Deal {deal_id} is completed!\n"
"Your {amount} USDT has been released to them."
),
"not_authorized": "You are not authorized to perform this action.",
"add_money_success": "Added {amount} USDT to user {target_id}'s balance.",
"balance_increased_notification": (
"Good news! You've received {amount} USDT. "
"Your new balance is {new_balance} USDT."
),
"deal_not_found": "This deal no longer exists or was not found.",
"deal_not_waiting": "This deal is not awaiting acceptance.",
"deal_not_accepted_state": "This deal is not in an active (accepted) state.",
"not_second_user": "You are not the second participant of this deal.",
"not_in_deal_flow": "Use the main menu or /start to begin creating a deal.",
"invalid_amount": "Invalid amount. Please enter a number.",
},
"ru": {
"welcome": (
"<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n"
"<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n"
"От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n"
"🔹 Удобное управление кошельками\n"
"🔹 Реферальная система\n\n"
"<b>Пожалуйста, выберите раздел ниже:</b>"
),
"btn_add_wallet": "🪙 Добавить кошелек",
"btn_create_deal": "🤝 Создать сделку",
"btn_profile": "👤 Профиль",
"btn_change_language": "🌐 Сменить язык",
"btn_support": "📞 Поддержка",
"add_wallet_placeholder": (
"🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n"
"Здесь вы можете связать или управлять своими кошельками."
),
"ask_second_username": (
"Пожалуйста, введите <b>@username</b> второго участника сделки "
"(можете не писать '@'):"
),
"profile_view": (
"👤 <b>Ваш профиль</b> \n\n"
" <b>• Имя: {first_name} {last_name}</b> \n"
"• <b>Логин: @{username}</b> \n"
"• <b>Баланс: {balance} USDT</b> \n"
"• <b>Предпочитаемый язык: {lang}</b> \n"
),
"language_changed": (
"Язык изменен на: <b>{lang}</b>\n"
),
"deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:",
"deal_step_amount": "Теперь укажите сумму сделки (в USDT):",
"deal_confirm_msg": (
"Вы собираетесь создать сделку с @{second_user}.\n"
"Тема: {topic}\n"
"Сумма: {amount} USDT\n\n"
"Подтвердить создание?"
),

text
"deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", }

}

def t(user_id: int, key: str) -> str:
"""Helper to get a translated string for a given user and key."""
lang = user_language.get(user_id, "en")
# Return the requested key from the correct language dictionary
return TEXTS[lang].get(key, f"Missing translation for {key}")

async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Start command, shows the main menu with a welcome message and buttons."""
user = update.effective_user
if user.username:
username_to_id[user.username.lower()] = user.id

text
# Default to English if we don't have a language for this user. if user.id not in user_language: user_language[user.id] = "en" lang = user_language[user.id] welcome_text = t(user.id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Example photo URL (local path). Adjust as needed or use a hosted image. photo_url = r"C:\Users\1234\Downloads\12 29\New folder\ayd.png" await update.message.reply_photo( photo=photo_url, caption=welcome_text, reply_markup=reply_markup, parse_mode="HTML" )

async def handle_main_menu_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles the buttons in the main menu (Add Wallet, Create Deal, Profile, etc.)."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()

text
if user.username: username_to_id[user.username.lower()] = user_id lang = user_language.get(user_id, "en") if query.data == 'add_wallet': await query.edit_message_caption( caption=t(user_id, "add_wallet_placeholder"), parse_mode="HTML" ) elif query.data == 'create_deal': # Set the user's deal step to the first step of deal creation user_deal_steps[user_id] = 'waiting_for_second_username' await query.edit_message_caption( caption=t(user_id, "ask_second_username"), parse_mode="HTML" ) elif query.data == 'profile': balance = user_balances.get(user_id, 0.0) profile_text = t(user_id, "profile_view").format( first_name=user.first_name if user.first_name else "", last_name=user.last_name if user.last_name else "", username=(user.username if user.username else "N/A"), balance=balance, lang=lang ) await query.edit_message_caption(caption=profile_text, parse_mode="HTML") elif query.data == 'change_language': # Toggle between English and Russian new_lang = "ru" if lang == "en" else "en" user_language[user_id] = new_lang # Decide button label based on new language back_label = "Назад" if new_lang == "ru" else "Back" back_button = InlineKeyboardMarkup([ [InlineKeyboardButton(back_label, callback_data="main_menu")] ]) # Show the "Language changed" text with a localized back button await query.edit_message_caption( caption=t(user_id, "language_changed").format(lang=new_lang.upper()), parse_mode="HTML", reply_markup=back_button ) elif query.data == 'main_menu': # Re-render (or go back to) the main menu in the user's current language current_lang = user_language.get(user_id, "en") welcome_text = t(user_id, "welcome") buttons = [ [InlineKeyboardButton(TEXTS[current_lang]["btn_add_wallet"], callback_data='add_wallet')], [InlineKeyboardButton(TEXTS[current_lang]["btn_create_deal"], callback_data='create_deal')], [InlineKeyboardButton(TEXTS[current_lang]["btn_profile"], callback_data='profile')], [InlineKeyboardButton(TEXTS[current_lang]["btn_change_language"], callback_data='change_language')], [InlineKeyboardButton(TEXTS[current_lang]["btn_support"], url='https://t.me/delaPaul')] ] reply_markup = InlineKeyboardMarkup(buttons) # Edit the same message caption to restore the main menu await query.edit_message_caption( caption=welcome_text, parse_mode="HTML", reply_markup=reply_markup )

async def add_money(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Admin-only command to add money to a user's balance."""
user_id = update.effective_user.id
if user_id != ADMIN_USER_ID:
await update.message.reply_text(t(user_id, "not_authorized"))
return

text
try: target_user_id = int(context.args[0]) amount = float(context.args[1]) except (IndexError, ValueError): await update.message.reply_text("Usage: /add_money <user_id> <amount>") return if target_user_id not in user_balances: user_balances[target_user_id] = 0.0 user_balances[target_user_id] += amount await update.message.reply_text( t(user_id, "add_money_success").format( amount=amount, target_id=target_user_id ) ) # Notify the target user about increased balance try: target_lang = user_language.get(target_user_id, "en") await context.bot.send_message( chat_id=target_user_id, text=TEXTS[target_lang]["balance_increased_notification"].format( amount=amount, new_balance=user_balances[target_user_id] ) ) except Exception: pass

async def handle_user_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handle free-text input from the user for the multi-step deal creation flow."""
user = update.effective_user
user_id = user.id
text = update.message.text.strip()

text
if user.username: username_to_id[user.username.lower()] = user_id # Check if the user is in the middle of creating a deal if user_id in user_deal_steps: step = user_deal_steps[user_id] if step == 'waiting_for_second_username': context.user_data['deal_second_username'] = text.lstrip('@').lower() user_deal_steps[user_id] = 'waiting_for_topic' await update.message.reply_text(t(user_id, "deal_step_topic")) return elif step == 'waiting_for_topic': context.user_data['deal_topic'] = text user_deal_steps[user_id] = 'waiting_for_amount' await update.message.reply_text(t(user_id, "deal_step_amount")) return elif step == 'waiting_for_amount': try: amount = float(text) except ValueError: await update.message.reply_text(t(user_id, "invalid_amount")) return context.user_data['deal_amount'] = amount second_user_username = context.user_data.get('deal_second_username') topic = context.user_data.get('deal_topic') msg = t(user_id, "deal_confirm_msg").format( second_user=second_user_username, topic=topic, amount=amount ) reply_markup = InlineKeyboardMarkup([ [ InlineKeyboardButton("✅ Yes", callback_data="confirm_deal_creation"), InlineKeyboardButton("❌ No", callback_data="cancel_deal_creation") ] ]) await update.message.reply_text(msg, reply_markup=reply_markup) user_deal_steps[user_id] = 'waiting_for_creation_confirmation' return else: # If the user is not in a deal flow, let them know or guide them to /start await update.message.reply_text(t(user_id, "not_in_deal_flow"))

async def handle_deal_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Handles deal-related callbacks: confirming creation, accepting, declining, etc."""
query = update.callback_query
user = query.from_user
user_id = user.id
await query.answer()

text
if user.username: username_to_id[user.username.lower()] = user_id if query.data == 'confirm_deal_creation': if user_id not in user_deal_steps or user_deal_steps[user_id] != 'waiting_for_creation_confirmation': await query.edit_message_text("No active deal creation to confirm.") return second_user_username = context.user_data['deal_second_username'] topic = context.user_data['deal_topic'] amount = context.user_data['deal_amount'] creator_balance = user_balances.get(user_id, 0.0) # Check if the creator has enough balance if creator_balance < amount: await query.edit_message_text(t(user_id, "deal_insufficient_balance")) user_deal_steps.pop(user_id, None) return deal_id = uuid.uuid4().hex second_user_id = username_to_id.get(second_user_username) active_deals[deal_id] = { 'creator': user_id, 'second_user': second_user_id, 'topic': topic, 'amount': amount, 'status': 'waiting_for_accept' } # Clear the user's deal step user_deal_steps.pop(user_id, None) await query.edit_message_text( t(user_id, "deal_created").format( deal_id=deal_id, second_user=second_user_username ) ) # Notify second user about the deal, if we have their ID if second_user_id: second_user_lang = user_language.get(second_user_id, "en") deal_info = TEXTS[second_user_lang]["deal_notify_second_user"].format( creator_username=user.username, topic=topic, amount=amount, deal_id=deal_id ) btns = [ [ InlineKeyboardButton("✅ Accept", callback_data=f"accept_{deal_id}"), InlineKeyboardButton("❌ Decline", callback_data=f"decline_{deal_id}") ] ] try: await context.bot.send_message( chat_id=second_user_id, text=deal_info, reply_markup=InlineKeyboardMarkup(btns) ) except Exception: await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) else: # If second user hasn't started the bot yet, we can't notify them await context.bot.send_message( chat_id=user_id, text=t(user_id, "deal_notify_username_not_found").format(username=second_user_username) ) elif query.data == 'cancel_deal_creation': user_deal_steps.pop(user_id, None) await query.edit_message_text(t(user_id, "deal_canceled")) elif query.data.startswith('accept_') or query.data.startswith('decline_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return if deal['status'] != 'waiting_for_accept': await query.edit_message_text(t(user_id, "deal_not_waiting")) return if query.data.startswith('accept_'): deal['status'] = 'accepted' creator_id = deal['creator'] amount = deal['amount'] # Re-check creator's balance if user_balances.get(creator_id, 0.0) < amount: deal['status'] = 'canceled' await query.edit_message_text(t(user_id, "deal_insufficient_after_accept")) return # Freeze the amount by deducting from creator's balance user_balances[creator_id] -= amount deal['frozen_amount'] = amount await query.edit_message_text( t(user_id, "deal_accepted").format(deal_id=deal_id) ) # Notify creator that the deal was accepted creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_accepted"].format( deal_id=deal_id, second_username=user.username, amount=amount ) ) except Exception: pass # Ask second user to confirm receipt final_btns = [ [ InlineKeyboardButton("✅ I have received the item", callback_data=f"received_{deal_id}") ] ] prompt_text = TEXTS[user_language.get(user_id, "en")]["deal_prompt_received"] await context.bot.send_message( chat_id=user_id, text=prompt_text, reply_markup=InlineKeyboardMarkup(final_btns) ) else: # Declined deal['status'] = 'declined' await query.edit_message_text( t(user_id, "deal_declined").format(deal_id=deal_id) ) creator_id = deal['creator'] creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_declined"].format( deal_id=deal_id, second_username=user.username ) ) except Exception: pass elif query.data.startswith('received_'): deal_id = query.data.split('_', 1)[1] if deal_id not in active_deals: await query.edit_message_text(t(user_id, "deal_not_found")) return deal = active_deals[deal_id] if deal['status'] != 'accepted': await query.edit_message_text(t(user_id, "deal_not_accepted_state")) return if user_id != deal['second_user']: await query.edit_message_text(t(user_id, "not_second_user")) return amount = deal.get('frozen_amount', 0.0) creator_id = deal['creator'] second_user_id = deal['second_user'] # Release funds to the second user if amount > 0: user_balances[second_user_id] = user_balances.get(second_user_id, 0.0) + amount deal['status'] = 'completed' deal['frozen_amount'] = 0.0 await query.edit_message_text( t(user_id, "deal_received_confirmed").format( deal_id=deal_id, amount=amount ) ) # Notify creator that the deal is completed creator_lang = user_language.get(creator_id, "en") try: await context.bot.send_message( chat_id=creator_id, text=TEXTS[creator_lang]["deal_creator_notified_completed"].format( deal_id=deal_id, amount=amount ) ) except Exception: pass

def main():
application = Application.builder().token(BOT_TOKEN).build()

text
# Commands application.add_handler(CommandHandler("start", start)) application.add_handler(CommandHandler("add_money", add_money)) # Handle main menu callbacks (including "main_menu") application.add_handler( CallbackQueryHandler( handle_main_menu_callback, pattern='^(add_wallet|create_deal|profile|change_language|main_menu)$' ) ) # Handle deal-related callbacks application.add_handler( CallbackQueryHandler( handle_deal_callback, pattern='^(confirm_deal_creation|cancel_deal_creation|accept_|decline_|received_)' ) ) # Handle user text for multi-step deal creation application.add_handler( MessageHandler(filters.TEXT & ~filters.COMMAND, handle_user_text) ) application.run_polling()

if name == 'main':
main()

Убери кнопку смены языка

Thought

Removing language toggling

I’m pulling out the language change button from the main menu and handling language change callbacks. This might leave the language-dictionary in place for switching languages.

Reasoned for 5 seconds

Answer

Below is your updated code without the language-change button. All the logic for multi-language support remains (in case you still want to handle users in different languages), but there is no button for the user to toggle language.

Changes Made

  1. Removed the btn_change_language line from the buttons in start().
  2. Removed the elif query.data == 'change_language': block in handle_main_menu_callback.
  3. Removed "change_language" from the callback query handler pattern.
python
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup from telegram.ext import ( Application, CommandHandler, CallbackQueryHandler, ContextTypes, MessageHandler, filters ) import uuid BOT_TOKEN = "7619922446:AAGuyec31whkGW3xflUvcdtSYLLLarc7UUo" ADMIN_USER_ID = 6883576176 user_balances = {} user_deal_steps = {} active_deals = {} username_to_id = {} user_language = {} # Single unified TEXTS dictionary TEXTS = { "en": { "welcome": ( "<b>👋 Welcome to Paul Automatic Guarantor – a reliable P2P guarantor</b>\n\n" "<b>Buy and sell anything – safely!</b>\n\n" "From Telegram gifts and NFTs to tokens and fiat, your transactions are easy and secure.\n\n" "🔹 Convenient wallet management\n" "🔹 Referral system\n\n" "<b>Please select a section below:</b>" ), "btn_add_wallet": "🪙 Add Wallet", "btn_create_deal": "🤝 Create a Deal", "btn_profile": "👤 Profile", "btn_support": "📞 Support", # Removed "btn_change_language" "add_wallet_placeholder": ( "🪙 This is a placeholder for the 'Add Wallet' section.\n" "Here you would guide users to link or manage their wallets." ), "ask_second_username": ( "<b>Please enter the @username of the second person in the deal (you can omit '@')</b>:" ), "profile_view": ( "👤 <b>Your Profile</b>\n\n" "• Name: {first_name} {last_name}\n" "• Username: @{username}\n" "• Balance: {balance} USDT\n" "• Preferred Language: {lang}\n" ), "language_changed": ( "Language changed to: <b>{lang}</b>\n" ), "deal_step_topic": "Great! Now enter the topic (e.g. 'NFT Gift'):", "deal_step_amount": "Now, please enter the amount (in USDT) for this deal:", "deal_confirm_msg": ( "<b>You are about to create a deal with @{second_user}.</b>\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "<b>Confirm creation?</b>" ), "deal_insufficient_balance": ( "<b>You do not have enough balance to create this deal. Cancelled.</b>" ), "deal_created": ( "✅ Deal created! Deal ID: {deal_id}\n\n" "Waiting for @{second_user} to accept." ), "deal_canceled": "Deal creation canceled.", "deal_notify_second_user": ( "👋 You have a new deal request from @{creator_username}!\n\n" "Topic: {topic}\n" "Amount: {amount} USDT\n\n" "Deal ID: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ We do not have a record of @{username}'s user ID. " "They need to start the bot first so we can notify them." ), "deal_accepted": ( "✅ You have accepted the deal {deal_id}.\n\n" "Funds are now in escrow. Please proceed with the exchange of the item." ), "deal_insufficient_after_accept": ( "Creator does not have sufficient funds. Deal canceled." ), "deal_creator_notified_accepted": ( "Your deal {deal_id} was accepted by @{second_username}. " "{amount} USDT is now frozen in escrow." ), "deal_declined": "❌ You have declined the deal {deal_id}.", "deal_creator_notified_declined": ( "Your deal {deal_id} was declined by @{second_username}." ), "deal_prompt_received": ( "Once you receive the item, press the button below to release escrow to the seller.\n" "If there's a problem, please contact support." ), "deal_received_confirmed": ( "✅ You have confirmed receipt. Deal {deal_id} is completed!\n" "You received {amount} USDT from escrow." ), "deal_creator_notified_completed": ( "The buyer confirmed receipt. Deal {deal_id} is completed!\n" "Your {amount} USDT has been released to them." ), "not_authorized": "You are not authorized to perform this action.", "add_money_success": "Added {amount} USDT to user {target_id}'s balance.", "balance_increased_notification": ( "Good news! You've received {amount} USDT. " "Your new balance is {new_balance} USDT." ), "deal_not_found": "This deal no longer exists or was not found.", "deal_not_waiting": "This deal is not awaiting acceptance.", "deal_not_accepted_state": "This deal is not in an active (accepted) state.", "not_second_user": "You are not the second participant of this deal.", "not_in_deal_flow": "Use the main menu or /start to begin creating a deal.", "invalid_amount": "Invalid amount. Please enter a number.", }, "ru": { "welcome": ( "<b>👋 Добро пожаловать в Paul Automatic Guarantor – надежный P2P гарант</b>\n\n" "<b>Покупайте и продавайте что угодно – безопасно!</b>\n\n" "От подарков в Telegram и NFT до токенов и фиата – ваши сделки просты и безопасны.\n\n" "🔹 Удобное управление кошельками\n" "🔹 Реферальная система\n\n" "<b>Пожалуйста, выберите раздел ниже:</b>" ), "btn_add_wallet": "🪙 Добавить кошелек", "btn_create_deal": "🤝 Создать сделку", "btn_profile": "👤 Профиль", "btn_support": "📞 Поддержка", # Removed "btn_change_language" "add_wallet_placeholder": ( "🪙 Это пример (заглушка) раздела 'Добавить кошелек'.\n" "Здесь вы можете связать или управлять своими кошельками." ), "ask_second_username": ( "Пожалуйста, введите <b>@username</b> второго участника сделки " "(можете не писать '@'):" ), "profile_view": ( "👤 <b>Ваш профиль</b> \n\n" " <b>• Имя: {first_name} {last_name}</b> \n" "• <b>Логин: @{username}</b> \n" "• <b>Баланс: {balance} USDT</b> \n" "• <b>Предпочитаемый язык: {lang}</b> \n" ), "language_changed": ( "Язык изменен на: <b>{lang}</b>\n" ), "deal_step_topic": "<b>Отлично! Теперь введите тему сделки (например, 'Подарок NFT')</b>:", "deal_step_amount": "Теперь укажите сумму сделки (в USDT):", "deal_confirm_msg": ( "Вы собираетесь создать сделку с @{second_user}.\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "Подтвердить создание?" ), "deal_insufficient_balance": ( "У вас недостаточно средств для создания сделки. Отменено." ), "deal_created": ( "✅ Сделка создана! ID сделки: {deal_id}\n\n" "Ожидаем подтверждения от @{second_user}." ), "deal_canceled": "Создание сделки отменено.", "deal_notify_second_user": ( "👋 У вас новый запрос на сделку от @{creator_username}!\n\n" "Тема: {topic}\n" "Сумма: {amount} USDT\n\n" "ID сделки: {deal_id}" ), "deal_notify_username_not_found": ( "⚠️ У нас нет данных о пользователе @{username}. " "Он должен сначала запустить бота, чтобы мы могли уведомить его." ), "deal_accepted": ( "✅ Вы приняли сделку {deal_id}.\n\n" "Средства заморожены. Пожалуйста, проведите обмен товаром." ), "deal_insufficient_after_accept": ( "У создателя больше недостаточно средств. Сделка отменена." ), "deal_creator_notified_accepted": ( "Ваша сделка {deal_id} была принята пользователем @{second_username}. " "{amount} USDT заморожено в эскроу." ), "deal_declined": "❌ Вы отклонили сделку {deal_id}.", "deal_creator_notified_declined": ( "Ваша сделка {deal_id} была отклонена пользователем @{second_username}." ), "deal_prompt_received": ( "Как только вы получите товар, нажмите кнопку ниже, чтобы передать средства продавцу.\n" "Если что-то не так, свяжитесь со службой поддержки." ), "deal_received_confirmed": ( "✅ Вы подтвердили получение. Сделка {deal_id} завершена!\n" "Вы получили {amount} USDT из эскроу." ), "deal_creator_notified_completed": ( "Покупатель подтвердил получение. Сделка {deal_id} завершена!\n" "Ваши {amount} USDT были переведены ему." ), "not_authorized": "У вас нет прав для этого действия.", "add_money_success": "Добавлено {amount} USDT на баланс пользователя {target_id}.", "balance_increased_notification": ( "Отличные новости! Вы получили {amount} USDT.\n" "Ваш новый баланс: {new_balance} USDT." ), "deal_not_found": "Сделка не найдена или уже не существует.", "deal_not_waiting": "Сделка не ожидает подтверждения.", "deal_not_accepted_state": "Сделка находится не в статусе 'принята'.", "not_second_user": "Вы не являетесь вторым участником данной сделки.", "not_in_deal_flow": "Используйте главное меню или /start для создания сделки.", "invalid_amount": "Неверно указана сумма. Пожалуйста, введите число.", } } def t(user_id: int, key: str) -> str: """Helper to get a translated string for a given user and key.""" lang = user_language.get(user_id, "en") return TEXTS[lang].get(key, f"Missing translation for {key}") async def

Share this Q&A