2025-12-04 14:46:30 +03:00
from aiogram import Router , F
from aiogram . filters import Command
from aiogram . types import Message , CallbackQuery , InlineKeyboardMarkup , InlineKeyboardButton
from aiogram . fsm . context import FSMContext
from database . db import async_session_maker
from database . models import LanguageLevel
2025-12-04 19:40:01 +03:00
from bot . handlers . start import main_menu_keyboard
2025-12-04 14:46:30 +03:00
from services . user_service import UserService
router = Router ( )
2025-12-04 19:40:01 +03:00
def _is_en ( user ) - > bool :
try :
return ( getattr ( user , ' language_interface ' , ' ru ' ) or ' ru ' ) == ' en '
except Exception :
return False
def _is_ja ( user ) - > bool :
try :
return ( getattr ( user , ' language_interface ' , ' ru ' ) or ' ru ' ) == ' ja '
except Exception :
return False
2025-12-04 14:46:30 +03:00
def get_settings_keyboard ( user ) - > InlineKeyboardMarkup :
""" Создать клавиатуру настроек """
2025-12-04 19:40:01 +03:00
is_en = _is_en ( user )
is_ja = _is_ja ( user )
2025-12-04 14:46:30 +03:00
keyboard = InlineKeyboardMarkup ( inline_keyboard = [
[ InlineKeyboardButton (
2025-12-04 19:40:01 +03:00
text = (
" 📊 Level: " if is_en else ( " 📊 レベル: " if is_ja else " 📊 Уровень: " )
) + f " { user . level . value } " ,
2025-12-04 14:46:30 +03:00
callback_data = " settings_level "
) ] ,
[ InlineKeyboardButton (
2025-12-04 19:40:01 +03:00
text = (
" 🎯 Learning language: " if is_en else ( " 🎯 学習言語: " if is_ja else " 🎯 Язык изучения: " )
) + ( user . learning_language . upper ( ) ) ,
callback_data = " settings_learning "
) ] ,
[ InlineKeyboardButton (
text = (
" 🌐 Interface language: " if is_en else ( " 🌐 インターフェース言語: " if is_ja else " 🌐 Язык интерфейса: " )
) + ( " 🇬🇧 English " if getattr ( user , ' language_interface ' , ' ru ' ) == ' en ' else ( " 🇯🇵 日本語 " if getattr ( user , ' language_interface ' , ' ru ' ) == ' ja ' else " 🇷🇺 Русский " ) ) ,
2025-12-04 14:46:30 +03:00
callback_data = " settings_language "
) ] ,
[ InlineKeyboardButton (
2025-12-04 19:40:01 +03:00
text = ( " ❌ Close " if is_en else ( " ❌ 閉じる " if is_ja else " ❌ Закрыть " ) ) ,
2025-12-04 14:46:30 +03:00
callback_data = " settings_close "
) ]
] )
return keyboard
2025-12-04 19:40:01 +03:00
def get_level_keyboard ( user = None ) - > InlineKeyboardMarkup :
2025-12-04 14:46:30 +03:00
""" Клавиатура выбора уровня """
2025-12-04 19:40:01 +03:00
lang = getattr ( user , ' language_interface ' , ' ru ' ) if user is not None else ' ru '
if lang == ' en ' :
levels = [
( " A1 - Beginner " , " set_level_A1 " ) ,
( " A2 - Elementary " , " set_level_A2 " ) ,
( " B1 - Intermediate " , " set_level_B1 " ) ,
( " B2 - Upper-intermediate " , " set_level_B2 " ) ,
( " C1 - Advanced " , " set_level_C1 " ) ,
( " C2 - Proficient " , " set_level_C2 " ) ,
]
elif lang == ' ja ' :
levels = [
( " A1 - 初級 " , " set_level_A1 " ) ,
( " A2 - 初級(上) " , " set_level_A2 " ) ,
( " B1 - 中級 " , " set_level_B1 " ) ,
( " B2 - 中級(上) " , " set_level_B2 " ) ,
( " C1 - 上級 " , " set_level_C1 " ) ,
( " C2 - ネイティブ " , " set_level_C2 " ) ,
]
else :
levels = [
( " A1 - Начальный " , " set_level_A1 " ) ,
( " A2 - Элементарный " , " set_level_A2 " ) ,
( " B1 - Средний " , " set_level_B1 " ) ,
( " B2 - Выше среднего " , " set_level_B2 " ) ,
( " C1 - Продвинутый " , " set_level_C1 " ) ,
( " C2 - Профессиональный " , " set_level_C2 " ) ,
]
2025-12-04 14:46:30 +03:00
keyboard = [ ]
for level_name , callback_data in levels :
keyboard . append ( [ InlineKeyboardButton ( text = level_name , callback_data = callback_data ) ] )
2025-12-04 19:40:01 +03:00
back_label = " ⬅️ Back " if lang == ' en ' else ( " ⬅️ 戻る " if lang == ' ja ' else " ⬅️ Назад " )
keyboard . append ( [ InlineKeyboardButton ( text = back_label , callback_data = " settings_back " ) ] )
2025-12-04 14:46:30 +03:00
return InlineKeyboardMarkup ( inline_keyboard = keyboard )
2025-12-04 19:40:01 +03:00
def get_language_keyboard ( user = None ) - > InlineKeyboardMarkup :
2025-12-04 14:46:30 +03:00
""" Клавиатура выбора языка интерфейса """
2025-12-04 19:40:01 +03:00
lang = getattr ( user , ' language_interface ' , ' ru ' ) if user is not None else ' ru '
back = " ⬅️ Back " if lang == ' en ' else ( " ⬅️ 戻る " if lang == ' ja ' else " ⬅️ Назад " )
2025-12-04 14:46:30 +03:00
keyboard = InlineKeyboardMarkup ( inline_keyboard = [
[ InlineKeyboardButton ( text = " 🇷🇺 Русский " , callback_data = " set_lang_ru " ) ] ,
2025-12-04 19:40:01 +03:00
[ InlineKeyboardButton ( text = " 🇬🇧 English " , callback_data = " set_lang_en " ) ] ,
[ InlineKeyboardButton ( text = " 🇯🇵 日本語 " , callback_data = " set_lang_ja " ) ] ,
[ InlineKeyboardButton ( text = back , callback_data = " settings_back " ) ]
2025-12-04 14:46:30 +03:00
] )
return keyboard
2025-12-04 19:40:01 +03:00
def get_learning_language_keyboard ( user = None ) - > InlineKeyboardMarkup :
""" Клавиатура выбора языка изучения """
lang = getattr ( user , ' language_interface ' , ' ru ' ) if user is not None else ' ru '
back = " ⬅️ Back " if lang == ' en ' else ( " ⬅️ 戻る " if lang == ' ja ' else " ⬅️ Назад " )
# Пары (код -> подпись)
options = [
( " en " , " 🇬🇧 English " if lang != ' ja ' else " 🇬🇧 英語 " ) ,
( " es " , " 🇪🇸 Spanish " if lang == ' en ' else ( " 🇪🇸 スペイン語 " if lang == ' ja ' else " 🇪🇸 Испанский " ) ) ,
( " de " , " 🇩🇪 German " if lang == ' en ' else ( " 🇩🇪 ドイツ語 " if lang == ' ja ' else " 🇩🇪 Немецкий " ) ) ,
( " fr " , " 🇫🇷 French " if lang == ' en ' else ( " 🇫🇷 フランス語 " if lang == ' ja ' else " 🇫🇷 Французский " ) ) ,
( " ja " , " 🇯🇵 Japanese " if lang == ' en ' else ( " 🇯🇵 日本語 " if lang == ' ja ' else " 🇯🇵 Японский " ) ) ,
]
keyboard = [ [ InlineKeyboardButton ( text = label , callback_data = f " set_learning_ { code } " ) ] for code , label in options ]
keyboard . append ( [ InlineKeyboardButton ( text = back , callback_data = " settings_back " ) ] )
return InlineKeyboardMarkup ( inline_keyboard = keyboard )
2025-12-04 14:46:30 +03:00
@router.message ( Command ( " settings " ) )
async def cmd_settings ( message : Message ) :
""" Обработчик команды /settings """
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , message . from_user . id )
if not user :
await message . answer ( " Сначала запусти бота командой /start " )
return
2025-12-04 19:40:01 +03:00
lang = getattr ( user , ' language_interface ' , ' ru ' )
title = " ⚙️ <b>Settings</b> \n \n " if lang == ' en ' else ( " ⚙️ <b>設定</b> \n \n " if lang == ' ja ' else " ⚙️ <b>Настройки</b> \n \n " )
level_label = " 📊 English level: " if lang == ' en ' else ( " 📊 英語レベル: " if lang == ' ja ' else " 📊 Уровень английского: " )
lang_label = " 🌐 Interface language: " if lang == ' en ' else ( " 🌐 インターフェース言語: " if lang == ' ja ' else " 🌐 Язык интерфейса: " )
lang_value = ' English ' if lang == ' en ' else ( ' 日本語 ' if lang == ' ja ' else ( ' Русский ' if user . language_interface == ' ru ' else ' English ' ) )
footer = " Choose what to change: " if lang == ' en ' else ( " 変更したい項目を選択: " if lang == ' ja ' else " Выбери, что хочешь изменить: " )
settings_text = f " { title } { level_label } <b> { user . level . value } </b> \n { lang_label } <b> { lang_value } </b> \n \n { footer } "
2025-12-04 14:46:30 +03:00
await message . answer ( settings_text , reply_markup = get_settings_keyboard ( user ) )
@router.callback_query ( F . data == " settings_level " )
async def settings_level ( callback : CallbackQuery ) :
""" Показать выбор уровня """
2025-12-04 19:40:01 +03:00
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , callback . from_user . id )
lang = getattr ( user , ' language_interface ' , ' ru ' ) if user else ' ru '
title = " 📊 <b>Choose your English level:</b> \n \n " if lang == ' en ' else ( " 📊 <b>英語レベルを選択:</b> \n \n " if lang == ' ja ' else " 📊 <b>Выбери свой уровень английского:</b> \n \n " )
body = (
" <b>A1-A2</b> - Beginner \n <b>B1-B2</b> - Intermediate \n <b>C1-C2</b> - Advanced \n \n " if lang == ' en ' else (
" <b>A1-A2</b> - 初級 \n <b>B1-B2</b> - 中級 \n <b>C1-C2</b> - 上級 \n \n " if lang == ' ja ' else
" <b>A1-A2</b> - Начинающий \n <b>B1-B2</b> - Средний \n <b>C1-C2</b> - Продвинутый \n \n "
) )
tail = " This affects difficulty of suggested words and tasks. " if lang == ' en ' else ( " これは提案される単語や課題の難易度に影響します。 " if lang == ' ja ' else " Это влияет на сложность предлагаемых слов и заданий. " )
await callback . message . edit_text ( title + body + tail , reply_markup = get_level_keyboard ( user ) )
await callback . answer ( )
@router.callback_query ( F . data == " settings_learning " )
async def settings_learning ( callback : CallbackQuery ) :
""" Показать выбор языка изучения """
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , callback . from_user . id )
lang = getattr ( user , ' language_interface ' , ' ru ' ) if user else ' ru '
title = " 🎯 <b>Select learning language:</b> \n \n " if lang == ' en ' else ( " 🎯 <b>学習言語を選択:</b> \n \n " if lang == ' ja ' else " 🎯 <b>Выбери язык изучения:</b> \n \n " )
await callback . message . edit_text ( title , reply_markup = get_learning_language_keyboard ( user ) )
await callback . answer ( )
@router.callback_query ( F . data . startswith ( " set_learning_ " ) )
async def set_learning_language ( callback : CallbackQuery ) :
""" Установить язык изучения """
code = callback . data . split ( " _ " ) [ - 1 ]
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , callback . from_user . id )
if user :
await UserService . update_user_learning_language ( session , user . id , code )
lang = getattr ( user , ' language_interface ' , ' ru ' )
if lang == ' en ' :
text = f " ✅ Learning language: <b> { code . upper ( ) } </b> "
back = " ⬅️ Back to settings "
elif lang == ' ja ' :
text = f " ✅ 学習言語: <b> { code . upper ( ) } </b> "
back = " ⬅️ 設定に戻る "
else :
text = f " ✅ Язык изучения: <b> { code . upper ( ) } </b> "
back = " ⬅️ К настройкам "
await callback . message . edit_text (
text ,
reply_markup = InlineKeyboardMarkup ( inline_keyboard = [ [ InlineKeyboardButton ( text = back , callback_data = " settings_back " ) ] ] )
)
2025-12-04 14:46:30 +03:00
await callback . answer ( )
@router.callback_query ( F . data . startswith ( " set_level_ " ) )
async def set_level ( callback : CallbackQuery ) :
""" Установить уровень """
level_str = callback . data . split ( " _ " ) [ - 1 ] # A1, A2, B1, B2, C1, C2
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , callback . from_user . id )
if user :
# Обновляем уровень
await UserService . update_user_level ( session , user . id , LanguageLevel [ level_str ] )
2025-12-04 19:40:01 +03:00
lang = getattr ( user , ' language_interface ' , ' ru ' )
changed = " ✅ Level changed to " if lang == ' en ' else ( " ✅ レベルが変更されました: " if lang == ' ja ' else " ✅ Уровень изменен на " )
msg = changed + f " <b> { level_str } </b> \n \n " + ( " You will now receive words and tasks matching your level! " if lang == ' en ' else ( " これからレベルに合った単語と課題が出題されます! " if lang == ' ja ' else " Теперь ты будешь получать слова и задания, соответствующие твоему уровню! " ) )
back = " ⬅️ Back to settings " if lang == ' en ' else ( " ⬅️ 設定に戻る " if lang == ' ja ' else " ⬅️ К настройкам " )
2025-12-04 14:46:30 +03:00
await callback . message . edit_text (
2025-12-04 19:40:01 +03:00
msg ,
reply_markup = InlineKeyboardMarkup ( inline_keyboard = [ [ InlineKeyboardButton ( text = back , callback_data = " settings_back " ) ] ] )
2025-12-04 14:46:30 +03:00
)
await callback . answer ( )
@router.callback_query ( F . data == " settings_language " )
async def settings_language ( callback : CallbackQuery ) :
""" Показать выбор языка """
2025-12-04 19:40:01 +03:00
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , callback . from_user . id )
lang = getattr ( user , ' language_interface ' , ' ru ' ) if user else ' ru '
title = " 🌐 <b>Select interface language:</b> \n \n " if lang == ' en ' else ( " 🌐 <b>インターフェース言語を選択:</b> \n \n " if lang == ' ja ' else " 🌐 <b>Выбери язык интерфейса:</b> \n \n " )
desc = " This will change the language of bot messages. " if lang == ' en ' else ( " ボットの表示言語が変更されます。 " if lang == ' ja ' else " Это изменит язык всех сообщений бота. " )
2025-12-04 14:46:30 +03:00
await callback . message . edit_text (
2025-12-04 19:40:01 +03:00
title + desc ,
reply_markup = get_language_keyboard ( user )
2025-12-04 14:46:30 +03:00
)
await callback . answer ( )
@router.callback_query ( F . data . startswith ( " set_lang_ " ) )
async def set_language ( callback : CallbackQuery ) :
""" Установить язык """
2025-12-04 19:40:01 +03:00
lang = callback . data . split ( " _ " ) [ - 1 ] # ru | en | ja
2025-12-04 14:46:30 +03:00
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , callback . from_user . id )
if user :
await UserService . update_user_language ( session , user . id , lang )
2025-12-04 19:40:01 +03:00
if lang == ' en ' :
text = " ✅ Interface language: <b>English</b> "
back = " ⬅️ Back "
elif lang == ' ja ' :
text = " ✅ インターフェース言語: <b>日本語</b> "
back = " ⬅️ 戻る "
else :
text = " ✅ Язык интерфейса: <b>Русский</b> "
back = " ⬅️ К настройкам "
2025-12-04 14:46:30 +03:00
await callback . message . edit_text (
2025-12-04 19:40:01 +03:00
text ,
reply_markup = InlineKeyboardMarkup ( inline_keyboard = [ [ InlineKeyboardButton ( text = back , callback_data = " settings_back " ) ] ] )
2025-12-04 14:46:30 +03:00
)
2025-12-04 19:40:01 +03:00
# Обновляем клавиатуру чата на выбранный язык
menu_updated = " Main menu updated ⤵️ " if lang == ' en ' else ( " メインメニューを更新しました ⤵️ " if lang == ' ja ' else " Клавиатура обновлена ⤵️ " )
await callback . message . answer ( menu_updated , reply_markup = main_menu_keyboard ( lang ) )
2025-12-04 14:46:30 +03:00
await callback . answer ( )
@router.callback_query ( F . data == " settings_back " )
async def settings_back ( callback : CallbackQuery ) :
""" Вернуться к настройкам """
async with async_session_maker ( ) as session :
user = await UserService . get_user_by_telegram_id ( session , callback . from_user . id )
if user :
2025-12-04 19:40:01 +03:00
lang = getattr ( user , ' language_interface ' , ' ru ' )
title = " ⚙️ <b>Settings</b> \n \n " if lang == ' en ' else ( " ⚙️ <b>設定</b> \n \n " if lang == ' ja ' else " ⚙️ <b>Настройки</b> \n \n " )
level_label = " 📊 English level: " if lang == ' en ' else ( " 📊 英語レベル: " if lang == ' ja ' else " 📊 Уровень английского: " )
lang_label = " 🌐 Interface language: " if lang == ' en ' else ( " 🌐 インターフェース言語: " if lang == ' ja ' else " 🌐 Язык интерфейса: " )
lang_value = ' English ' if user . language_interface == ' en ' else ( ' 日本語 ' if user . language_interface == ' ja ' else ' Русский ' )
footer = " Choose what to change: " if lang == ' en ' else ( " 変更したい項目を選択: " if lang == ' ja ' else " Выбери, что хочешь изменить: " )
settings_text = f " { title } { level_label } <b> { user . level . value } </b> \n { lang_label } <b> { lang_value } </b> \n \n { footer } "
2025-12-04 14:46:30 +03:00
await callback . message . edit_text ( settings_text , reply_markup = get_settings_keyboard ( user ) )
await callback . answer ( )
@router.callback_query ( F . data == " settings_close " )
async def settings_close ( callback : CallbackQuery ) :
""" Закрыть настройки """
await callback . message . delete ( )
await callback . answer ( )