feat(i18n): localize start/help/menu, practice, words, import, reminder, vocabulary, tasks/stats for RU/EN/JA; add JSON-based i18n helper\n\nfeat(lang): support learning/translation languages across AI flows; hide translations with buttons; store examples per lang\n\nfeat(vocab): add source_lang and translation_lang to Vocabulary, unique constraint (user_id, source_lang, word_original); filter /vocabulary by user.learning_language\n\nchore(migrations): add Alembic setup + migration to add vocab lang columns; env.py reads app settings and supports asyncpg URLs\n\nfix(words/import): pass learning_lang + translation_lang everywhere; fix menu themes generation\n\nfeat(settings): add learning language selector; update main menu on language change
This commit is contained in:
@@ -6,6 +6,7 @@ from aiogram.fsm.state import State, StatesGroup
|
||||
|
||||
from database.db import async_session_maker
|
||||
from services.user_service import UserService
|
||||
from utils.i18n import t
|
||||
|
||||
router = Router()
|
||||
|
||||
@@ -22,19 +23,19 @@ async def cmd_reminder(message: Message):
|
||||
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
|
||||
|
||||
if not user:
|
||||
await message.answer("Сначала запусти бота командой /start")
|
||||
await message.answer(t('ru', 'common.start_first'))
|
||||
return
|
||||
|
||||
# Формируем текст
|
||||
status = "✅ Включены" if user.reminders_enabled else "❌ Выключены"
|
||||
time_text = user.daily_task_time if user.daily_task_time else "Не установлено"
|
||||
lang = (user.language_interface if user else 'ru') or 'ru'
|
||||
status = t(lang, 'reminder.status_on') if user.reminders_enabled else t(lang, 'reminder.status_off')
|
||||
time_text = user.daily_task_time if user.daily_task_time else t(lang, 'reminder.time_not_set')
|
||||
|
||||
text = (
|
||||
f"⏰ <b>Напоминания</b>\n\n"
|
||||
f"Статус: {status}\n"
|
||||
f"Время: {time_text} UTC\n\n"
|
||||
f"Напоминания помогут не забывать о ежедневной практике.\n"
|
||||
f"Бот будет присылать сообщение в выбранное время каждый день."
|
||||
t(lang, 'reminder.title') + "\n\n" +
|
||||
t(lang, 'reminder.status_line', status=status) + "\n" +
|
||||
t(lang, 'reminder.time_line', time=time_text) + "\n\n" +
|
||||
t(lang, 'reminder.desc1') + "\n" +
|
||||
t(lang, 'reminder.desc2')
|
||||
)
|
||||
|
||||
# Создаем кнопки
|
||||
@@ -42,15 +43,15 @@ async def cmd_reminder(message: Message):
|
||||
|
||||
if user.reminders_enabled:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton(text="❌ Выключить", callback_data="reminder_disable")
|
||||
InlineKeyboardButton(text=t(lang, 'reminder.btn_disable'), callback_data="reminder_disable")
|
||||
])
|
||||
else:
|
||||
keyboard.append([
|
||||
InlineKeyboardButton(text="✅ Включить", callback_data="reminder_enable")
|
||||
InlineKeyboardButton(text=t(lang, 'reminder.btn_enable'), callback_data="reminder_enable")
|
||||
])
|
||||
|
||||
keyboard.append([
|
||||
InlineKeyboardButton(text="⏰ Изменить время", callback_data="reminder_set_time")
|
||||
InlineKeyboardButton(text=t(lang, 'reminder.btn_change_time'), callback_data="reminder_set_time")
|
||||
])
|
||||
|
||||
reply_markup = InlineKeyboardMarkup(inline_keyboard=keyboard)
|
||||
@@ -65,7 +66,7 @@ async def enable_reminders(callback: CallbackQuery):
|
||||
|
||||
if not user.daily_task_time:
|
||||
await callback.answer(
|
||||
"Сначала установи время напоминаний!",
|
||||
t(user.language_interface or 'ru', 'reminder.set_time_first'),
|
||||
show_alert=True
|
||||
)
|
||||
return
|
||||
@@ -73,11 +74,12 @@ async def enable_reminders(callback: CallbackQuery):
|
||||
user.reminders_enabled = True
|
||||
await session.commit()
|
||||
|
||||
await callback.answer("✅ Напоминания включены!")
|
||||
lang = (user.language_interface if user else 'ru') or 'ru'
|
||||
await callback.answer(t(lang, 'reminder.enabled_toast'))
|
||||
await callback.message.edit_text(
|
||||
f"✅ <b>Напоминания включены!</b>\n\n"
|
||||
f"Время: {user.daily_task_time} UTC\n\n"
|
||||
f"Ты будешь получать ежедневные напоминания о практике."
|
||||
t(lang, 'reminder.enabled_title') + "\n\n" +
|
||||
t(lang, 'reminder.time_line', time=user.daily_task_time) + "\n\n" +
|
||||
t(lang, 'reminder.enabled_desc')
|
||||
)
|
||||
|
||||
|
||||
@@ -90,10 +92,11 @@ async def disable_reminders(callback: CallbackQuery):
|
||||
user.reminders_enabled = False
|
||||
await session.commit()
|
||||
|
||||
await callback.answer("❌ Напоминания выключены")
|
||||
lang = (user.language_interface if user else 'ru') or 'ru'
|
||||
await callback.answer(t(lang, 'reminder.disabled_toast'))
|
||||
await callback.message.edit_text(
|
||||
"❌ <b>Напоминания выключены</b>\n\n"
|
||||
"Используй /reminder чтобы включить их снова."
|
||||
t(lang, 'reminder.disabled_title') + "\n\n" +
|
||||
t(lang, 'reminder.disabled_desc')
|
||||
)
|
||||
|
||||
|
||||
@@ -102,16 +105,15 @@ async def set_reminder_time_prompt(callback: CallbackQuery, state: FSMContext):
|
||||
"""Запросить время для напоминаний"""
|
||||
await state.set_state(ReminderStates.waiting_for_time)
|
||||
|
||||
async with async_session_maker() as session:
|
||||
user = await UserService.get_user_by_telegram_id(session, callback.from_user.id)
|
||||
lang = (user.language_interface if user else 'ru') or 'ru'
|
||||
await callback.message.edit_text(
|
||||
"⏰ <b>Установка времени напоминаний</b>\n\n"
|
||||
"Отправь время в формате <b>HH:MM</b> (UTC)\n\n"
|
||||
"Примеры:\n"
|
||||
"• <code>09:00</code> - 9 утра по UTC\n"
|
||||
"• <code>18:30</code> - 18:30 по UTC\n"
|
||||
"• <code>20:00</code> - 8 вечера по UTC\n\n"
|
||||
"💡 UTC = МСК - 3 часа\n"
|
||||
"(если хочешь 12:00 по МСК, введи 09:00)\n\n"
|
||||
"Отправь /cancel для отмены"
|
||||
t(lang, 'reminder.set_title') + "\n\n" +
|
||||
t(lang, 'reminder.set_desc') + "\n\n" +
|
||||
t(lang, 'reminder.set_examples') + "\n\n" +
|
||||
t(lang, 'reminder.set_utc_hint') + "\n\n" +
|
||||
t(lang, 'reminder.cancel_hint')
|
||||
)
|
||||
await callback.answer()
|
||||
|
||||
@@ -120,7 +122,7 @@ async def set_reminder_time_prompt(callback: CallbackQuery, state: FSMContext):
|
||||
async def cancel_set_time(message: Message, state: FSMContext):
|
||||
"""Отменить установку времени"""
|
||||
await state.clear()
|
||||
await message.answer("❌ Установка времени отменена")
|
||||
await message.answer(t('ru', 'reminder.cancelled'))
|
||||
|
||||
|
||||
@router.message(ReminderStates.waiting_for_time)
|
||||
@@ -143,11 +145,7 @@ async def process_reminder_time(message: Message, state: FSMContext):
|
||||
formatted_time = f"{hour:02d}:{minute:02d}"
|
||||
|
||||
except:
|
||||
await message.answer(
|
||||
"❌ Неверный формат времени!\n\n"
|
||||
"Используй формат <b>HH:MM</b> (например, 09:00 или 18:30)\n"
|
||||
"Или отправь /cancel для отмены"
|
||||
)
|
||||
await message.answer(t('ru', 'reminder.invalid_format'))
|
||||
return
|
||||
|
||||
# Сохраняем время
|
||||
@@ -163,10 +161,13 @@ async def process_reminder_time(message: Message, state: FSMContext):
|
||||
|
||||
await state.clear()
|
||||
|
||||
async with async_session_maker() as session:
|
||||
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
|
||||
lang = (user.language_interface if user else 'ru') or 'ru'
|
||||
await message.answer(
|
||||
f"✅ <b>Время установлено!</b>\n\n"
|
||||
f"Напоминания: <b>{formatted_time} UTC</b>\n"
|
||||
f"Статус: <b>Включены</b>\n\n"
|
||||
f"Ты будешь получать ежедневные напоминания о практике.\n"
|
||||
f"Используй /reminder для изменения настроек."
|
||||
t(lang, 'reminder.time_set_title') + "\n\n" +
|
||||
t(lang, 'reminder.time_line', time=formatted_time) + "\n" +
|
||||
t(lang, 'reminder.status_on_line') + "\n\n" +
|
||||
t(lang, 'reminder.enabled_desc') + "\n" +
|
||||
t(lang, 'reminder.use_settings')
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user