Add internationalization support and enhance language handling
All checks were successful
CI / lint-and-test (push) Successful in 14s
All checks were successful
CI / lint-and-test (push) Successful in 14s
- Introduced a new i18n module for managing translations and language normalization, supporting both Russian and English. - Updated various handlers and services to utilize the new translation functions for user-facing messages, improving user experience based on language preferences. - Enhanced error handling and response messages to be language-aware, ensuring appropriate feedback is provided to users in their preferred language. - Added tests for the i18n module to validate language detection and translation functionality. - Updated the example environment file to include a default language configuration.
This commit is contained in:
@@ -7,6 +7,7 @@ from telegram import Update
|
||||
from telegram.ext import CommandHandler, ContextTypes, MessageHandler, filters
|
||||
|
||||
from duty_teller.db.session import session_scope
|
||||
from duty_teller.i18n import get_lang, t
|
||||
from duty_teller.importers.duty_schedule import (
|
||||
DutyScheduleParseError,
|
||||
parse_duty_schedule,
|
||||
@@ -20,14 +21,12 @@ async def import_duty_schedule_cmd(
|
||||
) -> None:
|
||||
if not update.message or not update.effective_user:
|
||||
return
|
||||
lang = get_lang(update.effective_user)
|
||||
if not config.is_admin(update.effective_user.username or ""):
|
||||
await update.message.reply_text("Доступ только для администраторов.")
|
||||
await update.message.reply_text(t(lang, "import.admin_only"))
|
||||
return
|
||||
context.user_data["awaiting_handover_time"] = True
|
||||
await update.message.reply_text(
|
||||
"Укажите время пересменки в формате ЧЧ:ММ и часовой пояс, "
|
||||
"например 09:00 Europe/Moscow или 06:00 UTC."
|
||||
)
|
||||
await update.message.reply_text(t(lang, "import.handover_format"))
|
||||
|
||||
|
||||
async def handle_handover_time_text(
|
||||
@@ -39,18 +38,17 @@ async def handle_handover_time_text(
|
||||
return
|
||||
if not config.is_admin(update.effective_user.username or ""):
|
||||
return
|
||||
lang = get_lang(update.effective_user)
|
||||
text = update.message.text.strip()
|
||||
parsed = parse_handover_time(text)
|
||||
if parsed is None:
|
||||
await update.message.reply_text(
|
||||
"Не удалось разобрать время. Укажите, например: 09:00 Europe/Moscow"
|
||||
)
|
||||
await update.message.reply_text(t(lang, "import.parse_time_error"))
|
||||
return
|
||||
hour_utc, minute_utc = parsed
|
||||
context.user_data["handover_utc_time"] = (hour_utc, minute_utc)
|
||||
context.user_data["awaiting_handover_time"] = False
|
||||
context.user_data["awaiting_duty_schedule_file"] = True
|
||||
await update.message.reply_text("Отправьте файл в формате duty-schedule (JSON).")
|
||||
await update.message.reply_text(t(lang, "import.send_json"))
|
||||
|
||||
|
||||
async def handle_duty_schedule_document(
|
||||
@@ -60,11 +58,12 @@ async def handle_duty_schedule_document(
|
||||
return
|
||||
if not context.user_data.get("awaiting_duty_schedule_file"):
|
||||
return
|
||||
lang = get_lang(update.effective_user)
|
||||
handover = context.user_data.get("handover_utc_time")
|
||||
if not handover or not config.is_admin(update.effective_user.username or ""):
|
||||
return
|
||||
if not (update.message.document.file_name or "").lower().endswith(".json"):
|
||||
await update.message.reply_text("Нужен файл с расширением .json")
|
||||
await update.message.reply_text(t(lang, "import.need_json"))
|
||||
return
|
||||
|
||||
hour_utc, minute_utc = handover
|
||||
@@ -77,7 +76,7 @@ async def handle_duty_schedule_document(
|
||||
except DutyScheduleParseError as e:
|
||||
context.user_data.pop("awaiting_duty_schedule_file", None)
|
||||
context.user_data.pop("handover_utc_time", None)
|
||||
await update.message.reply_text(f"Ошибка разбора файла: {e}")
|
||||
await update.message.reply_text(t(lang, "import.parse_error", error=str(e)))
|
||||
return
|
||||
|
||||
def run_import_with_scope():
|
||||
@@ -90,16 +89,29 @@ async def handle_duty_schedule_document(
|
||||
None, run_import_with_scope
|
||||
)
|
||||
except Exception as e:
|
||||
await update.message.reply_text(f"Ошибка импорта: {e}")
|
||||
await update.message.reply_text(t(lang, "import.import_error", error=str(e)))
|
||||
else:
|
||||
total = num_duty + num_unavailable + num_vacation
|
||||
parts = [f"{num_users} пользователей", f"{num_duty} дежурств"]
|
||||
if num_unavailable:
|
||||
parts.append(f"{num_unavailable} недоступностей")
|
||||
if num_vacation:
|
||||
parts.append(f"{num_vacation} отпусков")
|
||||
unavailable_suffix = (
|
||||
t(lang, "import.done_unavailable", count=str(num_unavailable))
|
||||
if num_unavailable
|
||||
else ""
|
||||
)
|
||||
vacation_suffix = (
|
||||
t(lang, "import.done_vacation", count=str(num_vacation))
|
||||
if num_vacation
|
||||
else ""
|
||||
)
|
||||
await update.message.reply_text(
|
||||
"Импорт выполнен: " + ", ".join(parts) + f" (всего {total} событий)."
|
||||
t(
|
||||
lang,
|
||||
"import.done",
|
||||
users=str(num_users),
|
||||
duties=str(num_duty),
|
||||
unavailable=unavailable_suffix,
|
||||
vacation=vacation_suffix,
|
||||
total=str(total),
|
||||
)
|
||||
)
|
||||
finally:
|
||||
context.user_data.pop("awaiting_duty_schedule_file", None)
|
||||
|
||||
Reference in New Issue
Block a user