From 3896c455b8a24a359564e2670201f023b62da7c9 Mon Sep 17 00:00:00 2001 From: 3252a8 <3252a8@proton.me> Date: Mon, 1 Jun 2026 11:23:45 +0300 Subject: [PATCH] fix: decouple docs email previews from bot deps --- backend/bot/services/email_templates.py | 19 +++++----- docs-site/scripts/generate-email-previews.py | 37 ++++++++++++++++++-- 2 files changed, 46 insertions(+), 10 deletions(-) diff --git a/backend/bot/services/email_templates.py b/backend/bot/services/email_templates.py index 48b3a06..f8ed96a 100644 --- a/backend/bot/services/email_templates.py +++ b/backend/bot/services/email_templates.py @@ -12,11 +12,12 @@ from __future__ import annotations import html import re from dataclasses import dataclass -from typing import Optional, Sequence, Tuple +from typing import TYPE_CHECKING, Optional, Sequence, Tuple from urllib.parse import urlsplit -from bot.middlewares.i18n import JsonI18n, get_i18n_instance, normalize_locale_language_code -from config.settings import Settings +if TYPE_CHECKING: + from bot.middlewares.i18n import JsonI18n + from config.settings import Settings _BG = "#05070a" _CARD_BG = "#0e1116" @@ -64,14 +65,16 @@ def _brand_title(settings: Settings) -> str: def _normalize_lang(language_code: Optional[str], settings: Settings) -> str: - return normalize_locale_language_code( - language_code or settings.DEFAULT_LANGUAGE or "ru", - prefer_known_base=False, - ) + value = str(language_code or settings.DEFAULT_LANGUAGE or "ru").strip().lower() + return value.replace("_", "-") or "ru" def _resolve_i18n(i18n: Optional[JsonI18n]) -> JsonI18n: - return i18n or get_i18n_instance() + if i18n is not None: + return i18n + from bot.middlewares.i18n import get_i18n_instance + + return get_i18n_instance() def _t_html(i18n: JsonI18n, lang: str, key: str, **kwargs) -> str: diff --git a/docs-site/scripts/generate-email-previews.py b/docs-site/scripts/generate-email-previews.py index e3a4253..84d54a4 100644 --- a/docs-site/scripts/generate-email-previews.py +++ b/docs-site/scripts/generate-email-previews.py @@ -9,7 +9,6 @@ sys.path.insert(0, str(BACKEND_ROOT)) if hasattr(sys.stdout, "reconfigure"): sys.stdout.reconfigure(encoding="utf-8") -from bot.middlewares.i18n import JsonI18n # noqa: E402 from bot.services.email_templates import ( # noqa: E402 render_account_merged, render_login_code, @@ -26,6 +25,40 @@ from bot.services.email_templates import ( # noqa: E402 LANGUAGE = "ru" +class PreviewI18n: + def __init__(self, path: Path, default: str = "ru"): + self.default_lang = default + self.locales_data = {} + for item in path.glob("*.json"): + try: + data = json.loads(item.read_text(encoding="utf-8")) + except json.JSONDecodeError: + continue + if isinstance(data, dict): + self.locales_data[item.stem] = { + str(key): str(value) for key, value in data.items() if isinstance(value, str) + } + + def gettext(self, lang_code: str | None, key: str, **kwargs) -> str: + requested = str(lang_code or "").strip().lower().replace("_", "-") + requested_base = requested.split("-", 1)[0] + if requested in self.locales_data: + messages = self.locales_data[requested] + elif requested_base in self.locales_data: + messages = self.locales_data[requested_base] + else: + messages = self.locales_data.get(self.default_lang) or self.locales_data.get("en", {}) + template = messages.get(key) + if template is None and self.default_lang in self.locales_data: + template = self.locales_data[self.default_lang].get(key) + if template is None: + template = key + try: + return template.format(**kwargs) if kwargs else template + except Exception: + return template + + def settings(): return SimpleNamespace( DEFAULT_LANGUAGE=LANGUAGE, @@ -37,7 +70,7 @@ def settings(): ) -I18N = JsonI18n(str(REPO_ROOT / "locales"), default=LANGUAGE) +I18N = PreviewI18n(REPO_ROOT / "locales", default=LANGUAGE) SETTINGS = settings() SAMPLE = { "amount": 390,