i18n: add LANGUAGES, ACTIVE_LANGUAGES, respond_in_clause helper

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Giorgio Gilestro 2026-05-27 16:46:32 +02:00
parent 2ecf250d53
commit 5730aad73c
2 changed files with 92 additions and 0 deletions

48
app/services/i18n.py Normal file
View file

@ -0,0 +1,48 @@
"""Language registry + prompt helpers for localized AI output.
Two surfaces consume this module:
- Per-user LLM call sites (portfolio analysis only at this stage) call
``respond_in_clause(user.lang)`` and append the result to their
system prompt.
- The settings dropdown + its PATCH endpoint consult ``ACTIVE_LANGUAGES``
to decide which options are selectable. The strategic-log and digest
translation fan-outs also consult it to decide which languages to
spend tokens on.
Adding Spanish/French/German support later is a one-line constant
change: extend ``ACTIVE_LANGUAGES`` to include the new code. No other
code change is required the rest of the system already treats them
as first-class via ``LANGUAGES``.
"""
from __future__ import annotations
# Display labels for every language the system knows about. ES/FR/DE
# are kept here so labels still render in the dropdown (as disabled
# options) without requiring code changes to enable them later.
LANGUAGES: dict[str, str] = {
"en": "English",
"it": "Italian",
"es": "Spanish",
"fr": "French",
"de": "German",
}
# Languages users can actually select. Settings POST validates against
# this; the strategic-log + digest translation fan-outs only consider
# these.
ACTIVE_LANGUAGES: set[str] = {"en", "it"}
def respond_in_clause(lang: str | None) -> str:
"""Suffix appended to per-user LLM system prompts.
Returns an empty string for ``en`` (no nudge needed), an unknown
code, or ``None``/empty input those callers want the default
English path. Otherwise returns ``"\\n\\nRespond in <Language>."``
keyed off ``LANGUAGES``.
"""
if not lang or lang == "en" or lang not in LANGUAGES:
return ""
return f"\n\nRespond in {LANGUAGES[lang]}."