implement plurals, update de_DE translation to use plurals

This commit is contained in:
Jannes Höke 2016-05-24 15:49:23 +02:00
parent c54ffd83e5
commit 6901e7f4d0
10 changed files with 410 additions and 233 deletions

58
bot.py
View File

@ -37,11 +37,12 @@ from utils import display_name
import card as c
from errors import (NoGameInChatError, LobbyClosedError, AlreadyJoinedError,
NotEnoughPlayersError, DeckEmptyError)
from utils import _, __, send_async, answer_async, user_locale, game_locales, \
error, TIMEOUT
from utils import send_async, answer_async, error, TIMEOUT
from shared_vars import botan, gm, updater, dispatcher
from internationalization import _, __, user_locale, game_locales
import simple_commands
import settings
import simple_commands, settings
from simple_commands import help
@ -136,11 +137,12 @@ def leave_game(bot, update):
except NotEnoughPlayersError:
gm.end_game(chat, user)
send_async(bot, chat.id, text=__("Game ended!", game.translate))
send_async(bot, chat.id, text=__("Game ended!", multi=game.translate))
else:
send_async(bot, chat.id,
text=__("Okay. Next Player: {name}", game.translate).format(
text=__("Okay. Next Player: {name}",
multi=game.translate).format(
name=display_name(game.current_player.user)),
reply_to_message_id=update.message.message_id)
@ -197,10 +199,11 @@ def status_update(bot, update):
pass
except NotEnoughPlayersError:
gm.end_game(chat, user)
send_async(bot, chat.id, text=__("Game ended!", game.translate))
send_async(bot, chat.id, text=__("Game ended!",
multi=game.translate))
else:
send_async(bot, chat.id, text=__("Removing {name} from the game",
game.translate)
multi=game.translate)
.format(name=display_name(user)))
@ -236,7 +239,7 @@ def start_game(bot, update, args):
__("First player: {name}\n"
"Use /close to stop people from joining the game.\n"
"Enable multi-translations with /enable_translations",
game.translate)
multi=game.translate)
.format(name=display_name(game.current_player.user)))
@run_async
@ -410,9 +413,12 @@ def skip_player(bot, update):
delta = (now - started).seconds
if delta < skipped_player.waiting_time:
n = skipped_player.waiting_time - delta
send_async(bot, chat.id,
text=_("Please wait {time} seconds")
.format(time=(skipped_player.waiting_time - delta)),
text=_("Please wait {time} second",
"Please wait {time} seconds",
n)
.format(time=n),
reply_to_message_id=update.message.message_id)
elif skipped_player.waiting_time > 0:
@ -423,11 +429,17 @@ def skip_player(bot, update):
except DeckEmptyError:
pass
n = skipped_player.waiting_time
send_async(bot, chat.id,
text=__("Waiting time to skip this player has "
"been reduced to {time} second.\n"
"Next player: {name}",
"Waiting time to skip this player has "
"been reduced to {time} seconds.\n"
"Next player: {name}", game.translate)
.format(time=skipped_player.waiting_time,
"Next player: {name}",
n,
multi=game.translate)
.format(time=n,
name=display_name(next_player.user)))
game.turn()
@ -437,7 +449,7 @@ def skip_player(bot, update):
send_async(bot, chat.id,
text=__("{name1} was skipped four times in a row "
"and has been removed from the game.\n"
"Next player: {name2}", game.translate)
"Next player: {name2}", multi=game.translate)
.format(name1=display_name(skipped_player.user),
name2=display_name(next_player.user)))
@ -445,7 +457,7 @@ def skip_player(bot, update):
send_async(bot, chat.id,
text=__("{name} was skipped four times in a row "
"and has been removed from the game.\n"
"The game ended.", game.translate)
"The game ended.", multi=game.translate)
.format(name=display_name(skipped_player.user)))
gm.end_game(chat.id, skipped_player.user)
@ -459,7 +471,6 @@ def reply_to_query(bot, update):
Builds the result list for inline queries and answers to the client.
"""
results = list()
playable = list()
switch = None
try:
@ -476,7 +487,7 @@ def reply_to_query(bot, update):
elif user_id == game.current_player.user.id:
if game.choosing_color:
add_choose_color(results, game)
add_other_cards(playable, player, results, game)
add_other_cards(player, results, game)
else:
if not player.drew:
add_draw(player, results)
@ -541,7 +552,7 @@ def process_result(bot, update):
return
elif int(anti_cheat) != last_anti_cheat:
send_async(bot, chat.id,
text=__("Cheat attempt by {name}", game.translate)
text=__("Cheat attempt by {name}", multi=game.translate)
.format(name=display_name(player.user)))
return
elif result_id == 'call_bluff':
@ -560,7 +571,7 @@ def process_result(bot, update):
if game in gm.chatid_games.get(chat.id, list()):
send_async(bot, chat.id,
text=__("Next player: {name}", game.translate)
text=__("Next player: {name}", multi=game.translate)
.format(name=display_name(game.current_player.user)))
@ -572,7 +583,7 @@ def reset_waiting_time(bot, player):
player.waiting_time = 90
send_async(bot, chat.id,
text=__("Waiting time for {name} has been reset to 90 "
"seconds", player.game.translate)
"seconds", multi=player.game.translate)
.format(name=display_name(player.user)))
@ -598,7 +609,7 @@ def do_play_card(bot, player, result_id):
if len(player.cards) == 0:
send_async(bot, chat.id,
text=__("{name} won!", game.translate)
text=__("{name} won!", multi=game.translate)
.format(name=user.first_name))
if us.stats:
@ -612,7 +623,8 @@ def do_play_card(bot, player, result_id):
try:
gm.leave_game(user, chat)
except NotEnoughPlayersError:
send_async(bot, chat.id, text=__("Game ended!", game.translate))
send_async(bot, chat.id,
text=__("Game ended!", multi=game.translate))
us2 = UserSetting.get(id=game.current_player.user.id)
if us2 and us2.stats:
@ -636,7 +648,7 @@ def do_draw(bot, player):
except DeckEmptyError:
send_async(bot, player.game.chat.id,
text=__("There are no more cards in the deck.",
game.translate))
multi=game.translate))
if (game.last_card.value == c.DRAW_TWO or
game.last_card.special == c.DRAW_FOUR) and \
@ -694,6 +706,8 @@ dispatcher.add_handler(CommandHandler('enable_translations',
dispatcher.add_handler(CommandHandler('disable_translations',
disable_translations))
dispatcher.add_handler(CommandHandler('skip', skip_player))
simple_commands.register()
settings.register()
dispatcher.add_handler(MessageHandler([Filters.status_update], status_update))
dispatcher.add_error_handler(error)

175
internationalization.py Normal file
View File

@ -0,0 +1,175 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Telegram bot to play UNO in group chats
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import gettext
from functools import wraps
import logging
from locales import available_locales
from database import db_session
from user_setting import UserSetting
from shared_vars import gm
GETTEXT_DOMAIN = 'unobot'
GETTEXT_DIR = 'locales'
class _Underscore(object):
"""Class to emulate flufl.i18n behaviour, but with plural support"""
def __init__(self):
self.translators = {
locale: gettext.GNUTranslations(
open(gettext.find(
GETTEXT_DOMAIN, GETTEXT_DIR, languages=[locale]
), 'rb')
)
for locale
in available_locales.keys()
if locale != 'en_US' # No translation file for en_US
}
self.locale_stack = list()
def push(self, locale):
self.locale_stack.append(locale)
def pop(self):
if self.locale_stack:
return self.locale_stack.pop()
else:
return None
@property
def code(self):
if self.locale_stack:
return self.locale_stack[-1]
else:
return None
def __call__(self, singular, plural=None, n=1, locale=None):
if not locale:
locale = self.locale_stack[-1]
if locale not in self.translators.keys():
if n is 1:
return singular
else:
return plural
translator = self.translators[locale]
if plural is None:
return translator.gettext(singular)
else:
return translator.ngettext(singular, plural, n)
_ = _Underscore()
def __(singular, plural=None, n=1, multi=False):
"""Translates text into all locales on the stack"""
translations = list()
if not multi:
_.push('en_US')
translations.append(_(singular))
_.pop()
else:
for locale in _.locale_stack:
translation = _(singular, plural, n, locale)
logging.info(translation)
if translation not in translations:
translations.append(translation)
return '\n'.join(translations)
def user_locale(func):
@wraps(func)
@db_session
def wrapped(bot, update, *pargs, **kwargs):
user, chat = _user_chat_from_update(update)
with db_session:
us = UserSetting.get(id=user.id)
if us:
_.push(us.lang)
else:
_.push('en_US')
result = func(bot, update, *pargs, **kwargs)
_.pop()
return result
return wrapped
def game_locales(func):
@wraps(func)
@db_session
def wrapped(bot, update, *pargs, **kwargs):
user, chat = _user_chat_from_update(update)
player = gm.player_for_user_in_chat(user, chat)
locales = list()
if player:
for player in player.game.players:
us = UserSetting.get(id=player.user.id)
if us:
loc = us.lang
else:
loc = 'en_US'
if loc in locales:
continue
_.push(loc)
locales.append(loc)
result = func(bot, update, *pargs, **kwargs)
while _.code:
_.pop()
return result
return wrapped
def _user_chat_from_update(update):
try:
user = update.message.from_user
chat = update.message.chat
except (NameError, AttributeError):
try:
user = update.inline_query.from_user
chat = gm.userid_current[user.id].game.chat
except KeyError:
chat = None
except (NameError, AttributeError):
try:
user = update.chosen_inline_result.from_user
chat = gm.userid_current[user.id].game.chat
except (NameError, AttributeError):
chat = None
return user, chat

View File

@ -0,0 +1,21 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Telegram bot to play UNO in group chats
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .available import available_locales

37
locales/available.py Normal file
View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Telegram bot to play UNO in group chats
# Copyright (c) 2016 Jannes Höke <uno@jhoeke.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Defines a dict of all available locales to the language name"""
OFFSET = 127462 - ord('A')
def flag(code):
return chr(ord(code[0]) + OFFSET) + chr(ord(code[1]) + OFFSET)
available_locales = {'en_US': flag('US') + ' English (US)',
'de_DE': flag('DE') + ' Deutsch (DE)',
'es_ES': flag('ES') + ' Español (ES)',
'id_ID': flag('ID') + ' Bahasa Indonesia',
'it_IT': flag('IT') + ' Italiano',
'pt_BR': flag('BR') + ' Português Brasileiro',
'zh_HK': flag('HK') + ' 廣東話',
'zh_TW': flag('TW') + ' 中文(香港)'}

