# app/templates_config.py """ Shared Jinja2 templates configuration. All route modules should import `templates` from here to ensure consistent globals (like translation function) are available. Template Loading Strategy: - Core templates from app/templates/ (highest priority) - Module templates from app/modules//templates/ (namespaced) Module templates should use namespace prefix to avoid collisions: app/modules/cms/templates/cms/admin/pages.html -> Rendered as: templates.TemplateResponse("cms/admin/pages.html", ...) """ import logging from datetime import datetime from pathlib import Path from fastapi.templating import Jinja2Templates from jinja2 import ChoiceLoader, FileSystemLoader from app.utils.i18n import ( DEFAULT_LANGUAGE, LANGUAGE_FLAGS, LANGUAGE_NAMES, SUPPORTED_LANGUAGES, create_translation_context, ) logger = logging.getLogger(__name__) # Core templates directory TEMPLATES_DIR = Path(__file__).parent / "templates" MODULES_DIR = Path(__file__).parent / "modules" def create_template_loaders() -> ChoiceLoader: """ Create a ChoiceLoader that searches multiple template directories. Search order: 1. Core templates (app/templates/) - highest priority 2. Module templates (app/modules//templates/) - in alphabetical order Returns: ChoiceLoader configured with all template directories """ loaders = [FileSystemLoader(str(TEMPLATES_DIR))] # Core templates first # Add module template directories if MODULES_DIR.exists(): for module_dir in sorted(MODULES_DIR.iterdir()): if module_dir.is_dir(): templates_path = module_dir / "templates" if templates_path.exists() and templates_path.is_dir(): loaders.append(FileSystemLoader(str(templates_path))) logger.debug(f"[Templates] Added module templates: {module_dir.name}") return ChoiceLoader(loaders) def get_module_template_dirs() -> list[Path]: """ Get list of all module template directories. Useful for debugging and introspection. Returns: List of Path objects for module template directories """ dirs = [] if MODULES_DIR.exists(): for module_dir in sorted(MODULES_DIR.iterdir()): if module_dir.is_dir(): templates_path = module_dir / "templates" if templates_path.exists() and templates_path.is_dir(): dirs.append(templates_path) return dirs # Create shared templates instance with multi-directory loader templates = Jinja2Templates(directory=str(TEMPLATES_DIR)) templates.env.loader = create_template_loaders() # Add translation function to Jinja2 environment globals # This makes _() available in all templates AND macros _default_translator = create_translation_context(DEFAULT_LANGUAGE) templates.env.globals["_"] = _default_translator templates.env.globals["t"] = _default_translator # Alias templates.env.globals["SUPPORTED_LANGUAGES"] = SUPPORTED_LANGUAGES templates.env.globals["DEFAULT_LANGUAGE"] = DEFAULT_LANGUAGE templates.env.globals["LANGUAGE_NAMES"] = LANGUAGE_NAMES templates.env.globals["LANGUAGE_FLAGS"] = LANGUAGE_FLAGS templates.env.globals["current_year"] = datetime.now().year