From f44a184c889e39ae0efc03a5b61a20ab3a07465a Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 20 Oct 2026 22:54:05 +0000 Subject: [PATCH] feat(lang): use the Telegram language for new chats When /start is sent in a chat that has no language stored yet, the language_code of the user's Telegram client is now saved for that chat. Before, only the private chat was seeded (and only for users not yet in the database), so groups always started in English. A language chosen via /language is never overwritten. Closes #34 Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_01GT89dKDN1hzS5xThFhA8yF --- blackjackbot/commands/game/commands.py | 4 ++-- .../commands/game/tests/commands_test.py | 21 +++++++++++++++- database/database.py | 8 +++++++ database/tests/database_test.py | 24 +++++++++++++++++++ 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/blackjackbot/commands/game/commands.py b/blackjackbot/commands/game/commands.py index 5b25a09..3a884aa 100644 --- a/blackjackbot/commands/game/commands.py +++ b/blackjackbot/commands/game/commands.py @@ -18,10 +18,10 @@ def start_cmd(update, context): """Handles messages contianing the /start command. Starts a game for a specific user""" user = update.effective_user chat = update.effective_chat - lang_id = Database().get_lang_id(chat.id) - translator = Translator(lang_id=lang_id) Database().add_user(user.id, user.language_code, user.first_name, user.last_name, user.username) + # Use the language of the user's Telegram client for chats without a language yet, e.g. new groups + Database().set_default_lang_id(chat.id, user.language_code) try: GameStore().get_game(update.effective_chat.id) diff --git a/blackjackbot/commands/game/tests/commands_test.py b/blackjackbot/commands/game/tests/commands_test.py index 82c34f1..b6bb965 100644 --- a/blackjackbot/commands/game/tests/commands_test.py +++ b/blackjackbot/commands/game/tests/commands_test.py @@ -3,7 +3,7 @@ from unittest.mock import Mock, patch from blackjack.game import BlackJackGame -from blackjackbot.commands.game.commands import join_callback +from blackjackbot.commands.game.commands import join_callback, start_cmd from blackjackbot.gamestore import GameStore @@ -38,6 +38,25 @@ def test_join_callback_stores_user(self, db_mock, decorator_db_mock): self.assertEqual(2, len(game.players)) db_mock.return_value.add_user.assert_called_once_with(2, "de", "B", "Bee", "bbb") + @patch("blackjackbot.commands.game.commands.create_game") + @patch("blackjackbot.commands.game.commands.Database") + def test_start_cmd_uses_telegram_language(self, db_mock, create_game_mock): + """Starting a game must store the user's Telegram language for the chat before the game is created""" + chat_id = -1001234 + + update = Mock() + update.effective_chat.id = chat_id + update.effective_user.id = 2 + update.effective_user.first_name = "B" + update.effective_user.last_name = "Bee" + update.effective_user.username = "bbb" + update.effective_user.language_code = "de" + + create_game_mock.side_effect = lambda *args: db_mock.return_value.set_default_lang_id.assert_called_once_with(chat_id, "de") + start_cmd(update, Mock()) + + create_game_mock.assert_called_once() + if __name__ == '__main__': unittest.main() diff --git a/database/database.py b/database/database.py index 82ee9a1..3e83323 100644 --- a/database/database.py +++ b/database/database.py @@ -170,6 +170,14 @@ def set_lang_id(self, chat_id, lang_id): self.cursor.execute("UPDATE chats SET lang_id = ? WHERE chat_id = ?;", [lang_id, chat_id]) self.connection.commit() + def set_default_lang_id(self, chat_id, lang_id): + """Stores the language for a chat, unless the chat already got a language (e.g. chosen via /language)""" + if not lang_id: + return + Cache().invalidate_lang_cache(chat_id) + self.cursor.execute("INSERT OR IGNORE INTO chats (chat_id, lang_id) VALUES(?, ?);", [chat_id, lang_id.lower()]) + self.connection.commit() + def add_user(self, user_id, lang_id, first_name, last_name, username): if self.is_user_saved(user_id): return diff --git a/database/tests/database_test.py b/database/tests/database_test.py index 568ca9d..681f604 100644 --- a/database/tests/database_test.py +++ b/database/tests/database_test.py @@ -51,6 +51,30 @@ def test_add_user_with_existing_chat(self): self.db.cursor.execute("SELECT lang_id FROM chats WHERE chat_id=?;", [str(self.user_id)]) self.assertEqual("de", self.db.cursor.fetchone()["lang_id"]) + def test_set_default_lang_id_new_chat(self): + """Chats without a language must use the language_code sent by Telegram""" + self.assertEqual("en", self.db.get_lang_id(self.user_id)) + + self.db.set_default_lang_id(self.user_id, "DE") + + # The cached default language must not be returned anymore + self.assertEqual("de", self.db.get_lang_id(self.user_id)) + + def test_set_default_lang_id_existing_chat(self): + """A language which was already set for a chat (e.g. via /language) must not be overwritten""" + self.db.set_lang_id(chat_id=self.user_id, lang_id="nl") + + self.db.set_default_lang_id(self.user_id, "de") + + self.assertEqual("nl", self.db.get_lang_id(self.user_id)) + + def test_set_default_lang_id_without_language_code(self): + """Telegram does not always send a language_code, so nothing must be stored then""" + self.db.set_default_lang_id(self.user_id, None) + + self.db.cursor.execute("SELECT lang_id FROM chats WHERE chat_id=?;", [str(self.user_id)]) + self.assertIsNone(self.db.cursor.fetchone()) + if __name__ == '__main__': unittest.main()