View File

@ -29,7 +29,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: utf-8\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Gtranslator 2.91.6\n"
#: bot.py:60
@ -229,17 +229,22 @@ msgstr "Du spielst kein Spiel in dieser Gruppe."
#: bot.py:400
#, python-format
msgid "Please wait {time} seconds"
msgstr "Bitte warte {time} Sekunden"
msgid "Please wait {time} second"
msgid_plural "Please wait {time} seconds"
msgstr[0] "Bitte warte {time} Sekunde"
msgstr[1] "Bitte warte {time} Sekunden"
#: bot.py:413
#, python-format
msgid ""
"Waiting time to skip this player has been reduced to {time} seconds.\n"
msgid "Waiting time to skip this player has been reduced to {time} second.\n"
"Next player: {name}"
msgstr ""
"Die Wartezeit um diesen Spieler zu überspringen wurde auf {time} Sekunden "
"reduziert.\n"
msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n"
"Next player: {name}"
msgstr[0] "Die Wartezeit um diesen Spieler zu überspringen wurde auf {time} "
"Sekunde reduziert.\n"
"Nächster Spieler: {name}"
msgstr[1] "Die Wartezeit um diesen Spieler zu überspringen wurde auf {time} "
"Sekunden reduziert.\n"
"Nächster Spieler: {name}"
#: bot.py:424
@ -313,8 +318,10 @@ msgid "Choose Color"
msgstr "Wähle Farbe"
#: results.py:56
msgid "Cards (tap for game state):"
msgstr "Karten (tippe für Spielinfo):"
msgid "Last card (tap for game state):"
msgid_plural "Cards (tap for game state):"
msgstr[0] "Letzte Karte (tippe für Spielinfo):"
msgstr[1] "Karten (tippe für Spielinfo):"
#: results.py:60 results.py:123 results.py:165
msgid "Current player: {name}"
@ -325,13 +332,17 @@ msgid "Last card: {card}"
msgstr "Letzte Karte: {card}"
#: results.py:62 results.py:125 results.py:168
msgid "Players: {player_list}"
msgstr "Spieler: {player_list}"
msgid "Player: {player_list}"
msgid_plural "Players: {player_list}"
msgstr[0] "Spieler: {player_list}"
msgstr[1] "Spieler: {player_list}"
#: results.py:72
#, python-format
msgid "{name} ({number} cards)"
msgstr "{name} ({number} Karten)"
msgid "{name} ({number} card)"
msgid_plural "{name} ({number} cards)"
msgstr[0] "{name} ({number} Karte)"
msgstr[1] "{name} ({number} Karten)"
#: results.py:81
msgid "You are not playing"
@ -355,11 +366,10 @@ msgstr "Starte das Spiel mit /start"
#: results.py:108
#, python-format
msgid "Drawing 1 card"
msgstr "Zieht 1 Karte"
msgid "Drawing {number} cards"
msgstr "Zieht {number} Karten"
msgid "Drawing {number} card"
msgid_plural "Drawing {number} cards"
msgstr[0] "Ich ziehe {number} Karte"
msgstr[1] "Ich ziehe {number} Karten"
#: results.py:136
msgid "Pass"
@ -413,16 +423,22 @@ msgstr "Du hast die Spiel-Statistiken nicht aktiviert. Aktiviere sie, mit dem "
"/settings-Kommando in einem privaten Chat mit dem Bot."
#: simple_commands.py
msgid "{number} games played"
msgstr "{number} gespielte Spiele"
msgid "{number} game played"
msgid_plural "{number} games played"
msgstr[0] "{number} gespieltes Spiel"
msgstr[1] "{number} gespielte Spiele"
#: simple_commands.py
msgid "{number} first places"
msgstr "{number}x 1. Platz"
msgid "{number} first place"
msgid_plural "{number} first places"
msgstr[0] "{number} mal 1. Platz"
msgstr[1] "{number} mal 1. Platz"
#: simple_commands.py
msgid "{number} cards played"
msgstr "{number} gespielte Karten"
msgid "{number} card played"
msgid_plural "{number} cards played"
msgstr[0] "{number} gespielte Karte"
msgstr[1] "{number} gespielte Karten"
#: utils.py

View File

@ -29,6 +29,7 @@ msgstr ""
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: utf-8\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: bot.py:60
@ -184,14 +185,19 @@ msgstr ""
#: bot.py:400
#, python-format
msgid "Please wait {time} seconds"
msgstr ""
msgid "Please wait {time} second"
msgid_plural "Please wait {time} seconds"
msgstr[0] ""
msgstr[1] ""
#: bot.py:413
#, python-format
msgid "Waiting time to skip this player has been reduced to {time} seconds.\n"
msgid "Waiting time to skip this player has been reduced to {time} second.\n"
"Next player: {name}"
msgstr ""
msgid_plural "Waiting time to skip this player has been reduced to {time} seconds.\n"
"Next player: {name}"
msgstr[0] ""
msgstr[1] ""
#: bot.py:424
#, python-format
@ -256,8 +262,10 @@ msgid "Choose Color"
msgstr ""
#: results.py:56
msgid "Cards (tap for game state):"
msgstr ""
msgid "Last card (tap for game state):"
msgid_plural "Cards (tap for game state):"
msgstr[0] ""
msgstr[1] ""
#: results.py:60 results.py:123 results.py:165
msgid "Current player: {name}"
@ -268,13 +276,17 @@ msgid "Last card: {card}"
msgstr ""
#: results.py:62 results.py:125 results.py:168
msgid "Players: {player_list}"
msgstr ""
msgid "Player: {player_list}"
msgid_plural "Players: {player_list}"
msgstr[0] ""
msgstr[1] ""
#: results.py:72
#, python-format
msgid "{name} ({number} cards)"
msgstr ""
msgid "{name} ({number} card)"
msgid_plural "{name} ({number} cards)"
msgstr[0] ""
msgstr[1] ""
#: results.py:81
msgid "You are not playing"
@ -295,11 +307,10 @@ msgstr ""
#: results.py:108
#, python-format
msgid "Drawing 1 card"
msgstr ""
msgid "Drawing {number} cards"
msgstr ""
msgid "Drawing {number} card"
msgid_plural "Drawing {number} cards"
msgstr[0] ""
msgstr[1] ""
#: results.py:136
msgid "Pass"
@ -352,16 +363,22 @@ msgid "You did not enable statistics. Use /settings in "
msgstr ""
#: simple_commands.py
msgid "{number} games played"
msgstr ""
msgid "{number} game played"
msgid_plural "{number} games played"
msgstr[0] ""
msgstr[1] ""
#: simple_commands.py
msgid "{number} first places"
msgstr ""
msgid "{number} first place"
msgid_plural "{number} first places"
msgstr[0] ""
msgstr[1] ""
#: simple_commands.py
msgid "{number} cards played"
msgstr ""
msgid "{number} card played"
msgid_plural "{number} cards played"
msgstr[0] ""
msgstr[1] ""
#: utils.py

