Multilanguage support for reply keyboard buttons
This commit is contained in:
parent
02ce581ced
commit
62b390b7b9
@ -14,7 +14,7 @@ __author__ = "Davide Testa"
|
|||||||
__email__ = "davide@davte.it"
|
__email__ = "davide@davte.it"
|
||||||
__credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
|
__credits__ = ["Marco Origlia", "Nick Lee @Nickoala"]
|
||||||
__license__ = "GNU General Public License v3.0"
|
__license__ = "GNU General Public License v3.0"
|
||||||
__version__ = "2.1.36"
|
__version__ = "2.2.0"
|
||||||
__maintainer__ = "Davide Testa"
|
__maintainer__ = "Davide Testa"
|
||||||
__contact__ = "t.me/davte"
|
__contact__ = "t.me/davte"
|
||||||
|
|
||||||
|
@ -176,6 +176,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
self.commands = OrderedDict()
|
self.commands = OrderedDict()
|
||||||
self.command_aliases = OrderedDict()
|
self.command_aliases = OrderedDict()
|
||||||
self.messages['commands'] = dict()
|
self.messages['commands'] = dict()
|
||||||
|
self.messages['reply_keyboard_buttons'] = dict()
|
||||||
self._unknown_command_message = None
|
self._unknown_command_message = None
|
||||||
self.text_message_parsers = OrderedDict()
|
self.text_message_parsers = OrderedDict()
|
||||||
# Handle location messages
|
# Handle location messages
|
||||||
@ -206,7 +207,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
lambda update, user_record=None, authorization_level='user': True
|
lambda update, user_record=None, authorization_level='user': True
|
||||||
)
|
)
|
||||||
self.default_reply_keyboard_elements = []
|
self.default_reply_keyboard_elements = []
|
||||||
self._default_keyboard = dict()
|
|
||||||
self.recent_users = OrderedDict()
|
self.recent_users = OrderedDict()
|
||||||
self._log_file_name = None
|
self._log_file_name = None
|
||||||
self._errors_file_name = None
|
self._errors_file_name = None
|
||||||
@ -411,13 +411,32 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
return self._authorization_denied_message
|
return self._authorization_denied_message
|
||||||
return self.__class__._authorization_denied_message
|
return self.__class__._authorization_denied_message
|
||||||
|
|
||||||
@property
|
def get_keyboard(self, user_record=dict(), update=dict(),
|
||||||
def default_keyboard(self):
|
telegram_id=None):
|
||||||
"""Get the default keyboard.
|
"""Return a reply keyboard translated into user language."""
|
||||||
|
if (not user_record) and telegram_id:
|
||||||
It is sent when reply_markup is left blank and chat is private.
|
with self.db as db:
|
||||||
"""
|
user_record = db['users'].find_one(telegram_id=telegram_id)
|
||||||
return self._default_keyboard
|
buttons = [
|
||||||
|
dict(
|
||||||
|
text=self.get_message(
|
||||||
|
'reply_keyboard_buttons', command,
|
||||||
|
user_record=user_record, update=update,
|
||||||
|
default_message=element['reply_keyboard_button']
|
||||||
|
)
|
||||||
|
)
|
||||||
|
for command, element in self.commands.items()
|
||||||
|
if 'reply_keyboard_button' in element
|
||||||
|
]
|
||||||
|
if len(buttons) == 0:
|
||||||
|
return
|
||||||
|
return dict(
|
||||||
|
keyboard=make_lines_of_buttons(
|
||||||
|
buttons,
|
||||||
|
(2 if len(buttons) < 4 else 3) # Row length
|
||||||
|
),
|
||||||
|
resize_keyboard=True
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def unknown_command_message(self):
|
def unknown_command_message(self):
|
||||||
@ -1025,7 +1044,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
and chat_id > 0
|
and chat_id > 0
|
||||||
and text != self.authorization_denied_message
|
and text != self.authorization_denied_message
|
||||||
):
|
):
|
||||||
reply_markup = self.default_keyboard
|
reply_markup = self.get_keyboard(
|
||||||
|
update=update,
|
||||||
|
telegram_id=chat_id
|
||||||
|
)
|
||||||
if not text:
|
if not text:
|
||||||
return
|
return
|
||||||
parse_mode = str(parse_mode)
|
parse_mode = str(parse_mode)
|
||||||
@ -1176,7 +1198,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
and chat_id > 0
|
and chat_id > 0
|
||||||
and caption != self.authorization_denied_message
|
and caption != self.authorization_denied_message
|
||||||
):
|
):
|
||||||
reply_markup = self.default_keyboard
|
reply_markup = self.get_keyboard(
|
||||||
|
update=update,
|
||||||
|
telegram_id=chat_id
|
||||||
|
)
|
||||||
if type(photo) is str:
|
if type(photo) is str:
|
||||||
photo_path = photo
|
photo_path = photo
|
||||||
with self.db as db:
|
with self.db as db:
|
||||||
@ -1296,7 +1321,10 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
and chat_id > 0
|
and chat_id > 0
|
||||||
and caption != self.authorization_denied_message
|
and caption != self.authorization_denied_message
|
||||||
):
|
):
|
||||||
reply_markup = self.default_keyboard
|
reply_markup = self.get_keyboard(
|
||||||
|
update=update,
|
||||||
|
telegram_id=chat_id,
|
||||||
|
)
|
||||||
if document_path is not None:
|
if document_path is not None:
|
||||||
with self.db as db:
|
with self.db as db:
|
||||||
already_sent = db['sent_documents'].find_one(
|
already_sent = db['sent_documents'].find_one(
|
||||||
@ -1544,8 +1572,9 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
"""
|
"""
|
||||||
self._unknown_command_message = unknown_command_message
|
self._unknown_command_message = unknown_command_message
|
||||||
|
|
||||||
def command(self, command, aliases=None, show_in_keyboard=False,
|
def command(self, command, aliases=None, reply_keyboard_button=None,
|
||||||
description="", authorization_level='admin'):
|
show_in_keyboard=False, description="",
|
||||||
|
authorization_level='admin'):
|
||||||
"""Associate a bot command with a custom handler function.
|
"""Associate a bot command with a custom handler function.
|
||||||
|
|
||||||
Decorate command handlers like this:
|
Decorate command handlers like this:
|
||||||
@ -1559,9 +1588,11 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
`command` is the command name (with or without /).
|
`command` is the command name (with or without /).
|
||||||
`aliases` is a list of aliases; each will call the command handler
|
`aliases` is a list of aliases; each will call the command handler
|
||||||
function; the first alias will appear as button in
|
function; the first alias will appear as button in
|
||||||
default_keyboard.
|
reply keyboard if `reply_keyboard_button` is not set.
|
||||||
`show_in_keyboard`, if True, makes first alias appear in
|
`reply_keyboard_button` is a str or better dict of language-specific
|
||||||
default_keyboard.
|
strings to be shown in default keyboard.
|
||||||
|
`show_in_keyboard`, if True, makes a button for this command appear in
|
||||||
|
default keyboard.
|
||||||
`description` can be used to help users understand what `/command`
|
`description` can be used to help users understand what `/command`
|
||||||
does.
|
does.
|
||||||
`authorization_level` is the lowest authorization level needed to run
|
`authorization_level` is the lowest authorization level needed to run
|
||||||
@ -1623,8 +1654,13 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
if aliases:
|
if aliases:
|
||||||
for alias in aliases:
|
for alias in aliases:
|
||||||
self.command_aliases[alias] = decorated_command_handler
|
self.command_aliases[alias] = decorated_command_handler
|
||||||
if show_in_keyboard:
|
if show_in_keyboard and (aliases or reply_keyboard_button):
|
||||||
self.default_reply_keyboard_elements.append(aliases[0])
|
_reply_keyboard_button = reply_keyboard_button or aliases[0]
|
||||||
|
self.messages[
|
||||||
|
'reply_keyboard_buttons'][
|
||||||
|
command] = _reply_keyboard_button
|
||||||
|
self.commands[command][
|
||||||
|
'reply_keyboard_button'] = _reply_keyboard_button
|
||||||
return command_decorator
|
return command_decorator
|
||||||
|
|
||||||
def parser(self, condition, description='', authorization_level='admin',
|
def parser(self, condition, description='', authorization_level='admin',
|
||||||
@ -1690,7 +1726,8 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
return parser_decorator
|
return parser_decorator
|
||||||
|
|
||||||
def set_command(self, command, handler, aliases=None,
|
def set_command(self, command, handler, aliases=None,
|
||||||
show_in_keyboard=False, description="",
|
reply_keyboard_button=None, show_in_keyboard=False,
|
||||||
|
description="",
|
||||||
authorization_level='admin'):
|
authorization_level='admin'):
|
||||||
"""Associate a `command` with a `handler`.
|
"""Associate a `command` with a `handler`.
|
||||||
|
|
||||||
@ -1700,9 +1737,11 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
`handler` is the function to be called on update objects.
|
`handler` is the function to be called on update objects.
|
||||||
`aliases` is a list of aliases; each will call the command handler
|
`aliases` is a list of aliases; each will call the command handler
|
||||||
function; the first alias will appear as button in
|
function; the first alias will appear as button in
|
||||||
default_keyboard.
|
reply keyboard if `reply_keyboard_button` is not set.
|
||||||
`show_in_keyboard`, if True, makes first alias appear in
|
`reply_keyboard_button` is a str or better dict of language-specific
|
||||||
default_keyboard.
|
strings to be shown in default keyboard.
|
||||||
|
`show_in_keyboard`, if True, makes a button for this command appear in
|
||||||
|
default keyboard.
|
||||||
`description` is a description and can be used to help users understand
|
`description` is a description and can be used to help users understand
|
||||||
what `/command` does.
|
what `/command` does.
|
||||||
`authorization_level` is the lowest authorization level needed to run
|
`authorization_level` is the lowest authorization level needed to run
|
||||||
@ -1712,6 +1751,7 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
raise TypeError(f'Handler `{handler}` is not callable.')
|
raise TypeError(f'Handler `{handler}` is not callable.')
|
||||||
return self.command(
|
return self.command(
|
||||||
command=command, aliases=aliases,
|
command=command, aliases=aliases,
|
||||||
|
reply_keyboard_button=reply_keyboard_button,
|
||||||
show_in_keyboard=show_in_keyboard, description=description,
|
show_in_keyboard=show_in_keyboard, description=description,
|
||||||
authorization_level=authorization_level
|
authorization_level=authorization_level
|
||||||
)(handler)
|
)(handler)
|
||||||
@ -1944,33 +1984,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
del self.individual_location_handlers[identifier]
|
del self.individual_location_handlers[identifier]
|
||||||
return
|
return
|
||||||
|
|
||||||
def set_default_keyboard(self, keyboard='set_default'):
|
|
||||||
"""Set a default keyboard for the bot.
|
|
||||||
|
|
||||||
If a keyboard is not passed as argument, a default one is generated,
|
|
||||||
based on aliases of commands.
|
|
||||||
"""
|
|
||||||
if keyboard == 'set_default':
|
|
||||||
buttons = [
|
|
||||||
dict(
|
|
||||||
text=x
|
|
||||||
)
|
|
||||||
for x in self.default_reply_keyboard_elements
|
|
||||||
]
|
|
||||||
if len(buttons) == 0:
|
|
||||||
self._default_keyboard = None
|
|
||||||
else:
|
|
||||||
self._default_keyboard = dict(
|
|
||||||
keyboard=make_lines_of_buttons(
|
|
||||||
buttons,
|
|
||||||
(2 if len(buttons) < 4 else 3) # Row length
|
|
||||||
),
|
|
||||||
resize_keyboard=True
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
self._default_keyboard = keyboard
|
|
||||||
return
|
|
||||||
|
|
||||||
async def webhook_feeder(self, request):
|
async def webhook_feeder(self, request):
|
||||||
"""Handle incoming HTTP `request`s.
|
"""Handle incoming HTTP `request`s.
|
||||||
|
|
||||||
@ -2012,7 +2025,6 @@ class Bot(TelegramBot, ObjectWithDatabase, MultiLanguageObject):
|
|||||||
|
|
||||||
def setup(self):
|
def setup(self):
|
||||||
"""Make bot ask for updates and handle responses."""
|
"""Make bot ask for updates and handle responses."""
|
||||||
self.set_default_keyboard()
|
|
||||||
if not self.webhook_url:
|
if not self.webhook_url:
|
||||||
asyncio.ensure_future(self.get_updates())
|
asyncio.ensure_future(self.get_updates())
|
||||||
else:
|
else:
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
"""Bot support for multiple languages."""
|
"""Bot support for multiple languages."""
|
||||||
|
|
||||||
# Standard library modules
|
# Standard library modules
|
||||||
|
import asyncio
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@ -17,6 +18,10 @@ default_language_messages = {
|
|||||||
'en': "Language 🗣",
|
'en': "Language 🗣",
|
||||||
'it': "Lingua 🗣"
|
'it': "Lingua 🗣"
|
||||||
},
|
},
|
||||||
|
'reply_keyboard_button': {
|
||||||
|
'en': "Language 🗣",
|
||||||
|
'it': "Lingua 🗣"
|
||||||
|
},
|
||||||
'description': {
|
'description': {
|
||||||
'en': "Change language settings",
|
'en': "Change language settings",
|
||||||
'it': "Cambia le impostazioni della lingua"
|
'it': "Cambia le impostazioni della lingua"
|
||||||
@ -26,6 +31,10 @@ default_language_messages = {
|
|||||||
'description': {
|
'description': {
|
||||||
'en': "Change language settings",
|
'en': "Change language settings",
|
||||||
'it': "Cambia le impostazioni della lingua"
|
'it': "Cambia le impostazioni della lingua"
|
||||||
|
},
|
||||||
|
'language_set': {
|
||||||
|
'en': "Selected language: English 🇬🇧",
|
||||||
|
'it': "Lingua selezionata: Italiano 🇮🇹"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'language_panel': {
|
'language_panel': {
|
||||||
@ -265,6 +274,16 @@ async def _language_button(bot, update, user_record, data):
|
|||||||
ensure=True
|
ensure=True
|
||||||
)
|
)
|
||||||
user_record['selected_language_code'] = data[1]
|
user_record['selected_language_code'] = data[1]
|
||||||
|
if 'chat' in update['message'] and update['message']['chat']['id'] > 0:
|
||||||
|
asyncio.ensure_future(
|
||||||
|
bot.send_message(
|
||||||
|
text=bot.get_message(
|
||||||
|
'language', 'language_button', 'language_set',
|
||||||
|
update=update['message'], user_record=user_record
|
||||||
|
),
|
||||||
|
chat_id=update['message']['chat']['id']
|
||||||
|
)
|
||||||
|
)
|
||||||
if len(data) == 0 or data[0] in ('show', 'set'):
|
if len(data) == 0 or data[0] in ('show', 'set'):
|
||||||
text, reply_markup = get_language_panel(bot, user_record)
|
text, reply_markup = get_language_panel(bot, user_record)
|
||||||
if text:
|
if text:
|
||||||
@ -292,18 +311,17 @@ def init(
|
|||||||
bot.messages['language'] = language_messages
|
bot.messages['language'] = language_messages
|
||||||
bot.add_supported_languages(supported_languages)
|
bot.add_supported_languages(supported_languages)
|
||||||
|
|
||||||
language_command_alias = bot.get_message(
|
aliases = [
|
||||||
'language', 'language_command', 'alias',
|
alias
|
||||||
language='en', default_message=None
|
for alias in language_messages[
|
||||||
)
|
'language_command']['alias'].values()
|
||||||
if language_command_alias is None:
|
]
|
||||||
aliases = []
|
|
||||||
else:
|
|
||||||
aliases = [language_command_alias]
|
|
||||||
|
|
||||||
@bot.command(
|
@bot.command(
|
||||||
command='/language',
|
command='/language',
|
||||||
aliases=aliases,
|
aliases=aliases,
|
||||||
|
reply_keyboard_button=language_messages['language_command'][
|
||||||
|
'reply_keyboard_button'],
|
||||||
show_in_keyboard=show_in_keyboard,
|
show_in_keyboard=show_in_keyboard,
|
||||||
description=language_messages['language_command']['description'],
|
description=language_messages['language_command']['description'],
|
||||||
authorization_level='everybody'
|
authorization_level='everybody'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user