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 bot.handlers.start import main_menu_keyboard
from services.user_service import UserService
from utils.i18n import t, get_user_lang
from utils.levels import (
get_user_level_for_language,
get_available_levels,
get_level_system,
get_level_key_for_i18n,
)
router = Router()
def get_settings_keyboard(user) -> InlineKeyboardMarkup:
"""Создать клавиатуру настроек"""
lang = get_user_lang(user)
ui_lang_code = getattr(user, 'language_interface', 'ru') or 'ru'
current_level = get_user_level_for_language(user)
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(
text=t(lang, 'settings.level_prefix') + f"{current_level}",
callback_data="settings_level"
)],
[InlineKeyboardButton(
text=t(lang, 'settings.learning_prefix') + user.learning_language.upper(),
callback_data="settings_learning"
)],
[InlineKeyboardButton(
text=t(lang, 'settings.interface_prefix') + t(lang, f'settings.lang_name.{ui_lang_code}'),
callback_data="settings_language"
)],
[InlineKeyboardButton(
text=t(lang, 'settings.close'),
callback_data="settings_close"
)]
])
return keyboard
def get_level_keyboard(user=None) -> InlineKeyboardMarkup:
"""Клавиатура выбора уровня (CEFR или JLPT в зависимости от языка изучения)"""
lang = get_user_lang(user)
learning_lang = getattr(user, 'learning_language', 'en') or 'en'
available_levels = get_available_levels(learning_lang)
keyboard = []
for level in available_levels:
# Ключ локализации: settings.level.a1 или settings.jlpt.n5
i18n_key = get_level_key_for_i18n(learning_lang, level)
level_name = t(lang, i18n_key)
keyboard.append([InlineKeyboardButton(text=level_name, callback_data=f"set_level_{level}")])
keyboard.append([InlineKeyboardButton(text=t(lang, 'settings.back'), callback_data="settings_back")])
return InlineKeyboardMarkup(inline_keyboard=keyboard)
def get_language_keyboard(user=None) -> InlineKeyboardMarkup:
"""Клавиатура выбора языка интерфейса"""
lang = get_user_lang(user)
keyboard = InlineKeyboardMarkup(inline_keyboard=[
[InlineKeyboardButton(text=t(lang, 'settings.lang_name.ru'), callback_data="set_lang_ru")],
[InlineKeyboardButton(text=t(lang, 'settings.lang_name.en'), callback_data="set_lang_en")],
[InlineKeyboardButton(text=t(lang, 'settings.lang_name.ja'), callback_data="set_lang_ja")],
[InlineKeyboardButton(text=t(lang, 'settings.back'), callback_data="settings_back")]
])
return keyboard
def get_learning_language_keyboard(user=None) -> InlineKeyboardMarkup:
"""Клавиатура выбора языка изучения"""
lang = get_user_lang(user)
options = [
("en", t(lang, 'settings.learning_lang.en')),
("es", t(lang, 'settings.learning_lang.es')),
("de", t(lang, 'settings.learning_lang.de')),
("fr", t(lang, 'settings.learning_lang.fr')),
("ja", t(lang, 'settings.learning_lang.ja')),
]
keyboard = [[InlineKeyboardButton(text=label, callback_data=f"set_learning_{code}")] for code, label in options]
keyboard.append([InlineKeyboardButton(text=t(lang, 'settings.back'), callback_data="settings_back")])
return InlineKeyboardMarkup(inline_keyboard=keyboard)
@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(t('ru', 'common.start_first'))
return
lang = get_user_lang(user)
ui_lang_code = getattr(user, 'language_interface', 'ru') or 'ru'
lang_value = t(lang, f'settings.lang_name.{ui_lang_code}')
current_level = get_user_level_for_language(user)
settings_text = (
t(lang, 'settings.title') +
t(lang, 'settings.level_prefix') + f"{current_level}\n" +
t(lang, 'settings.interface_prefix') + f"{lang_value}\n\n" +
t(lang, 'settings.choose')
)
await message.answer(settings_text, reply_markup=get_settings_keyboard(user))
@router.callback_query(F.data == "settings_level")
async def settings_level(callback: CallbackQuery):
"""Показать выбор уровня"""
async with async_session_maker() as session:
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
lang = get_user_lang(user)
learning_lang = getattr(user, 'learning_language', 'en') or 'en'
level_system = get_level_system(learning_lang)
# Выбираем правильное описание групп уровней
groups_key = 'settings.jlpt_groups' if level_system == 'jlpt' else 'settings.level_groups'
text = t(lang, 'settings.level_title') + t(lang, groups_key) + t(lang, 'settings.level_hint')
await callback.message.edit_text(text, 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 = get_user_lang(user)
await callback.message.edit_text(t(lang, 'settings.learning_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 = get_user_lang(user)
text = t(lang, 'settings.learning_changed', code=code.upper())
await callback.message.edit_text(
text,
reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text=t(lang, 'settings.back_to_settings'), callback_data="settings_back")]])
)
await callback.answer()
@router.callback_query(F.data.startswith("set_level_"))
async def set_level(callback: CallbackQuery):
"""Установить уровень (CEFR или JLPT)"""
level_str = callback.data.split("_")[-1] # A1, A2, B1, B2, C1, C2 или N5, N4, N3, N2, N1
async with async_session_maker() as session:
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
if user:
# Передаём строковый уровень, UserService сам разберётся с системой
await UserService.update_user_level(session, user.id, level_str)
lang = get_user_lang(user)
msg = t(lang, 'settings.level_changed', level=level_str) + t(lang, 'settings.level_changed_hint')
await callback.message.edit_text(
msg,
reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text=t(lang, 'settings.back_to_settings'), callback_data="settings_back")]])
)
await callback.answer()
@router.callback_query(F.data == "settings_language")
async def settings_language(callback: CallbackQuery):
"""Показать выбор языка"""
async with async_session_maker() as session:
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
lang = get_user_lang(user)
await callback.message.edit_text(
t(lang, 'settings.lang_title') + t(lang, 'settings.lang_desc'),
reply_markup=get_language_keyboard(user)
)
await callback.answer()
@router.callback_query(F.data.startswith("set_lang_"))
async def set_language(callback: CallbackQuery):
"""Установить язык"""
new_lang = callback.data.split("_")[-1] # ru | en | ja
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, new_lang)
# Используем новый язык для сообщений
text = t(new_lang, 'settings.lang_changed')
await callback.message.edit_text(
text,
reply_markup=InlineKeyboardMarkup(inline_keyboard=[[InlineKeyboardButton(text=t(new_lang, 'settings.back'), callback_data="settings_back")]])
)
# Обновляем клавиатуру чата на выбранный язык
await callback.message.answer(t(new_lang, 'settings.menu_updated'), reply_markup=main_menu_keyboard(new_lang))
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:
lang = get_user_lang(user)
ui_lang_code = getattr(user, 'language_interface', 'ru') or 'ru'
lang_value = t(lang, f'settings.lang_name.{ui_lang_code}')
current_level = get_user_level_for_language(user)
settings_text = (
t(lang, 'settings.title') +
t(lang, 'settings.level_prefix') + f"{current_level}\n" +
t(lang, 'settings.interface_prefix') + f"{lang_value}\n\n" +
t(lang, 'settings.choose')
)
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()