View File

@ -26,8 +26,8 @@ from telegram import InlineQueryResultArticle, InputTextMessageContent, \
InlineQueryResultCachedSticker as Sticker
import card as c
from utils import display_color, display_color_group, display_name, \
list_subtract, _, __
from utils import display_color, display_color_group, display_name
from internationalization import _, __
def add_choose_color(results, game):
@ -44,17 +44,16 @@ def add_choose_color(results, game):
)
def add_other_cards(playable, player, results, game):
def add_other_cards(player, results, game):
"""Add hand cards when choosing colors"""
if not playable:
playable = list()
results.append(
InlineQueryResultArticle(
"hand",
title=_("Cards (tap for game state):"),
description=', '.join([repr(card) for card in
list_subtract(player.cards, playable)]),
title=_("Card (tap for game state):",
"Cards (tap for game state):",
len(player.cards)),
description=', '.join([repr(card) for card in player.cards]),
input_message_content=game_info(game)
)
)
@ -62,7 +61,9 @@ def add_other_cards(playable, player, results, game):
def player_list(game):
"""Generate list of player strings"""
return [_("{name} ({number} cards)")
return [_("{name} ({number} card)",
"{name} ({number} cards)",
len(player.cards))
.format(name=player.user.first_name, number=len(player.cards))
for player in game.players]
@ -101,10 +102,9 @@ def add_draw(player, results):
Sticker(
"draw", sticker_file_id=c.STICKERS['option_draw'],
input_message_content=
InputTextMessageContent(__('Drawing 1 card', player.game.translate)
if n == 1 else
__('Drawing {number} cards',
player.game.translate)
InputTextMessageContent(__('Drawing {number} card',
'Drawing {number} cards', n,
multi=player.game.translate)
.format(number=n))
)
)
@ -127,8 +127,9 @@ def add_pass(results, game):
results.append(
Sticker(
"pass", sticker_file_id=c.STICKERS['option_pass'],
input_message_content=InputTextMessageContent(__('Pass',
game.translate))
input_message_content=InputTextMessageContent(
__('Pass', multi=game.translate)
)
)
)
@ -141,7 +142,7 @@ def add_call_bluff(results, game):
sticker_file_id=c.STICKERS['option_bluff'],
input_message_content=
InputTextMessageContent(__("I'm calling your bluff!",
game.translate))
multi=game.translate))
)
)
@ -168,6 +169,8 @@ def game_info(game):
"\n" +
_("Last card: {card}").format(card=repr(game.last_card)) +
"\n" +
_("Players: {player_list}")
_("Player: {player_list}",
"Players: {player_list}",
len(players))
.format(player_list=" -> ".join(players))
)

