diff --git a/Dockerfile b/Dockerfile index 9831aa7..a53cfc7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,6 +4,11 @@ ENV PYTHONUNBUFFERED=1 \ POETRY_VERSION=1.1.2 \ POETRY_VIRTUALENVS_CREATE="false" +RUN apt-get update && \ + apt-get install -y gettext build-essential && \ + apt-get clean && rm -rf /var/cache/apt/* && rm -rf /var/lib/apt/lists/* && rm -rf /tmp/* + + RUN pip install "poetry==$POETRY_VERSION" WORKDIR /app @@ -13,6 +18,8 @@ RUN poetry install --no-interaction --no-ansi --no-dev COPY . /app +RUN msgfmt locales/zh/LC_MESSAGES/olgram.po -o locales/zh/LC_MESSAGES/olgram.mo --use-fuzzy + EXPOSE 80 ENTRYPOINT ["./docker-entrypoint.sh"] diff --git a/docker-compose-debug.yaml b/docker-compose-debug.yaml index 16e5cad..4beb41b 100644 --- a/docker-compose-debug.yaml +++ b/docker-compose-debug.yaml @@ -3,7 +3,7 @@ version: '3' services: postgres: - image: postgres:13.4 + image: postgres:14 environment: - POSTGRES_USER=test_user - POSTGRES_PASSWORD=test_passwd diff --git a/locales/locale.py b/locales/locale.py new file mode 100644 index 0000000..e062086 --- /dev/null +++ b/locales/locale.py @@ -0,0 +1,12 @@ +import gettext +from olgram.settings import BotSettings +from os.path import dirname + +locales_dir = dirname(__file__) + +lang = BotSettings.language() +if lang == "ru": + _ = lambda x: x +else: + t = gettext.translation("olgram", localedir=locales_dir, languages=[lang]) + _ = t.gettext diff --git a/locales/zh/LC_MESSAGES/olgram.po b/locales/zh/LC_MESSAGES/olgram.po new file mode 100644 index 0000000..520e009 --- /dev/null +++ b/locales/zh/LC_MESSAGES/olgram.po @@ -0,0 +1,564 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ORGANIZATION +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2022-03-22 04:36+0300\n" +"PO-Revision-Date: 2022-03-22 04:55+0300\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Generated-By: pygettext.py 1.5\n" +"X-Generator: Poedit 3.0\n" +"Last-Translator: \n" +"Plural-Forms: nplurals=1; plural=0;\n" +"Language: zh_CN\n" + +#: olgram/commands/bot_actions.py:21 +msgid "Бот удалён" +msgstr "移除机器人" + +#: olgram/commands/bot_actions.py:37 olgram/commands/bot_actions.py:49 +msgid "Текст сброшен" +msgstr "倾倒的文本" + +#: olgram/commands/bot_actions.py:63 +msgid "Выбран личный чат" +msgstr "选择了私聊" + +#: olgram/commands/bot_actions.py:68 +msgid "Нельзя привязать бота к этому чату" +msgstr "你不能将机器人链接到这个聊天室" + +#: olgram/commands/bot_actions.py:72 +msgid "Выбран чат {0}" +msgstr "聊天选择 {0}" + +#: olgram/commands/bots.py:42 +msgid "У вас уже слишком много ботов." +msgstr "你已经有太多的机器人了。" + +#: olgram/commands/bots.py:45 +msgid "" +"\n" +" Чтобы подключить бот, вам нужно выполнить три действия:\n" +"\n" +" 1. Перейдите в бот @BotFather, нажмите START и отправьте команду /" +"newbot\n" +" 2. Введите название бота, а потом username бота.\n" +" 3. После создания бота перешлите ответное сообщение в этот бот или " +"скопируйте и пришлите token бота.\n" +"\n" +" Важно: не подключайте боты, которые используются в других сервисах " +"(Manybot, Chatfuel, Livegram и других).\n" +" " +msgstr "" +"\n" +" 要连接机器人,你需要遵循三个步骤。\n" +"\n" +" 1. 转到机器人@BotFather,按START键并发送/newbot\n" +" 2. 输入机器人的名字,然后输入机器人的用户名。\n" +" 3. 一旦创建了机器人,就向这个机器人转发一条回复信息,或者复制并发送机器人" +"的令牌。\n" +"\n" +" 重要:不要连接用于其他服务的机器人(Manybot、Chatfuel、Livegram和其" +"他)。\n" +" " + +#: olgram/commands/bots.py:65 +msgid "" +"\n" +" Это не токен бота.\n" +"\n" +" Токен выглядит вот так: 123456789:AAAA-" +"abc123_AbcdEFghijKLMnopqrstu12\n" +" " +msgstr "" +"\n" +" 这不是一个机器人令牌。\n" +"\n" +" 该令牌看起来像这样:123456789:AAAA-abc123_AbcdEFghijKLMnopqrstu12\n" +" " + +#: olgram/commands/bots.py:72 +msgid "" +"\n" +" Не удалось запустить этого бота: неверный токен\n" +" " +msgstr "" +"\n" +" 运行此机器人失败:错误的令牌\n" +" " + +#: olgram/commands/bots.py:77 +msgid "" +"\n" +" Не удалось запустить этого бота: непредвиденная ошибка\n" +" " +msgstr "" +"\n" +" 该机器人无法启动:意外错误\n" +" " + +#: olgram/commands/bots.py:82 +msgid "" +"\n" +" Такой бот уже есть в базе данных\n" +" " +msgstr "" +"\n" +" 这样的机器人已经在数据库中出现了\n" +" " + +#: olgram/commands/bots.py:114 +msgid "Бот добавлен! Список ваших ботов: /mybots" +msgstr "机器人已加入! 你的机器人列表:/mybots" + +#: olgram/commands/info.py:21 +msgid "Недостаточно прав" +msgstr "没有足够的权利" + +#: olgram/commands/info.py:32 +msgid "Количество ботов: {0}\n" +msgstr "机器人的数量。{0}\n" + +#: olgram/commands/info.py:33 +msgid "Количество пользователей (у конструктора): {0}\n" +msgstr "用户的数量(在构造器处)。{0}\n" + +#: olgram/commands/info.py:34 +msgid "Шаблонов ответов: {0}\n" +msgstr "答案模板。{0}\n" + +#: olgram/commands/info.py:35 +msgid "Входящих сообщений у всех ботов: {0}\n" +msgstr "所有的机器人都有传入的信息。{0}\n" + +#: olgram/commands/info.py:36 +msgid "Исходящих сообщений у всех ботов: {0}\n" +msgstr "所有的机器人都有外发信息。{0}\n" + +#: olgram/commands/menu.py:31 +msgid "" +"\n" +" У вас нет добавленных ботов.\n" +"\n" +" Отправьте команду /addbot, чтобы добавить бот.\n" +" " +msgstr "" +"\n" +" 你没有添加任何机器人。\n" +"\n" +" 发送命令/addbot来添加一个机器人。\n" +" " + +#: olgram/commands/menu.py:46 +msgid "Ваши боты" +msgstr "你的机器人" + +#: olgram/commands/menu.py:67 +msgid "Личные сообщения" +msgstr "个人留言" + +#: olgram/commands/menu.py:72 olgram/commands/menu.py:117 +#: olgram/commands/menu.py:143 olgram/commands/menu.py:166 +#: olgram/commands/menu.py:222 +msgid "<< Назад" +msgstr "<< 返回" + +#: olgram/commands/menu.py:78 +msgid "" +"\n" +" Этот бот не добавлен в чаты, поэтому все сообщения будут приходить " +"вам в бот.\n" +" Чтобы подключить чат — добавьте бот @{0} в чат, откройте это меню " +"ещё раз и выберите добавленный чат.\n" +" Если ваш бот состоял в групповом чате до того, как его добавили в " +"Olgram - удалите бота из чата и добавьте\n" +" снова.\n" +" " +msgstr "" +"\n" +" 这个机器人没有被添加到聊天记录中,所以所有的信息都会在机器人中找到" +"你。\n" +" 要连接聊天--将机器人@{0}添加到聊天中,再次打开此菜单并选择添加的聊" +"天。\n" +" 如果你的机器人在添加到Olgram之前是在群组聊天中,请将其从聊天室中删" +"除,然后添加到群组中。\n" +" 再次。\n" +" " + +#: olgram/commands/menu.py:85 +msgid "" +"\n" +" В этом разделе вы можете привязать бота @{0} к чату.\n" +" Выберите чат, куда бот будет пересылать сообщения.\n" +" " +msgstr "" +"\n" +" 在本节中,您可以将@{0}机器人绑定到一个聊天室。\n" +" 选择机器人将转发消息的聊天室。\n" +" " + +#: olgram/commands/menu.py:97 +msgid "Текст" +msgstr "文本" + +#: olgram/commands/menu.py:102 +msgid "Чат" +msgstr "聊天" + +#: olgram/commands/menu.py:107 +msgid "Удалить бот" +msgstr "删除机器人" + +#: olgram/commands/menu.py:112 +msgid "Статистика" +msgstr "统计数据" + +#: olgram/commands/menu.py:121 +msgid "Опции" +msgstr "选择" + +#: olgram/commands/menu.py:126 +msgid "" +"\n" +" Управление ботом @{0}.\n" +"\n" +" Если у вас возникли вопросы по настройке бота, то посмотрите нашу " +"справку /help или напишите нам\n" +" @civsocit_feedback_bot\n" +" " +msgstr "" +"\n" +" 机器人管理@{0}。\n" +"\n" +" 如果你有任何关于机器人配置的问题,请参阅我们的帮助/help或给我们发电子邮" +"件\n" +" @civsocit_feedback_bot\n" +" " + +#: olgram/commands/menu.py:138 +msgid "Да, удалить бот" +msgstr "是的,删除该机器人" + +#: olgram/commands/menu.py:147 +msgid "" +"\n" +" Вы уверены, что хотите удалить бота @{0}?\n" +" " +msgstr "" +"\n" +" 你确定要删除机器人@{0}吗?\n" +" " + +#: olgram/commands/menu.py:156 +msgid "Потоки сообщений" +msgstr "信息流" + +#: olgram/commands/menu.py:161 +msgid "Данные пользователя" +msgstr "用户数据" + +#: olgram/commands/menu.py:171 olgram/commands/menu.py:172 +msgid "включены" +msgstr "包括" + +#: olgram/commands/menu.py:171 olgram/commands/menu.py:172 +msgid "выключены" +msgstr "关闭" + +#: olgram/commands/menu.py:173 +msgid "" +"\n" +" Потоки сообщений: {0}\n" +" Данные пользователя: {1}\n" +" " +msgstr "" +"\n" +" " +"信息流: {0}\n" +" 用户数据: {1}\n" +" " + +#: olgram/commands/menu.py:185 olgram/commands/menu.py:247 +#: olgram/commands/menu.py:289 +msgid "<< Завершить редактирование" +msgstr "<< 完成编辑" + +#: olgram/commands/menu.py:189 +msgid "Автоответчик" +msgstr "答录机" + +#: olgram/commands/menu.py:194 olgram/commands/menu.py:261 +msgid "Сбросить текст" +msgstr "重置文本" + +#: olgram/commands/menu.py:199 +msgid "" +"\n" +" Сейчас вы редактируете текст, который отправляется после того, как " +"пользователь отправит вашему боту @{0}\n" +" команду /start\n" +"\n" +" Текущий текст:\n" +"
\n"
+"    {1}\n"
+"    
\n" +" Отправьте сообщение, чтобы изменить текст.\n" +" " +msgstr "" +"\n" +" 你现在正在编辑用户向你的机器人发送@{0}之后的文本。\n" +" /启动命令\n" +"\n" +" 目前的文本。\n" +"
\n"
+"    {1}\n"
+"    
。\n" +" 发送消息,改变文本。\n" +" " + +#: olgram/commands/menu.py:226 +msgid "" +"\n" +" Статистика по боту @{0}\n" +"\n" +" Входящих сообщений: {1}\n" +" Ответных сообщений: {2}\n" +" Шаблоны ответов: {3}\n" +" Забанено пользователей: {4}\n" +" " +msgstr "" +"\n" +" 机器人统计 @{0}\n" +"\n" +" 收到的信息: {1}\n" +" 回复信息: {2}\n" +" 答案模板: {3}\n" +" 被禁止的用户: {4}\n" +" " + +#: olgram/commands/menu.py:251 +msgid "Предыдущий текст" +msgstr "" + +#: olgram/commands/menu.py:256 +msgid "Шаблоны ответов..." +msgstr "回答模板..." + +#: olgram/commands/menu.py:266 +msgid "" +"\n" +" Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в " +"ответ на все входящие сообщения @{0} автоматически. По умолчанию оно " +"отключено.\n" +"\n" +" Текущий текст:\n" +"
\n"
+"    {1}\n"
+"    
\n" +" Отправьте сообщение, чтобы изменить текст.\n" +" " +msgstr "" +"\n" +" 你现在正在编辑自动回复的文本。该信息会自动响应所有收到的@{0}信息而发送。" +"默认情况下,它是禁用的。\n" +"\n" +" 目前的文本。\n" +"
\n"
+"    {1}\n"
+"    
。\n" +" 发送消息,改变文本。\n" +" " + +#: olgram/commands/menu.py:276 +msgid "(отключено)" +msgstr "(关闭)" + +#: olgram/commands/menu.py:293 +msgid "" +"\n" +" Сейчас вы редактируете шаблоны ответов для @{0}. Текущие шаблоны:\n" +"\n" +"
\n"
+"    {1}\n"
+"    
\n" +" Отправьте какую-нибудь фразу (например: \"Ваш заказ готов, ожидайте!\"), " +"чтобы добавить её в шаблон.\n" +" Чтобы удалить шаблон из списка, отправьте его номер в списке (например, " +"4)\n" +" " +msgstr "" +"\n" +" 你现在正在编辑@{0}的答案模板。目前的模板。\n" +"\n" +"
\n"
+"    {1}\n"
+"    
。\n" +" 发送一个短语(例如:\"您的订单已准备好,请等待!\"),将其添加到模板" +"中。\n" +" 要从列表中删除一个模板,请发送它在列表中的编号(如4)。\n" +" " + +#: olgram/commands/menu.py:312 +msgid "(нет шаблонов)" +msgstr "(没有模板)" + +#: olgram/commands/menu.py:351 +msgid "У вас нет шаблонов, чтобы их удалять" +msgstr "你没有模板来删除它们" + +#: olgram/commands/menu.py:353 +msgid "Неправильное число. Чтобы удалить шаблон, введите число от 0 до {0}" +msgstr "不正确的数字。要删除一个模式,请在0和{0}之间输入一个数字。" + +#: olgram/commands/menu.py:361 +msgid "У вашего бота уже слишком много шаблонов" +msgstr "你的机器人已经有太多的模式了" + +#: olgram/commands/menu.py:365 +msgid "Такой текст уже есть в списке шаблонов" +msgstr "此文本已在模板列表中" + +#: olgram/commands/menu.py:383 +msgid "У вас нет прав на этого бота" +msgstr "你对这个机器人没有任何权利" + +#: olgram/commands/start.py:23 +msgid "" +"\n" +" Olgram Bot — это конструктор ботов обратной связи в Telegram. Подробнее " +"читайте здесь.\n" +"\n" +" Используйте эти команды, чтобы управлять этим ботом:\n" +"\n" +" /addbot - добавить бот\n" +" /mybots - управление ботами\n" +"\n" +" /help - помощь\n" +" " +msgstr "" +"\n" +" Olgram Bot — 是一个Telegram反馈机器人的构建者。阅读更多 在此阅读.\n" +"\n" +" 使用这些命令来控制这个机器人:\n" +"\n" +" /addbot - 捆绑\n" +" /mybots - 机器人控制\n" +"\n" +" /help - 帮助\n" +" " + +#: olgram/commands/start.py:42 +msgid "" +"\n" +" Читайте инструкции на нашем сайте https://olgram.readthedocs.io\n" +" Техническая поддержка: @civsocit_feedback_bot\n" +" Версия {0}\n" +" " +msgstr "" +"\n" +" 请阅读我们网站上的说明 https://olgram.readthedocs.io\n" +" 技术支持。@civsocit_feedback_bot\n" +" 版本{0}\n" +" " + +#: olgram/models/models.py:30 +msgid "" +"\n" +" Здравствуйте!\n" +" Напишите ваш вопрос и мы ответим вам в ближайшее время.\n" +" " +msgstr "" +"\n" +" 你好!\n" +" 请写下您的问题,我们将很快给您答复。\n" +" " + +#: olgram/utils/permissions.py:40 +msgid "Владелец бота ограничил доступ к этому функционалу 😞" +msgstr "机器人所有者已经限制了对该功能的访问 😞" + +#: olgram/utils/permissions.py:52 +msgid "Владелец бота ограничил доступ к этому функционалу😞" +msgstr "机器人主人限制了对该功能的访问😞。" + +#: server/custom.py:40 +msgid "" +"Политика конфиденциальности\n" +"\n" +"Этот бот не хранит ваши сообщения, имя пользователя и @username. При " +"отправке сообщения (кроме команд /start и /security_policy) ваш " +"идентификатор пользователя записывается в кеш на некоторое время и потом " +"удаляется из кеша. Этот идентификатор используется только для общения с " +"оператором; боты Olgram не делают массовых рассылок.\n" +"\n" +msgstr "" +"隐私政策видит ваши имя пользователя, @username и идентификатор пользователя в " +"силу настроек, которые оператор указал при создании бота." +msgstr "" +"当发送消息时(除了/start和/security_policy),操作者看到你的用户名、@" +"用户名和用户ID,凭借的是操作者在创建机器人时指定的设置。" + +#: server/custom.py:50 +msgid "" +"В зависимости от ваших настроек конфиденциальности Telegram, оператор может " +"видеть ваш username, имя пользователя и другую информацию." +msgstr "" +"根据你的Telegram隐私设置,运营商可能会看到你的用户名,用户名和其他信息。" + +#: server/custom.py:61 +msgid "Сообщение от пользователя " +msgstr "用户的信息 " + +#: server/custom.py:88 +msgid "Вы заблокированы в этом боте" +msgstr "你在这个机器人中被封锁了" + +#: server/custom.py:128 +msgid "" +"Невозможно переслать сообщение: автор не найден (сообщение слишком " +"старое?)" +msgstr "无法转发信息:找不到作者(信息太旧?)" + +#: server/custom.py:136 +msgid "Пользователь заблокирован" +msgstr "用户被封锁了" + +#: server/custom.py:141 +msgid "Пользователь не был забанен" +msgstr "该用户没有被禁止" + +#: server/custom.py:144 +msgid "Пользователь разбанен" +msgstr "解禁的用户" + +#: server/custom.py:149 +msgid "Невозможно переслать сообщение (автор заблокировал бота?)" +msgstr "无法转发该信息(作者已经屏蔽了机器人?)" + +#: server/server.py:41 +msgid "(Пере)запустить бота" +msgstr "(重新)启动机器人" + +#: server/server.py:42 +msgid "Политика конфиденциальности" +msgstr "隐私政策" diff --git a/main.py b/main.py index e72eb33..80d7c90 100644 --- a/main.py +++ b/main.py @@ -12,6 +12,7 @@ import olgram.commands.start # noqa: F401 import olgram.commands.menu # noqa: F401 import olgram.commands.bot_actions # noqa: F401 import olgram.commands.info # noqa: F401 +from locales.locale import _ from server.server import main as server_main @@ -26,10 +27,10 @@ async def init_olgram(): from aiogram.types import BotCommand await bot.set_my_commands( [ - BotCommand("start", "Запустить бота"), - BotCommand("addbot", "Добавить бот"), - BotCommand("mybots", "Управление ботами"), - BotCommand("help", "Справка") + BotCommand("start", _("Запустить бота")), + BotCommand("addbot", _("Добавить бот")), + BotCommand("mybots", _("Управление ботами")), + BotCommand("help", _("Справка")) ] ) diff --git a/olgram/commands/bot_actions.py b/olgram/commands/bot_actions.py index 7d00b3a..d7ad67a 100644 --- a/olgram/commands/bot_actions.py +++ b/olgram/commands/bot_actions.py @@ -5,6 +5,7 @@ from aiogram import types from aiogram.utils.exceptions import TelegramAPIError, Unauthorized from olgram.models.models import Bot from server.server import unregister_token +from locales.locale import _ async def delete_bot(bot: Bot, call: types.CallbackQuery): @@ -17,7 +18,7 @@ async def delete_bot(bot: Bot, call: types.CallbackQuery): # Вероятно пользователь сбросил токен или удалил бот, это уже не наши проблемы pass await bot.delete() - await call.answer("Бот удалён") + await call.answer(_("Бот удалён")) try: await call.message.delete() except TelegramAPIError: @@ -33,7 +34,7 @@ async def reset_bot_text(bot: Bot, call: types.CallbackQuery): """ bot.start_text = bot._meta.fields_map['start_text'].default await bot.save() - await call.answer("Текст сброшен") + await call.answer(_("Текст сброшен")) async def reset_bot_second_text(bot: Bot, call: types.CallbackQuery): @@ -45,7 +46,7 @@ async def reset_bot_second_text(bot: Bot, call: types.CallbackQuery): """ bot.second_text = bot._meta.fields_map['second_text'].default await bot.save() - await call.answer("Текст сброшен") + await call.answer(_("Текст сброшен")) async def select_chat(bot: Bot, call: types.CallbackQuery, chat: str): @@ -59,16 +60,16 @@ async def select_chat(bot: Bot, call: types.CallbackQuery, chat: str): if chat == "personal": bot.group_chat = None await bot.save() - await call.answer("Выбран личный чат") + await call.answer(_("Выбран личный чат")) return chat_obj = await bot.group_chats.filter(id=chat).first() if not chat_obj: - await call.answer("Нельзя привязать бота к этому чату") + await call.answer(_("Нельзя привязать бота к этому чату")) return bot.group_chat = chat_obj await bot.save() - await call.answer(f"Выбран чат {chat_obj.name}") + await call.answer(_("Выбран чат {0}").format(chat_obj.name)) async def threads(bot: Bot, call: types.CallbackQuery): diff --git a/olgram/commands/bots.py b/olgram/commands/bots.py index 9f2f5c6..a46d5b0 100644 --- a/olgram/commands/bots.py +++ b/olgram/commands/bots.py @@ -12,6 +12,7 @@ from olgram.models.models import Bot, User from olgram.settings import OlgramSettings from olgram.commands.menu import send_bots_menu from server.server import register_token +from locales.locale import _ from olgram.router import dp @@ -38,10 +39,10 @@ async def add_bot(message: types.Message, state: FSMContext): """ bot_count = await Bot.filter(owner__telegram_id=message.from_user.id).count() if bot_count >= OlgramSettings.max_bots_per_user(): - await message.answer("У вас уже слишком много ботов.") + await message.answer(_("У вас уже слишком много ботов.")) return - await message.answer(dedent(""" + await message.answer(dedent(_(""" Чтобы подключить бот, вам нужно выполнить три действия: 1. Перейдите в бот @BotFather, нажмите START и отправьте команду /newbot @@ -49,7 +50,7 @@ async def add_bot(message: types.Message, state: FSMContext): 3. После создания бота перешлите ответное сообщение в этот бот или скопируйте и пришлите token бота. Важно: не подключайте боты, которые используются в других сервисах (Manybot, Chatfuel, Livegram и других). - """)) + """))) await state.set_state("add_bot") @@ -61,26 +62,26 @@ async def bot_added(message: types.Message, state: FSMContext): token = re.findall(token_pattern, message.text) async def on_invalid_token(): - await message.answer(dedent(""" + await message.answer(dedent(_(""" Это не токен бота. Токен выглядит вот так: 123456789:AAAA-abc123_AbcdEFghijKLMnopqrstu12 - """)) + """))) async def on_dummy_token(): - await message.answer(dedent(""" + await message.answer(dedent(_(""" Не удалось запустить этого бота: неверный токен - """)) + """))) async def on_unknown_error(): - await message.answer(dedent(""" + await message.answer(dedent(_(""" Не удалось запустить этого бота: непредвиденная ошибка - """)) + """))) async def on_duplication_bot(): - await message.answer(dedent(""" + await message.answer(dedent(_(""" Такой бот уже есть в базе данных - """)) + """))) if not token: return await on_invalid_token() @@ -98,7 +99,7 @@ async def bot_added(message: types.Message, state: FSMContext): except TelegramAPIError: return await on_unknown_error() - user, _ = await User.get_or_create(telegram_id=message.from_user.id) + user, created = await User.get_or_create(telegram_id=message.from_user.id) bot = Bot(token=Bot.encrypted_token(token), owner=user, name=test_bot_info.username, super_chat_id=message.from_user.id) try: @@ -110,5 +111,5 @@ async def bot_added(message: types.Message, state: FSMContext): await bot.delete() return await on_unknown_error() - await message.answer("Бот добавлен! Список ваших ботов: /mybots") + await message.answer(_("Бот добавлен! Список ваших ботов: /mybots")) await state.reset_state() diff --git a/olgram/commands/info.py b/olgram/commands/info.py index 330451c..c6513f0 100644 --- a/olgram/commands/info.py +++ b/olgram/commands/info.py @@ -8,6 +8,7 @@ from olgram.models import models from olgram.router import dp from olgram.settings import OlgramSettings +from locales.locale import _ @dp.message_handler(commands=["info"], state="*") @@ -17,7 +18,7 @@ async def info(message: types.Message, state: FSMContext): """ if message.chat.id != OlgramSettings.supervisor_id(): - await message.answer("Недостаточно прав") + await message.answer(_("Недостаточно прав")) return bots = await models.Bot.all() @@ -28,8 +29,8 @@ async def info(message: types.Message, state: FSMContext): income_messages = sum([bot.incoming_messages_count for bot in bots]) outgoing_messages = sum([bot.outgoing_messages_count for bot in bots]) - await message.answer(f"Количество ботов: {bots_count}\n" - f"Количество пользователей (у конструктора): {user_count}\n" - f"Шаблонов ответов: {templates_count}\n" - f"Входящих сообщений у всех ботов: {income_messages}\n" - f"Исходящих сообщений у всех ботов: {outgoing_messages}\n") + await message.answer(_("Количество ботов: {0}\n").format(bots_count) + + _("Количество пользователей (у конструктора): {0}\n").format(user_count) + + _("Шаблонов ответов: {0}\n").format(templates_count) + + _("Входящих сообщений у всех ботов: {0}\n").format(income_messages) + + _("Исходящих сообщений у всех ботов: {0}\n").format(outgoing_messages)) diff --git a/olgram/commands/menu.py b/olgram/commands/menu.py index b285f01..d84b3ab 100644 --- a/olgram/commands/menu.py +++ b/olgram/commands/menu.py @@ -7,6 +7,7 @@ from aiogram.utils.callback_data import CallbackData from textwrap import dedent from olgram.utils.mix import edit_or_create, button_text_limit, wrap from olgram.commands import bot_actions +from locales.locale import _ import typing as ty @@ -27,11 +28,11 @@ async def send_bots_menu(chat_id: int, user_id: int, call=None): user = await User.get_or_none(telegram_id=user_id) bots = await Bot.filter(owner=user) if not bots: - await AioBot.get_current().send_message(chat_id, dedent(""" + await AioBot.get_current().send_message(chat_id, dedent(_(""" У вас нет добавленных ботов. Отправьте команду /addbot, чтобы добавить бот. - """)) + """))) return keyboard = types.InlineKeyboardMarkup(row_width=2) @@ -42,7 +43,7 @@ async def send_bots_menu(chat_id: int, user_id: int, call=None): chat=empty)) ) - text = "Ваши боты" + text = _("Ваши боты") if call: await edit_or_create(call, text, keyboard) else: @@ -63,28 +64,28 @@ async def send_chats_menu(bot: Bot, call: types.CallbackQuery): ) if chats: keyboard.insert( - types.InlineKeyboardButton(text="Личные сообщения", + types.InlineKeyboardButton(text=_("Личные сообщения"), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="chat", chat="personal")) ) keyboard.insert( - types.InlineKeyboardButton(text="<< Назад", + types.InlineKeyboardButton(text=_("<< Назад"), callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) ) if not chats: - text = dedent(f""" + text = dedent(_(""" Этот бот не добавлен в чаты, поэтому все сообщения будут приходить вам в бот. - Чтобы подключить чат — добавьте бот @{bot.name} в чат, откройте это меню ещё раз и выберите добавленный чат. + Чтобы подключить чат — добавьте бот @{0} в чат, откройте это меню ещё раз и выберите добавленный чат. Если ваш бот состоял в групповом чате до того, как его добавили в Olgram - удалите бота из чата и добавьте снова. - """) + """)).format(bot.name) else: - text = dedent(f""" - В этом разделе вы можете привязать бота @{bot.name} к чату. + text = dedent(_(""" + В этом разделе вы можете привязать бота @{0} к чату. Выберите чат, куда бот будет пересылать сообщения. - """) + """)).format(bot.name) await edit_or_create(call, text, keyboard) @@ -93,86 +94,86 @@ async def send_bot_menu(bot: Bot, call: types.CallbackQuery): await call.answer() keyboard = types.InlineKeyboardMarkup(row_width=2) keyboard.insert( - types.InlineKeyboardButton(text="Текст", + types.InlineKeyboardButton(text=_("Текст"), callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="text", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Чат", + types.InlineKeyboardButton(text=_("Чат"), callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="chat", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Удалить бот", + types.InlineKeyboardButton(text=_("Удалить бот"), callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="delete", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Статистика", + types.InlineKeyboardButton(text=_("Статистика"), callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="stat", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="<< Назад", + types.InlineKeyboardButton(text=_("<< Назад"), callback_data=menu_callback.new(level=0, bot_id=empty, operation=empty, chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Опции", + types.InlineKeyboardButton(text=_("Опции"), callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="settings", chat=empty)) ) - await edit_or_create(call, dedent(f""" - Управление ботом @{bot.name}. + await edit_or_create(call, dedent(_(""" + Управление ботом @{0}. Если у вас возникли вопросы по настройке бота, то посмотрите нашу справку /help или напишите нам @civsocit_feedback_bot - """), reply_markup=keyboard) + """)).format(bot.name), reply_markup=keyboard) async def send_bot_delete_menu(bot: Bot, call: types.CallbackQuery): await call.answer() keyboard = types.InlineKeyboardMarkup(row_width=2) keyboard.insert( - types.InlineKeyboardButton(text="Да, удалить бот", + types.InlineKeyboardButton(text=_("Да, удалить бот"), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="delete_yes", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="<< Назад", + types.InlineKeyboardButton(text=_("<< Назад"), callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) ) - await edit_or_create(call, dedent(f""" - Вы уверены, что хотите удалить бота @{bot.name}? - """), reply_markup=keyboard) + await edit_or_create(call, dedent(_(""" + Вы уверены, что хотите удалить бота @{0}? + """)).format(bot.name), reply_markup=keyboard) async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery): await call.answer() keyboard = types.InlineKeyboardMarkup(row_width=1) keyboard.insert( - types.InlineKeyboardButton(text="Потоки сообщений", + types.InlineKeyboardButton(text=_("Потоки сообщений"), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="threads", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Данные пользователя", + types.InlineKeyboardButton(text=_("Данные пользователя"), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="additional_info", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="<< Назад", + types.InlineKeyboardButton(text=_("<< Назад"), callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) ) - thread_turn = "включены" if bot.enable_threads else "выключены" - info_turn = "включены" if bot.enable_additional_info else "выключены" - text = dedent(f""" - Потоки сообщений: {thread_turn} - Данные пользователя: {info_turn} - """) + thread_turn = _("включены") if bot.enable_threads else _("выключены") + info_turn = _("включены") if bot.enable_additional_info else _("выключены") + text = dedent(_(""" + Потоки сообщений: {0} + Данные пользователя: {1} + """)).format(thread_turn, info_turn) await edit_or_create(call, text, reply_markup=keyboard, parse_mode="HTML") @@ -181,21 +182,21 @@ async def send_bot_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = await call.answer() keyboard = types.InlineKeyboardMarkup(row_width=2) keyboard.insert( - types.InlineKeyboardButton(text="<< Завершить редактирование", + types.InlineKeyboardButton(text=_("<< Завершить редактирование"), callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Автоответчик", + types.InlineKeyboardButton(text=_("Автоответчик"), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="next_text", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Сбросить текст", + types.InlineKeyboardButton(text=_("Сбросить текст"), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="reset_text", chat=empty)) ) - text = dedent(""" + text = dedent(_(""" Сейчас вы редактируете текст, который отправляется после того, как пользователь отправит вашему боту @{0} команду /start @@ -204,7 +205,7 @@ async def send_bot_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = {1} Отправьте сообщение, чтобы изменить текст. - """) + """)) text = text.format(bot.name, bot.start_text) if call: await edit_or_create(call, text, keyboard, parse_mode="HTML") @@ -218,18 +219,19 @@ async def send_bot_statistic_menu(bot: Bot, call: ty.Optional[types.CallbackQuer await call.answer() keyboard = types.InlineKeyboardMarkup(row_width=2) keyboard.insert( - types.InlineKeyboardButton(text="<< Назад", + types.InlineKeyboardButton(text=_("<< Назад"), callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) ) - text = dedent(f""" - Статистика по боту @{bot.name} + text = dedent(_(""" + Статистика по боту @{0} - Входящих сообщений: {bot.incoming_messages_count} - Ответных сообщений: {bot.outgoing_messages_count} - Шаблоны ответов: {len(await bot.answers)} - Забанено пользователей: {len(await bot.banned_users)} - """) + Входящих сообщений: {1} + Ответных сообщений: {2} + Шаблоны ответов: {3} + Забанено пользователей: {4} + """)).format(bot.name, bot.incoming_messages_count, bot.outgoing_messages_count, len(await bot.answers), + len(await bot.banned_users)) if call: await edit_or_create(call, text, keyboard, parse_mode="HTML") else: @@ -242,26 +244,26 @@ async def send_bot_second_text_menu(bot: Bot, call: ty.Optional[types.CallbackQu await call.answer() keyboard = types.InlineKeyboardMarkup(row_width=2) keyboard.insert( - types.InlineKeyboardButton(text="<< Завершить редактирование", + types.InlineKeyboardButton(text=_("<< Завершить редактирование"), callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Предыдущий текст", + types.InlineKeyboardButton(text=_("Предыдущий текст"), callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="text", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Шаблоны ответов...", + types.InlineKeyboardButton(text=_("Шаблоны ответов..."), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="templates", chat=empty)) ) keyboard.insert( - types.InlineKeyboardButton(text="Сбросить текст", + types.InlineKeyboardButton(text=_("Сбросить текст"), callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="reset_second_text", chat=empty)) ) - text = dedent(""" + text = dedent(_(""" Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в ответ на все входящие сообщения @{0} \ автоматически. По умолчанию оно отключено. @@ -270,8 +272,8 @@ async def send_bot_second_text_menu(bot: Bot, call: ty.Optional[types.CallbackQu {1} Отправьте сообщение, чтобы изменить текст. - """) - text = text.format(bot.name, bot.second_text if bot.second_text else "(отключено)") + """)) + text = text.format(bot.name, bot.second_text if bot.second_text else _("(отключено)")) if call: await edit_or_create(call, text, keyboard, parse_mode="HTML") else: @@ -284,11 +286,11 @@ async def send_bot_templates_menu(bot: Bot, call: ty.Optional[types.CallbackQuer await call.answer() keyboard = types.InlineKeyboardMarkup(row_width=2) keyboard.insert( - types.InlineKeyboardButton(text="<< Завершить редактирование", + types.InlineKeyboardButton(text=_("<< Завершить редактирование"), callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty)) ) - text = dedent(""" + text = dedent(_(""" Сейчас вы редактируете шаблоны ответов для @{0}. Текущие шаблоны:
@@ -296,7 +298,7 @@ async def send_bot_templates_menu(bot: Bot, call: ty.Optional[types.CallbackQuer
     
Отправьте какую-нибудь фразу (например: "Ваш заказ готов, ожидайте!"), чтобы добавить её в шаблон. Чтобы удалить шаблон из списка, отправьте его номер в списке (например, 4) - """) + """)) templates = await bot.answers @@ -307,7 +309,7 @@ async def send_bot_templates_menu(bot: Bot, call: ty.Optional[types.CallbackQuer templates_text = "\n".join(f"{n}. {wrap(template.text, max_len)}" for n, template in enumerate(templates)) if not templates_text: - templates_text = "(нет шаблонов)" + templates_text = _("(нет шаблонов)") text = text.format(bot.name, templates_text) if call: await edit_or_create(call, text, keyboard, parse_mode="HTML") @@ -346,20 +348,21 @@ async def template_received(message: types.Message, state: FSMContext): number = int(message.text) templates = await bot.answers if not templates: - await message.answer("У вас нет шаблонов, чтобы их удалять") + await message.answer(_("У вас нет шаблонов, чтобы их удалять")) if number < 0 or number >= len(templates): - await message.answer(f"Неправильное число. Чтобы удалить шаблон, введите число от 0 до {len(templates)}") + await message.answer(_("Неправильное число. Чтобы удалить шаблон, введите число от 0 до {0}").format( + len(templates))) return await templates[number].delete() else: # Add template total_templates = len(await bot.answers) if total_templates > 30: - await message.answer("У вашего бота уже слишком много шаблонов") + await message.answer(_("У вашего бота уже слишком много шаблонов")) else: answers = await bot.answers.filter(text=message.text) if answers: - await message.answer("Такой текст уже есть в списке шаблонов") + await message.answer(_("Такой текст уже есть в списке шаблонов")) else: template = DefaultAnswer(text=message.text, bot=bot) await template.save() @@ -377,7 +380,7 @@ async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMCon bot_id = callback_data.get("bot_id") bot = await Bot.get_or_none(id=bot_id) if not bot or (await bot.owner).telegram_id != call.from_user.id: - await call.answer("У вас нет прав на этого бота", show_alert=True) + await call.answer(_("У вас нет прав на этого бота"), show_alert=True) return if level == "1": diff --git a/olgram/commands/start.py b/olgram/commands/start.py index daf5263..13e56d0 100644 --- a/olgram/commands/start.py +++ b/olgram/commands/start.py @@ -7,6 +7,7 @@ from aiogram.dispatcher import FSMContext from textwrap import dedent from olgram.settings import OlgramSettings from olgram.utils.permissions import public +from locales.locale import _ from olgram.router import dp @@ -19,9 +20,7 @@ async def start(message: types.Message, state: FSMContext): """ await state.reset_state() - # TODO: locale - - await message.answer(dedent(""" + await message.answer(dedent(_(""" Olgram Bot — это конструктор ботов обратной связи в Telegram. Подробнее \ читайте здесь. @@ -31,7 +30,7 @@ async def start(message: types.Message, state: FSMContext): /mybots - управление ботами /help - помощь - """), parse_mode="html") + """)), parse_mode="html") @dp.message_handler(commands=["help"], state="*") @@ -40,11 +39,11 @@ async def help(message: types.Message, state: FSMContext): """ Команда /help """ - await message.answer(dedent(f""" + await message.answer(dedent(_(""" Читайте инструкции на нашем сайте https://olgram.readthedocs.io Техническая поддержка: @civsocit_feedback_bot - Версия {OlgramSettings.version()} - """)) + Версия {0} + """)).format(OlgramSettings.version())) @dp.message_handler(commands=["chatid"], state="*") diff --git a/olgram/models/models.py b/olgram/models/models.py index b63319b..b9bb6f7 100644 --- a/olgram/models/models.py +++ b/olgram/models/models.py @@ -3,6 +3,7 @@ from tortoise import fields from uuid import uuid4 from textwrap import dedent from olgram.settings import DatabaseSettings +from locales.locale import _ class MetaInfo(Model): @@ -26,10 +27,10 @@ class Bot(Model): owner = fields.ForeignKeyField("models.User", related_name="bots") name = fields.CharField(max_length=33) code = fields.UUIDField(default=uuid4, index=True) - start_text = fields.TextField(default=dedent(""" + start_text = fields.TextField(default=dedent(_(""" Здравствуйте! Напишите ваш вопрос и мы ответим вам в ближайшее время. - """)) + """))) second_text = fields.TextField(null=True, default=None) group_chats = fields.ManyToManyField("models.GroupChat", related_name="bots", on_delete=fields.relational.CASCADE, diff --git a/olgram/settings.py b/olgram/settings.py index 1cb5b72..063a942 100644 --- a/olgram/settings.py +++ b/olgram/settings.py @@ -109,6 +109,14 @@ class BotSettings(AbstractSettings): """ return cls._get_env("BOT_TOKEN") + @classmethod + def language(cls) -> str: + """ + Язык + """ + lang = cls._get_env("O_LANG", allow_none=True) + return lang.lower() if lang else "ru" + class DatabaseSettings(AbstractSettings): @classmethod diff --git a/olgram/utils/permissions.py b/olgram/utils/permissions.py index 4755ffd..d1ad567 100644 --- a/olgram/utils/permissions.py +++ b/olgram/utils/permissions.py @@ -1,6 +1,7 @@ import aiogram.types as types from aiogram.dispatcher.handler import CancelHandler, current_handler from aiogram.dispatcher.middlewares import BaseMiddleware +from locales.locale import _ def public(): @@ -36,7 +37,7 @@ class AccessMiddleware(BaseMiddleware): return if message.chat.id != admin_id: - await message.answer("Владелец бота ограничил доступ к этому функционалу 😞") + await message.answer(_("Владелец бота ограничил доступ к этому функционалу 😞")) raise CancelHandler() async def on_process_callback_query(self, call: types.CallbackQuery, data: dict): @@ -48,5 +49,5 @@ class AccessMiddleware(BaseMiddleware): return if call.message.chat.id != admin_id: - await call.answer("Владелец бота ограничил доступ к этому функционалу😞") + await call.answer(_("Владелец бота ограничил доступ к этому функционалу😞")) raise CancelHandler() diff --git a/poetry.lock b/poetry.lock index 8081d35..481b0fa 100644 --- a/poetry.lock +++ b/poetry.lock @@ -341,6 +341,14 @@ python-versions = ">=3.5" [package.extras] cli = ["click (>=5.0)"] +[[package]] +name = "python-gettext" +version = "4.0" +description = "Python Gettext po to mo file compiler." +category = "main" +optional = false +python-versions = "*" + [[package]] name = "pytz" version = "2020.5" @@ -393,7 +401,7 @@ multidict = ">=4.0" [metadata] lock-version = "1.1" python-versions = "^3.8" -content-hash = "20aec5e4517c3e0bc03d4410544c1c898f0469c9bcfc4f4fecf4c405b1765ded" +content-hash = "9151864c69f349148a36cc7551bb54fd240229eb2533e92b82a0f85a251a56f3" [metadata.files] aerich = [ @@ -825,6 +833,9 @@ python-dotenv = [ {file = "python-dotenv-0.19.2.tar.gz", hash = "sha256:a5de49a31e953b45ff2d2fd434bbc2670e8db5273606c1e737cc6b93eff3655f"}, {file = "python_dotenv-0.19.2-py2.py3-none-any.whl", hash = "sha256:32b2bdc1873fd3a3c346da1c6db83d0053c3c62f28f1f38516070c4c8971b1d3"}, ] +python-gettext = [ + {file = "python-gettext-4.0.tar.gz", hash = "sha256:626b501a51ac892fc3460cf550e60dca121f544eaa46eb69c90ce4682fc7ec02"}, +] pytz = [ {file = "pytz-2020.5-py2.py3-none-any.whl", hash = "sha256:16962c5fb8db4a8f63a26646d8886e9d769b6c511543557bc84e9569fb9a9cb4"}, {file = "pytz-2020.5.tar.gz", hash = "sha256:180befebb1927b16f6b57101720075a984c019ac16b1b7575673bea42c6c3da5"}, diff --git a/pyproject.toml b/pyproject.toml index c65f2e1..6fbd3bf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -15,6 +15,7 @@ pycrypto = "^2.6.1" aioredis = "1.3" aerich = "0.5.x" tortoise-orm = {extras = ["asyncpg"], version = "^0.18.1"} +python-gettext = "^4.0" [tool.poetry.dev-dependencies] flake8 = "^4.0.1" diff --git a/refresh_lang.sh b/refresh_lang.sh new file mode 100644 index 0000000..13ced9b --- /dev/null +++ b/refresh_lang.sh @@ -0,0 +1 @@ +/usr/lib/python3.10/Tools/i18n/pygettext.py -d chinese -o locales/zh/LC_MESSAGES/olgram.pot olgram/ server/ diff --git a/server/custom.py b/server/custom.py index ce25530..c4e9407 100644 --- a/server/custom.py +++ b/server/custom.py @@ -12,6 +12,7 @@ import logging import typing as ty from olgram.settings import ServerSettings from olgram.models.models import Bot, GroupChat, BannedUser +from locales.locale import _ from server.inlines import inline_handler _logger = logging.getLogger(__name__) @@ -36,18 +37,18 @@ def _thread_uniqie_id(bot_id: int, chat_id: int) -> str: def _on_security_policy(message: types.Message, bot): - text = "Политика конфиденциальности\n\n" \ - "Этот бот не хранит ваши сообщения, имя пользователя и @username. При отправке сообщения (кроме команд " \ - "/start и /security_policy) ваш идентификатор пользователя записывается в кеш на некоторое время и потом " \ - "удаляется из кеша. Этот идентификатор используется только для общения с оператором; боты Olgram " \ - "не делают массовых рассылок.\n\n" + text = _("Политика конфиденциальности\n\n" \ + "Этот бот не хранит ваши сообщения, имя пользователя и @username. При отправке сообщения (кроме команд " \ + "/start и /security_policy) ваш идентификатор пользователя записывается в кеш на некоторое время и потом " \ + "удаляется из кеша. Этот идентификатор используется только для общения с оператором; боты Olgram " \ + "не делают массовых рассылок.\n\n") if bot.enable_additional_info: - text += "При отправке сообщения (кроме команд /start и /security_policy) оператор видит ваши имя " \ - "пользователя, @username и идентификатор пользователя в силу настроек, которые оператор указал при " \ - "создании бота." + text += _("При отправке сообщения (кроме команд /start и /security_policy) оператор видит ваши имя " \ + "пользователя, @username и идентификатор пользователя в силу настроек, которые оператор указал при " \ + "создании бота.") else: - text += "В зависимости от ваших настроек конфиденциальности Telegram, оператор может видеть ваш username, " \ - "имя пользователя и другую информацию." + text += _("В зависимости от ваших настроек конфиденциальности Telegram, оператор может видеть ваш username, " \ + "имя пользователя и другую информацию.") return SendMessage(chat_id=message.chat.id, text=text, @@ -57,7 +58,7 @@ def _on_security_policy(message: types.Message, bot): async def send_user_message(message: types.Message, super_chat_id: int, bot): """Переслать сообщение от пользователя, добавлять к нему user info при необходимости""" if bot.enable_additional_info: - user_info = "Сообщение от пользователя " + user_info = _("Сообщение от пользователя ") user_info += message.from_user.full_name if message.from_user.username: user_info += " | @" + message.from_user.username @@ -84,7 +85,7 @@ async def handle_user_message(message: types.Message, super_chat_id: int, bot): banned = await bot.banned_users.filter(telegram_id=message.chat.id) if banned: return SendMessage(chat_id=message.chat.id, - text="Вы заблокированы в этом боте") + text=_("Вы заблокированы в этом боте")) # Пересылаем сообщение в супер-чат if is_super_group and bot.enable_threads: @@ -124,28 +125,28 @@ async def handle_operator_message(message: types.Message, super_chat_id: int, bo chat_id = message.reply_to_message.forward_from_chat if not chat_id: return SendMessage(chat_id=message.chat.id, - text="Невозможно переслать сообщение: автор не найден " - "(сообщение слишком старое?)", + text=_("Невозможно переслать сообщение: автор не найден (сообщение слишком " + "старое?)"), parse_mode="HTML") chat_id = int(chat_id) if message.text == "/ban": - user, _ = await BannedUser.get_or_create(telegram_id=chat_id, bot=bot) + user, create = await BannedUser.get_or_create(telegram_id=chat_id, bot=bot) await user.save() - return SendMessage(chat_id=message.chat.id, text="Пользователь заблокирован") + return SendMessage(chat_id=message.chat.id, text=_("Пользователь заблокирован")) if message.text == "/unban": banned_user = await bot.banned_users.filter(telegram_id=chat_id).first() if not banned_user: - return SendMessage(chat_id=message.chat.id, text="Пользователь не был забанен") + return SendMessage(chat_id=message.chat.id, text=_("Пользователь не был забанен")) else: await banned_user.delete() - return SendMessage(chat_id=message.chat.id, text="Пользователь разбанен") + return SendMessage(chat_id=message.chat.id, text=_("Пользователь разбанен")) try: await message.copy_to(chat_id) except (exceptions.MessageError, exceptions.Unauthorized): - await message.reply("Невозможно переслать сообщение (автор заблокировал бота?)", + await message.reply(_("Невозможно переслать сообщение (автор заблокировал бота?)"), parse_mode="HTML") return diff --git a/server/server.py b/server/server.py index 1ea5eb2..22bfa8e 100644 --- a/server/server.py +++ b/server/server.py @@ -5,6 +5,7 @@ from aiohttp import web from asyncio import get_event_loop import ssl from olgram.settings import ServerSettings +from locales.locale import _ from .custom import CustomRequestHandler import logging @@ -37,8 +38,8 @@ async def register_token(bot: Bot) -> bool: res = await a_bot.set_webhook(url_for_bot(bot), certificate=certificate, drop_pending_updates=True, max_connections=10) await a_bot.set_my_commands([ - BotCommand("/start", "(Пере)запустить бота"), - BotCommand("/security_policy", "Политика конфиденциальности") + BotCommand("/start", _("(Пере)запустить бота")), + BotCommand("/security_policy", _("Политика конфиденциальности")) ]) await a_bot.session.close()