from __future__ import annotations import os from dataclasses import dataclass from pathlib import Path from typing import Dict, Optional from dotenv import load_dotenv load_dotenv() DEFAULT_CLIENT_COOLDOWN_SECONDS = 5.0 @dataclass(frozen=True) class Config: bot_token: str manager_group_id: int database_path: Path # Optional per-language overrides for i18n keys (lang -> text). welcome_text: Dict[str, str] ack_text: Dict[str, str] cooldown_text: Dict[str, str] client_cooldown_seconds: float def _optional_env(name: str) -> Optional[str]: raw = os.getenv(name) if raw is None: return None value = raw.strip() return value or None def _text_overrides_for(key: str) -> Dict[str, str]: """Load per-language text overrides. Supported env vars (example for welcome): WELCOME_TEXT_RU / WELCOME_TEXT_UK — language-specific WELCOME_TEXT — legacy; applies only to default language (ru), so UK keeps its catalog string and the services button stays consistent. """ from bot.i18n import DEFAULT_LANGUAGE, SUPPORTED_LANGUAGES overrides: Dict[str, str] = {} legacy = _optional_env(key) if legacy is not None: overrides[DEFAULT_LANGUAGE] = legacy for lang in SUPPORTED_LANGUAGES: specific = _optional_env(f"{key}_{lang.upper()}") if specific is not None: overrides[lang] = specific return overrides def load_config() -> Config: token = os.getenv("BOT_TOKEN", "").strip() if not token: raise RuntimeError("BOT_TOKEN is not set") group_raw = os.getenv("MANAGER_GROUP_ID", "").strip() if not group_raw: raise RuntimeError("MANAGER_GROUP_ID is not set") try: manager_group_id = int(group_raw) except ValueError as exc: raise RuntimeError("MANAGER_GROUP_ID must be an integer") from exc db_path = Path(os.getenv("DATABASE_PATH", "data/bot.db")).expanduser() cooldown_raw = os.getenv("CLIENT_COOLDOWN_SECONDS", str(DEFAULT_CLIENT_COOLDOWN_SECONDS)) try: client_cooldown_seconds = float(cooldown_raw) except ValueError as exc: raise RuntimeError("CLIENT_COOLDOWN_SECONDS must be a number") from exc if client_cooldown_seconds < 0: raise RuntimeError("CLIENT_COOLDOWN_SECONDS must be >= 0") return Config( bot_token=token, manager_group_id=manager_group_id, database_path=db_path, welcome_text=_text_overrides_for("WELCOME_TEXT"), ack_text=_text_overrides_for("ACK_TEXT"), cooldown_text=_text_overrides_for("COOLDOWN_TEXT"), client_cooldown_seconds=client_cooldown_seconds, ) def apply_text_overrides(config: Config) -> None: """Apply optional env text overrides into the i18n catalog (per language).""" from bot.i18n import TEXTS for lang, text in config.welcome_text.items(): if lang in TEXTS: TEXTS[lang]["welcome"] = text for lang, text in config.ack_text.items(): if lang in TEXTS: TEXTS[lang]["ack"] = text for lang, text in config.cooldown_text.items(): if lang in TEXTS: TEXTS[lang]["cooldown"] = text