View File

@ -18,31 +18,14 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
from telegram import ReplyKeyboardMarkup, Emoji
from telegram.ext import CommandHandler, RegexHandler
from utils import send_async
from user_setting import UserSetting
from utils import _, user_locale
from shared_vars import dispatcher
OFFSET = 127462 - ord('A')
def flag(code):
return chr(ord(code[0]) + OFFSET) + chr(ord(code[1]) + OFFSET)
available_locales = [['en_US - ' + flag('US') + ' English (US)'],
['de_DE - ' + flag('DE') + ' Deutsch (DE)'],
['es_ES - ' + flag('ES') + ' Español (ES)'],
['id_ID - ' + flag('ID') + ' Bahasa Indonesia'],
['it_IT - ' + flag('IT') + ' Italiano'],
['pt_BR - ' + flag('BR') + ' Português Brasileiro'],
['zh_HK - ' + flag('HK') + ' 廣東話'],
['zh_TW - ' + flag('TW') + ' 中文(香港)']]
from locales import available_locales
from internationalization import _, user_locale
@user_locale
@ -83,8 +66,11 @@ def kb_select(bot, update, groups):
send_async(bot, chat.id, text=_("Enabled statistics!"))
elif option == Emoji.EARTH_GLOBE_EUROPE_AFRICA:
kb = [[locale + ' - ' + descr]
for locale, descr
in sorted(available_locales.items())]
send_async(bot, chat.id, text=_("Select locale"),
reply_markup=ReplyKeyboardMarkup(keyboard=available_locales,
reply_markup=ReplyKeyboardMarkup(keyboard=kb,
one_time_keyboard=True))
elif option == Emoji.CROSS_MARK:
@ -102,9 +88,7 @@ def locale_select(bot, update, groups):
user = update.message.from_user
option = groups[0]
if option in [locale.split()[0]
for row in available_locales
for locale in row]:
if option in available_locales:
us = UserSetting.get(id=user.id)
us.lang = option
_.push(option)
@ -112,10 +96,11 @@ def locale_select(bot, update, groups):
_.pop()
dispatcher.add_handler(CommandHandler('settings', show_settings))
dispatcher.add_handler(RegexHandler('^([' + Emoji.BAR_CHART +
Emoji.EARTH_GLOBE_EUROPE_AFRICA +
Emoji.CROSS_MARK + ']) .+$',
kb_select, pass_groups=True))
dispatcher.add_handler(RegexHandler(r'^(\w\w_\w\w) - .*',
locale_select, pass_groups=True))
def register():
dispatcher.add_handler(CommandHandler('settings', show_settings))
dispatcher.add_handler(RegexHandler('^([' + Emoji.BAR_CHART +
Emoji.EARTH_GLOBE_EUROPE_AFRICA +
Emoji.CROSS_MARK + ']) .+$',
kb_select, pass_groups=True))
dispatcher.add_handler(RegexHandler(r'^(\w\w_\w\w) - .*',
locale_select, pass_groups=True))

View File

@ -21,8 +21,9 @@ from telegram import ParseMode
from telegram.ext import CommandHandler
from user_setting import UserSetting
from utils import _, send_async, user_locale
from utils import send_async
from shared_vars import dispatcher
from internationalization import _, user_locale
help_text = ("Follow these steps:\n\n"
"1. Add this bot to a group\n"
@ -101,18 +102,34 @@ def stats(bot, update):
"a private chat with the bot to enable them."))
else:
stats_text = list()
n = us.games_played
stats_text.append(
_("{number} games played").format(number=us.games_played))
_("{number} game played",
"{number} games played",
n).format(number=n)
)
n = us.first_places
stats_text.append(
_("{number} first places").format(number=us.first_places))
_("{number} first places",
"{number} first places",
n).format(number=n)
)
n = us.cards_played
stats_text.append(
_("{number} cards played").format(number=us.cards_played))
_("{number} card played",
"{number} cards played",
n).format(number=n)
)
send_async(bot, update.message.chat_id,
text='\n'.join(stats_text))
dispatcher.add_handler(CommandHandler('help', help))
dispatcher.add_handler(CommandHandler('source', source))
dispatcher.add_handler(CommandHandler('news', news))
dispatcher.add_handler(CommandHandler('stats', stats))
def register():
dispatcher.add_handler(CommandHandler('help', help))
dispatcher.add_handler(CommandHandler('source', source))
dispatcher.add_handler(CommandHandler('news', news))
dispatcher.add_handler(CommandHandler('stats', stats))

