forked from test/mau_mau_bot
implement plurals, update de_DE translation to use plurals
This commit is contained in:
parent
c54ffd83e5
commit
6901e7f4d0
10 changed files with 410 additions and 233 deletions
58
bot.py
58
bot.py
|
@ -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
175
internationalization.py
Normal 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
|
|
@ -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
37
locales/available.py
Normal 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') + ' 中文(香港)'}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
37
results.py
37
results.py
|
@ -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))
|
||||
)
|
45
settings.py
45
settings.py
|
@ -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))
|
||||
|
|
|
@ -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
112
utils.py
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue