From 400c6137fd5b102622f1210420ad682f54cadd30 Mon Sep 17 00:00:00 2001 From: Alexander Kalinovsky Date: Thu, 28 Aug 2025 15:29:14 +0300 Subject: [PATCH] Refactor language and role enums; update user language default value --- docs/index.md | 2 +- src/quickbot/__init__.py | 68 +++++++++++++++++++++--------- src/quickbot/bot/handlers/start.py | 2 +- src/quickbot/i18n/__init__.py | 40 ++++++++++++++++++ src/quickbot/model/__init__.py | 6 +++ src/quickbot/model/language.py | 2 +- src/quickbot/model/role.py | 4 +- src/quickbot/model/user.py | 2 +- 8 files changed, 99 insertions(+), 27 deletions(-) create mode 100644 src/quickbot/i18n/__init__.py diff --git a/docs/index.md b/docs/index.md index fac0752..4f2b934 100644 --- a/docs/index.md +++ b/docs/index.md @@ -66,7 +66,7 @@ class AppEntity(BotEntity): back_populates="entities", sa_relationship_kwargs={ "lazy": "selectin", - "foreign_keys": "Entity.user_id", + "foreign_keys": "AppEntity.user_id", } ), caption="User", diff --git a/src/quickbot/__init__.py b/src/quickbot/__init__.py index 48efe04..c1c76e0 100644 --- a/src/quickbot/__init__.py +++ b/src/quickbot/__init__.py @@ -1,25 +1,51 @@ -from .main import QuickBot as QuickBot, Config as Config -from .router import Router as Router -from .model.bot_entity import BotEntity as BotEntity -from .model.bot_process import BotProcess as BotProcess -from .model.bot_enum import BotEnum as BotEnum, EnumMember as EnumMember +from .main import QuickBot, Config +from .router import Router +from .model.bot_entity import BotEntity +from .model.bot_process import BotProcess +from .model import BotEnum, EnumMember from .bot.handlers.context import ( - ContextData as ContextData, - CallbackCommand as CallbackCommand, - CommandContext as CommandContext, + ContextData, + CallbackCommand, + CommandContext, ) from .model.descriptors import ( - Entity as Entity, - EntityField as EntityField, - EntityForm as EntityForm, - EntityList as EntityList, - Filter as Filter, - EntityPermission as EntityPermission, - CommandCallbackContext as CommandCallbackContext, - BotContext as BotContext, - CommandButton as CommandButton, - FieldEditButton as FieldEditButton, - InlineButton as InlineButton, - FormField as FormField, - Process as Process, + Entity, + EntityField, + EntityForm, + EntityList, + Filter, + EntityPermission, + CommandCallbackContext, + BotContext, + CommandButton, + FieldEditButton, + InlineButton, + FormField, + Process, ) + +__all__ = [ + "QuickBot", + "Config", + "Router", + "BotEntity", + "BotProcess", + "BotEnum", + "EnumMember", + "ContextData", + "CallbackCommand", + "CommandContext", + "Entity", + "EntityField", + "EntityForm", + "EntityList", + "Filter", + "EntityPermission", + "CommandCallbackContext", + "BotContext", + "CommandButton", + "FieldEditButton", + "InlineButton", + "FormField", + "Process", +] diff --git a/src/quickbot/bot/handlers/start.py b/src/quickbot/bot/handlers/start.py index e2a0a1f..05d86e2 100644 --- a/src/quickbot/bot/handlers/start.py +++ b/src/quickbot/bot/handlers/start.py @@ -55,7 +55,7 @@ async def default_start_handler[UserType: UserBase]( ]: lang = LanguageBase(message.from_user.language_code) else: - lang = LanguageBase.EN + lang = LanguageBase.DEFAULT user = await User.create( session=db_session, diff --git a/src/quickbot/i18n/__init__.py b/src/quickbot/i18n/__init__.py new file mode 100644 index 0000000..04ca509 --- /dev/null +++ b/src/quickbot/i18n/__init__.py @@ -0,0 +1,40 @@ +import gettext as gt +import os +from contextlib import contextmanager + + +def get_translator(language, domain, localedir): + return gt.translation(domain, localedir, languages=[language]) + + +def gettext(message: str) -> str: + return gt.gettext(message) + + +def get_local_text(message: str, locale: str) -> str: + return translators[locale].gettext(message) + + +@contextmanager +def use_locale(locale: str): + original_gettext = gt.gettext + gt.gettext = translators[locale].gettext + try: + yield + finally: + gt.gettext = original_gettext + + +locales_dir = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, "locales") + +locales = [ + locale + for locale in os.listdir(locales_dir) + if os.path.isdir(os.path.join(locales_dir, locale)) +] + +translators = { + locale: get_translator(locale, "messages", locales_dir) + for locale in os.listdir(locales_dir) + if os.path.isdir(os.path.join(locales_dir, locale)) +} \ No newline at end of file diff --git a/src/quickbot/model/__init__.py b/src/quickbot/model/__init__.py index 44968fe..2dd1c44 100644 --- a/src/quickbot/model/__init__.py +++ b/src/quickbot/model/__init__.py @@ -6,6 +6,12 @@ from typing import cast from .bot_enum import BotEnum, EnumMember from ..db import async_session +from .user import UserBase +from .role import RoleBase +from .language import LanguageBase + +__all__ = ["UserBase", "RoleBase", "LanguageBase"] + class EntityPermission(BotEnum): LIST_RLS = EnumMember("list_rls") diff --git a/src/quickbot/model/language.py b/src/quickbot/model/language.py index afee9ba..47db9f5 100644 --- a/src/quickbot/model/language.py +++ b/src/quickbot/model/language.py @@ -2,4 +2,4 @@ from .bot_enum import BotEnum, EnumMember class LanguageBase(BotEnum): - EN = EnumMember("en", {"en": "🇬🇧 english"}) + DEFAULT = EnumMember("default") diff --git a/src/quickbot/model/role.py b/src/quickbot/model/role.py index 38462b6..838923f 100644 --- a/src/quickbot/model/role.py +++ b/src/quickbot/model/role.py @@ -2,5 +2,5 @@ from .bot_enum import BotEnum, EnumMember class RoleBase(BotEnum): - SUPER_USER = EnumMember("super_user") - DEFAULT_USER = EnumMember("default_user") + SUPER_USER = EnumMember("super_user", {"default": "admin"}) + DEFAULT_USER = EnumMember("default_user", {"default": "user"}) diff --git a/src/quickbot/model/user.py b/src/quickbot/model/user.py index 2c4c351..b380f6a 100644 --- a/src/quickbot/model/user.py +++ b/src/quickbot/model/user.py @@ -24,7 +24,7 @@ class UserBase(BotEntity, table=False): lang: LanguageBase = Field( description="User language", sa_type=EnumType(LanguageBase), - default_factory=lambda: LanguageBase.EN, + default_factory=lambda: LanguageBase.DEFAULT, ) is_active: bool = EntityField(description="User is active", default=True)