- Added `bot_username` to settings for dynamic retrieval of the bot's username. - Implemented `_resolve_bot_username` function to fetch the bot's username if not set, improving user experience in group chats. - Updated `DutyWithUser` schema to include optional `phone` and `username` fields for enhanced duty information. - Enhanced API responses to include contact details for users, ensuring better communication. - Introduced a new current duty view in the web app, displaying active duty information along with contact options. - Updated CSS styles for better presentation of contact information in duty cards. - Added unit tests to verify the inclusion of contact details in API responses and the functionality of the current duty view.
181 lines
14 KiB
Python
181 lines
14 KiB
Python
"""Translation dictionaries: MESSAGES[lang][key]. Keys: dotted, e.g. start.greeting."""
|
||
|
||
MESSAGES: dict[str, dict[str, str]] = {
|
||
"en": {
|
||
"start.greeting": "Hi! I'm the duty calendar bot. Use /help for the command list.",
|
||
"set_phone.private_only": "The /set_phone command is only available in private chat.",
|
||
"set_phone.saved": "Phone saved: {phone}",
|
||
"set_phone.cleared": "Phone cleared.",
|
||
"set_phone.error": "Error saving.",
|
||
"help.title": "Available commands:",
|
||
"help.start": "/start — Start",
|
||
"help.help": "/help — Show this help",
|
||
"help.set_phone": "/set_phone — Set or clear phone for duty display",
|
||
"help.calendar_link": "/calendar_link — Get personal calendar subscription link (private chat)",
|
||
"help.pin_duty": "/pin_duty — In a group: pin the duty message (bot needs admin with Pin messages)",
|
||
"help.refresh_pin": "/refresh_pin — In a group: refresh pinned duty message text immediately",
|
||
"refresh_pin.group_only": "The /refresh_pin command works only in groups.",
|
||
"refresh_pin.no_message": "There is no pinned duty message to refresh in this chat.",
|
||
"refresh_pin.updated": "Pinned duty message updated.",
|
||
"refresh_pin.failed": "Could not update the pinned message (permissions or edit error).",
|
||
"refresh_pin.untrusted": "Group was removed from trusted list; pin record cleared.",
|
||
"trust_group.added": "Group added to trusted list.",
|
||
"trust_group.already_trusted": "This group is already trusted.",
|
||
"trust_group.group_only": "The /trust_group command works only in groups.",
|
||
"untrust_group.removed": "Group removed from trusted list.",
|
||
"untrust_group.not_trusted": "This group is not in the trusted list.",
|
||
"untrust_group.group_only": "The /untrust_group command works only in groups.",
|
||
"group.not_trusted": (
|
||
"This group is not authorized to receive duty data. "
|
||
"An administrator can add the group with /trust_group."
|
||
),
|
||
"help.trust_group": "/trust_group — In a group: add group to trusted list (admin only)",
|
||
"help.untrust_group": "/untrust_group — In a group: remove group from trusted list (admin only)",
|
||
"calendar_link.private_only": "The /calendar_link command is only available in private chat.",
|
||
"calendar_link.access_denied": "Access denied.",
|
||
"calendar_link.success": (
|
||
"Personal (your duties only):\n{url_personal}\n\n"
|
||
"Team (all duties):\n{url_team}"
|
||
),
|
||
"calendar_link.help_hint": (
|
||
"Subscribe to these URLs in Google Calendar, Apple Calendar, or Outlook."
|
||
),
|
||
"calendar_link.error": "Could not generate link. Please try again later.",
|
||
"help.import_schedule": "/import_duty_schedule — Import duty schedule (JSON)",
|
||
"help.set_role": "/set_role — Set user role (user | admin)",
|
||
"set_role.usage": "Usage: /set_role @username user|admin or reply to a message and send /set_role user|admin",
|
||
"set_role.user_not_found": "User not found.",
|
||
"set_role.done": "Role set: {name} → {role}",
|
||
"set_role.error": "Could not set role.",
|
||
"errors.generic": "An error occurred. Please try again later.",
|
||
"pin_duty.group_only": "The /pin_duty command works only in groups.",
|
||
"pin_duty.no_message": "There is no duty message in this chat yet. Add the bot to the group — it will create one automatically.",
|
||
"pin_duty.pinned": "Duty message pinned.",
|
||
"pin_duty.failed": (
|
||
"Could not pin. Make sure the bot is an administrator with "
|
||
"«Pin messages» permission."
|
||
),
|
||
"pin_duty.could_not_pin_make_admin": (
|
||
"Duty message was sent but could not be pinned. Make the bot an "
|
||
"administrator with «Pin messages» permission, then send /pin_duty in the "
|
||
"chat — the current message will be pinned."
|
||
),
|
||
"pin_duty.view_contacts": "View contacts",
|
||
"duty.no_duty": "No duty at the moment.",
|
||
"duty.label": "Duty:",
|
||
"import.admin_only": "Access for administrators only.",
|
||
"import.handover_format": (
|
||
"Enter handover time as HH:MM and timezone, e.g. 09:00 Europe/Moscow or "
|
||
"06:00 UTC."
|
||
),
|
||
"import.parse_time_error": "Could not parse time. Enter e.g.: 09:00 Europe/Moscow",
|
||
"import.send_json": "Send the duty-schedule file (JSON).",
|
||
"import.need_json": "File must have .json extension.",
|
||
"import.parse_error": "File parse error: {error}",
|
||
"import.import_error": "Import error: {error}",
|
||
"import.done": (
|
||
"Import done: {users} users, {duties} duties{unavailable}{vacation} "
|
||
"({total} events total)."
|
||
),
|
||
"import.done_unavailable": ", {count} unavailable",
|
||
"import.done_vacation": ", {count} vacation",
|
||
"api.open_from_telegram": "Open the calendar from Telegram",
|
||
"api.auth_bad_signature": (
|
||
"Invalid signature. Ensure BOT_TOKEN on the server matches the bot from "
|
||
"which the calendar was opened (same bot as in the menu)."
|
||
),
|
||
"api.auth_invalid": "Invalid auth data",
|
||
"api.access_denied": "Access denied",
|
||
"dates.bad_format": "Parameters from and to must be in YYYY-MM-DD format",
|
||
"dates.from_after_to": "from date must not be after to",
|
||
"contact.show": "Contacts",
|
||
"contact.back": "Back",
|
||
"current_duty.title": "Current Duty",
|
||
"current_duty.no_duty": "No one is on duty right now",
|
||
"current_duty.shift": "Shift",
|
||
"current_duty.back": "Back to calendar",
|
||
},
|
||
"ru": {
|
||
"start.greeting": "Привет! Я бот календаря дежурств. Используй /help для списка команд.",
|
||
"set_phone.private_only": "Команда /set_phone доступна только в личке.",
|
||
"set_phone.saved": "Телефон сохранён: {phone}",
|
||
"set_phone.cleared": "Телефон очищен.",
|
||
"set_phone.error": "Ошибка сохранения.",
|
||
"help.title": "Доступные команды:",
|
||
"help.start": "/start — Начать",
|
||
"help.help": "/help — Показать эту справку",
|
||
"help.set_phone": "/set_phone — Указать или очистить телефон для отображения в дежурстве",
|
||
"help.calendar_link": "/calendar_link — Получить ссылку на персональную подписку календаря (только в личке)",
|
||
"help.pin_duty": "/pin_duty — В группе: закрепить сообщение о дежурстве (нужны права админа у бота)",
|
||
"help.refresh_pin": "/refresh_pin — В группе: немедленно обновить текст закреплённого сообщения о дежурстве",
|
||
"refresh_pin.group_only": "Команда /refresh_pin работает только в группах.",
|
||
"refresh_pin.no_message": "В этом чате нет закреплённого сообщения о дежурстве для обновления.",
|
||
"refresh_pin.updated": "Закреплённое сообщение о дежурстве обновлено.",
|
||
"refresh_pin.failed": "Не удалось обновить закреплённое сообщение (права или ошибка редактирования).",
|
||
"refresh_pin.untrusted": "Группа удалена из доверенных; запись о закреплении сброшена.",
|
||
"trust_group.added": "Группа добавлена в доверенные.",
|
||
"trust_group.already_trusted": "Эта группа уже в доверенных.",
|
||
"trust_group.group_only": "Команда /trust_group работает только в группах.",
|
||
"untrust_group.removed": "Группа удалена из доверенных.",
|
||
"untrust_group.not_trusted": "Эта группа не в доверенных.",
|
||
"untrust_group.group_only": "Команда /untrust_group работает только в группах.",
|
||
"group.not_trusted": (
|
||
"Эта группа не авторизована для получения данных дежурных. "
|
||
"Администратор может добавить группу командой /trust_group."
|
||
),
|
||
"help.trust_group": "/trust_group — В группе: добавить группу в доверенные (только админ)",
|
||
"help.untrust_group": "/untrust_group — В группе: удалить группу из доверенных (только админ)",
|
||
"calendar_link.private_only": "Команда /calendar_link доступна только в личке.",
|
||
"calendar_link.access_denied": "Доступ запрещён.",
|
||
"calendar_link.success": (
|
||
"Персональный (только ваши дежурства):\n{url_personal}\n\n"
|
||
"Общий (все дежурства):\n{url_team}"
|
||
),
|
||
"calendar_link.help_hint": (
|
||
"Подпишитесь на эти ссылки в Google Календаре, Календаре Apple или Outlook."
|
||
),
|
||
"calendar_link.error": "Не удалось сформировать ссылку. Попробуйте позже.",
|
||
"help.import_schedule": "/import_duty_schedule — Импорт расписания дежурств (JSON)",
|
||
"help.set_role": "/set_role — Выдать роль пользователю (user | admin)",
|
||
"set_role.usage": "Использование: /set_role @username user|admin или ответьте на сообщение и отправьте /set_role user|admin",
|
||
"set_role.user_not_found": "Пользователь не найден.",
|
||
"set_role.done": "Роль установлена: {name} → {role}",
|
||
"set_role.error": "Не удалось установить роль.",
|
||
"errors.generic": "Произошла ошибка. Попробуйте позже.",
|
||
"pin_duty.group_only": "Команда /pin_duty работает только в группах.",
|
||
"pin_duty.no_message": "В этом чате ещё нет сообщения о дежурстве. Добавьте бота в группу — оно создастся автоматически.",
|
||
"pin_duty.pinned": "Сообщение о дежурстве закреплено.",
|
||
"pin_duty.failed": "Не удалось закрепить. Убедитесь, что бот — администратор с правом «Закреплять сообщения».",
|
||
"pin_duty.could_not_pin_make_admin": "Сообщение о дежурстве отправлено, но закрепить его не удалось. "
|
||
"Сделайте бота администратором с правом «Закреплять сообщения» (Pin messages), "
|
||
"затем отправьте в чат команду /pin_duty — текущее сообщение будет закреплено.",
|
||
"pin_duty.view_contacts": "Контакты",
|
||
"duty.no_duty": "Сейчас дежурства нет.",
|
||
"duty.label": "Дежурство:",
|
||
"import.admin_only": "Доступ только для администраторов.",
|
||
"import.handover_format": "Укажите время пересменки в формате ЧЧ:ММ и часовой пояс, "
|
||
"например 09:00 Europe/Moscow или 06:00 UTC.",
|
||
"import.parse_time_error": "Не удалось разобрать время. Укажите, например: 09:00 Europe/Moscow",
|
||
"import.send_json": "Отправьте файл в формате duty-schedule (JSON).",
|
||
"import.need_json": "Нужен файл с расширением .json",
|
||
"import.parse_error": "Ошибка разбора файла: {error}",
|
||
"import.import_error": "Ошибка импорта: {error}",
|
||
"import.done": "Импорт выполнен: {users} пользователей, {duties} дежурств{unavailable}{vacation} (всего {total} событий).",
|
||
"import.done_unavailable": ", {count} недоступностей",
|
||
"import.done_vacation": ", {count} отпусков",
|
||
"api.open_from_telegram": "Откройте календарь из Telegram",
|
||
"api.auth_bad_signature": "Неверная подпись. Убедитесь, что BOT_TOKEN на сервере совпадает с токеном бота, "
|
||
"из которого открыт календарь (тот же бот, что в меню).",
|
||
"api.auth_invalid": "Неверные данные авторизации",
|
||
"api.access_denied": "Доступ запрещён",
|
||
"dates.bad_format": "Параметры from и to должны быть в формате YYYY-MM-DD",
|
||
"dates.from_after_to": "Дата from не должна быть позже to",
|
||
"contact.show": "Контакты",
|
||
"contact.back": "Назад",
|
||
"current_duty.title": "Текущее дежурство",
|
||
"current_duty.no_duty": "Сейчас никто не дежурит",
|
||
"current_duty.shift": "Смена",
|
||
"current_duty.back": "Назад к календарю",
|
||
},
|
||
}
|