112
utils.py
View File

@ -19,52 +19,17 @@
import logging
from functools import wraps
from flufl.i18n import registry
from flufl.i18n import PackageStrategy
from telegram import Emoji
from telegram.ext.dispatcher import run_async
import locales
from database import db_session
from user_setting import UserSetting
from shared_vars import gm
strategy = PackageStrategy('unobot', locales)
application = registry.register(strategy)
_ = application._
from internationalization import _, __
logger = logging.getLogger(__name__)
TIMEOUT = 2.5
def __(string, multi_translate):
"""Translates text into all locales on the stack"""
translations = list()
locales = list()
if not multi_translate:
_.push('en_US')
translations.append(_(string))
_.pop()
else:
while _.code:
translation = _(string)
if translation not in translations:
translations.append(translation)
locales.append(_.code)
_.pop()
for l in reversed(locales):
_.push(l)
return '\n'.join(translations)
def list_subtract(list1, list2):
""" Helper function to subtract two lists and return the sorted result """
list1 = list1.copy()
@ -138,76 +103,3 @@ def answer_async(bot, *args, **kwargs):
bot.answerInlineQuery(*args, **kwargs)
except Exception as e:
error(None, None, e)
def user_locale(func):
@wraps(func)
@db_session
def wrapped(bot, update, *pargs, **kwargs):
user, chat = _user_chat_from_update(update)
with db_session:
us = UserSetting.get(id=user.id)
if us:
_.push(us.lang)
else:
_.push('en_US')
result = func(bot, update, *pargs, **kwargs)
_.pop()
return result
return wrapped
def game_locales(func):
@wraps(func)
@db_session
def wrapped(bot, update, *pargs, **kwargs):
user, chat = _user_chat_from_update(update)
player = gm.player_for_user_in_chat(user, chat)
locales = list()
if player:
for player in player.game.players:
us = UserSetting.get(id=player.user.id)
if us:
loc = us.lang
else:
loc = 'en_US'
if loc in locales:
continue
_.push(loc)
locales.append(loc)
result = func(bot, update, *pargs, **kwargs)
while _.code:
_.pop()
return result
return wrapped
def _user_chat_from_update(update):
try:
user = update.message.from_user
chat = update.message.chat
except (NameError, AttributeError):
try:
user = update.inline_query.from_user
chat = gm.userid_current[user.id].game.chat
except KeyError:
chat = None
except (NameError, AttributeError):
try:
user = update.chosen_inline_result.from_user
chat = gm.userid_current[user.id].game.chat
except (NameError, AttributeError):
chat = None
return user, chat