diff --git a/panel/main.py b/panel/main.py index 7ae57f0..1200b80 100644 --- a/panel/main.py +++ b/panel/main.py @@ -1,5 +1,8 @@ import os import sys +import glob +import re +import asyncio sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from fastapi import FastAPI, HTTPException, status @@ -67,12 +70,82 @@ def translate_filter(text, lang="es"): templates.env.filters["translate"] = translate_filter +_warmed_languages = set() + +async def pre_warm_ui_translations(lang: str): + if lang == "es" or lang in _warmed_languages: + return + + _warmed_languages.add(lang) + print(f"[Panel] Pre-calentando traducciones para idioma UI: {lang}...") + + strings_to_translate = set() + for f in glob.glob(os.path.join(os.path.dirname(__file__), "templates", "*.html")): + try: + with open(f, "r", encoding="utf-8") as fd: + content = fd.read() + strings_to_translate.update(re.findall(r'\"([^\"]+)\"\s*\|\s*translate', content)) + strings_to_translate.update(re.findall(r'\'([^\']+)\'\s*\|\s*translate', content)) + except Exception: + pass + + missing_strings = [] + for text in strings_to_translate: + norm_text = _normalize_text(text) + if not norm_text: continue + + cache_key = f"{lang}:{norm_text}" + if cache_key in _ui_memory_cache: continue + + cached = get_ui_translation(norm_text, lang) + if cached: + _ui_memory_cache[cache_key] = cached + else: + missing_strings.append(norm_text) + + if not missing_strings: + print(f"[Panel] Pre-calentamiento completo: 0 cadenas faltantes para {lang}") + return + + print(f"[Panel] Falta traducir {len(missing_strings)} cadenas UI al {lang}. Empezando concurrencia...") + + from botdiscord.translate import translate_text + + async def _fetch_and_save(text): + translated = await translate_text(text, lang) + if translated and translated != text: + save_ui_translation(text, lang, translated) + _ui_memory_cache[f"{lang}:{text}"] = translated + + tasks = [_fetch_and_save(t) for t in missing_strings] + await asyncio.gather(*tasks) + print(f"[Panel] Pre-calentamiento terminado para {lang}.") + +@app.middleware("http") +async def translation_pre_warm_middleware(request: Request, call_next): + # Detectamos el idioma que va a usar la página para asegurarnos de que esté cargado + if request.url.path.startswith("/static") or request.url.path.startswith("/api"): + return await call_next(request) + + lang = request.cookies.get("panel_lang") + if not lang: + accept_lang = request.headers.get("accept-language", "es") + lang = accept_lang.split(",")[0].split("-")[0] + + if lang and len(lang) == 2: + await pre_warm_ui_translations(lang) + + return await call_next(request) + @app.get("/set-lang/{lang}") async def set_lang(lang: str, request: Request): # Validamos que el idioma sea de 2 letras if len(lang) != 2: return RedirectResponse(url="/dashboard") + # Ejecutamos el calentamiento asíncrono para que la redirección sea instantánea + await pre_warm_ui_translations(lang) + response = RedirectResponse(url=request.headers.get("referer", "/dashboard")) response.set_cookie(key="panel_lang", value=lang, max_age=31536000) # 1 año return response