i18n: add diagnostic logging to localizer + lang-toggle click path

This commit is contained in:
Giorgio Gilestro 2026-05-27 23:37:11 +02:00
parent 833d1775ab
commit 74b61a59ed
2 changed files with 28 additions and 8 deletions

View file

@ -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

View file

@ -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);
}
};
</script>