From 74b61a59edb2946e3a1e85a9c2d858d8b9d92722 Mon Sep 17 00:00:00 2001 From: Giorgio Gilestro Date: Wed, 27 May 2026 23:37:11 +0200 Subject: [PATCH] i18n: add diagnostic logging to localizer + lang-toggle click path --- app/routers/api.py | 22 ++++++++++++++++++++++ app/templates/base.html | 14 ++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/app/routers/api.py b/app/routers/api.py index 5075654..87a2aee 100644 --- a/app/routers/api.py +++ b/app/routers/api.py @@ -21,6 +21,10 @@ from app.auth import require_token, maybe_current_user, CurrentUser from app.services.i18n import ACTIVE_LANGUAGES from app.config import get_settings from app.db import get_session, utcnow +from app.logging import get_logger + + +log = get_logger("api_router") from app.templates_env import templates from app.models import ( Headline, @@ -312,8 +316,14 @@ async def _localized_content( Returns None to signal 'use row.content as-is' (the default English path).""" if row is None or principal is None or principal.user is None: + log.info("i18n.log.skip", reason="no_row_or_principal", + row_id=getattr(row, "id", None), + has_principal=principal is not None, + has_user=(principal.user is not None) if principal else False) return None lang = (principal.user.lang or "en") + log.info("i18n.log.lookup", row_id=row.id, lang=lang, + user_id=principal.user.id) if lang == "en": return None t = (await session.execute( @@ -321,6 +331,9 @@ async def _localized_content( .where(StrategicLogTranslation.log_id == row.id) .where(StrategicLogTranslation.lang == lang) )).scalar_one_or_none() + log.info("i18n.log.result", row_id=row.id, lang=lang, + found=(t is not None), + content_preview=(t.content[:60] if t is not None else None)) return t.content if t is not None else None @@ -335,8 +348,14 @@ async def _apply_localized_summary( for the lifetime of this GET request. """ if row is None or principal is None or principal.user is None: + log.info("i18n.summary.skip", reason="no_row_or_principal", + row_id=getattr(row, "id", None), + has_principal=principal is not None, + has_user=(principal.user is not None) if principal else False) return lang = (principal.user.lang or "en") + log.info("i18n.summary.lookup", row_id=row.id, lang=lang, + user_id=principal.user.id) if lang == "en": return t = (await session.execute( @@ -344,6 +363,9 @@ async def _apply_localized_summary( .where(IndicatorSummaryTranslation.summary_id == row.id) .where(IndicatorSummaryTranslation.lang == lang) )).scalar_one_or_none() + log.info("i18n.summary.result", row_id=row.id, lang=lang, + found=(t is not None), + content_preview=(t.content[:60] if t is not None else None)) if t is not None: row.content = t.content diff --git a/app/templates/base.html b/app/templates/base.html index fbf52e0..5a40399 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -143,12 +143,11 @@ }; window.cassandraSetLang = async function (newLang) { + console.log('[lang] click', newLang); var pill = document.getElementById('lang-toggle'); - if (!pill) return; + if (!pill) { console.warn('[lang] no pill element'); return; } var prev = pill.dataset.lang; - if (prev === newLang) return; - // Optimistic update — flip the pill immediately so the click feels - // responsive. Revert on PATCH failure. + if (prev === newLang) { console.log('[lang] already', newLang); return; } pill.dataset.lang = newLang; try { var r = await fetch('/api/settings/language', { @@ -157,18 +156,17 @@ credentials: 'same-origin', body: JSON.stringify({lang: newLang}), }); + console.log('[lang] PATCH', r.status); if (!r.ok) throw new Error('HTTP ' + r.status); - // Trigger HTMX-driven panels to re-fetch in the new language. - // Same shape as cassandraSetTone — every panel that listens to - // tone-changed also listens to lang-changed. ['#dash-header-container', '#log-panel .panel-body', '#indicators-body', '#log-content'].forEach(function (sel) { var el = document.querySelector(sel); + console.log('[lang] trigger', sel, 'found:', !!el, 'htmx:', !!window.htmx); if (el && window.htmx) window.htmx.trigger(el, 'lang-changed'); }); } catch (e) { pill.dataset.lang = prev; - console.warn('language switch failed:', e); + console.warn('[lang] switch failed:', e); } };