i18n: bilingual landing page (EN / IT) with auto-detect routing
Public landing page is now served in English and Italian via path-
prefixed URLs (/en/ and /it/), with the bare / detecting the
visitor's language and 302-ing to the right one.
Routing
-------
* GET / : if authed → dashboard (unchanged). Otherwise the visitor's
language is resolved from (in priority order) the rtm.lang cookie,
the Accept-Language header, the cf-ipcountry geolocation header,
and finally DEFAULT_LANG, then a 302 redirects to /<lang>/.
* GET /en/ + /it/ : render the localised landing template, set the
rtm.lang cookie (1-year, SameSite=Lax) so the next /-visit goes
straight to the same translation. Logged-in users with user.lang
set bypass detection for / (same priority chain — user.lang wins
on every public surface they touch).
Storage
-------
* app/locales/<lang>.yaml — flat-ish nested copy files. YAML chosen
so a future translator can edit without touching Python. Strings
containing inline HTML (<strong>, <em>, <a>) are rendered with the
Jinja `safe` filter in the template.
* app/services/locales.py — loads at startup, exposes get_locale()
and detect_public_lang(). Wraps each YAML tree in a small _Dotted
view so templates can write {{ t.hero.subhead }} (deliberately NOT
a dict subclass — dict's built-in method names would shadow YAML
keys like `items`).
Template + chrome
-----------------
* landing.html ported in full to {{ t.<key> }} references.
* public_base.html gets <html lang="…"> + hreflang link tags (en/it/
x-default) when a route opts in via lang_switch=true. A tiny
EN | IT link group lands in the public header, only visible on
surfaces that opt in.
* public.css picks up the small lang-switch widget styles.
Scope (intentionally narrow)
----------------------------
* Only the landing page is localised. Pricing, terms, privacy,
disclaimer, login, verify all stay English-only for now; their
header chrome stays English too because localising labels there
while the linked content is still EN would be a worse mismatch.
* When other public pages get translated, lang_switch=true on those
routes will surface the same widget there with no template changes.
Tests
-----
* tests/test_locales.py covers YAML load parity (every active
language has a file), dotted access through the tree, the
detection precedence chain, and the unknown-locale fallback.
Deps
----
* pyyaml was already in requirements.lock as a transitive but not
declared. Added to pyproject so it stays pinned as an explicit
direct dependency.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
d98a90f35e
commit
ee8384f1ba
10 changed files with 721 additions and 93 deletions
128
app/locales/it.yaml
Normal file
128
app/locales/it.yaml
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
# Italian copy for the public landing page.
|
||||
#
|
||||
# Note: brand names ("Read the Markets") and proper nouns
|
||||
# (tickers, currency codes) stay verbatim — they aren't translated.
|
||||
|
||||
hero:
|
||||
tagline: "Capisci i mercati. Non scommetterci sopra."
|
||||
subhead: >-
|
||||
Pensato per investitori che vogliono <strong>ragionare con
|
||||
lucidità</strong> e tagliare fuori il rumore ad alta frequenza
|
||||
che nasce dal trattare i mercati come un casinò. Aggreghiamo
|
||||
notizie cross-asset e segnali macro, e ne scriviamo una lettura
|
||||
in prosa chiara: cosa giustificano i fondamentali sottostanti,
|
||||
rispetto a cosa sta facendo la folla. Aggiornato durante la
|
||||
giornata di trading. Un servizio editoriale, non finanziario.
|
||||
cta_dashboard: "Apri dashboard"
|
||||
cta_pricing: "Vedi i piani"
|
||||
cta_signup: "Iscriviti gratis"
|
||||
|
||||
shot_dashboard:
|
||||
alt: "Anteprima dashboard"
|
||||
zoom_hint: "Clicca per ingrandire"
|
||||
caption: >-
|
||||
La dashboard. In alto una lettura cross-asset aggregata, sotto
|
||||
gruppi di indicatori selezionati a mano. Il toggle del livello
|
||||
di lettura (Novice / Pro) cambia il taglio di ogni pannello
|
||||
generato dall'IA, da prosa accessibile a registro tecnico
|
||||
sintetico.
|
||||
|
||||
features:
|
||||
news:
|
||||
tag: "Notizie, aggregate"
|
||||
title: "Titoli dall'intero universo macro"
|
||||
body: >-
|
||||
Feed RSS e per-ticker che coprono azioni, tassi, credito, FX,
|
||||
materie prime e geopolitica. Ogni titolo è etichettato
|
||||
automaticamente per tema, così il rumore resta rumore e il
|
||||
materiale rilevante per i fondamentali è facile da trovare.
|
||||
L'ingestione segue il calendario di trading — fuori orario
|
||||
tutto resta in pausa.
|
||||
shot_alt: "Feed notizie con tag automatici"
|
||||
shot_caption: >-
|
||||
Il feed delle notizie. Ogni titolo porta uno o più tag tematici
|
||||
(tassi, AI, energia, geopolitica, …) per tenere i fili che ti
|
||||
interessano e silenziare gli altri. Click su un tag per
|
||||
includerlo; shift-click per escluderlo.
|
||||
indicators:
|
||||
tag: "Segnali macro"
|
||||
title: "Una tape cross-asset curata"
|
||||
body: >-
|
||||
Un set di indicatori selezionato a mano su ogni classe di
|
||||
attivo, aggiornato ogni ora durante le sessioni di mercato.
|
||||
Ogni gruppo ha una lettura breve che spiega cosa il movimento
|
||||
<em>significa</em>, non cosa è stato. Ancorata a utili,
|
||||
politica monetaria, valutazione — non a pattern grafici.
|
||||
shot_alt: "Pannello indicatori con commento IA"
|
||||
shot_caption: >-
|
||||
Il pannello indicatori. Tab per classe di attivo (azionario,
|
||||
tassi, materie prime, FX, obbligazioni, …); ogni tab porta una
|
||||
'lettura' di un paragrafo scritta dal modello sopra i prezzi
|
||||
live. I numeri ancorano la prosa, così il commento è
|
||||
verificabile, non sospeso nel vuoto.
|
||||
strategic:
|
||||
tag: "Lettura strategica"
|
||||
title: "Razionale vs irrazionale, paragrafo per paragrafo"
|
||||
body: >-
|
||||
Leghiamo i titoli della giornata e i segnali cross-asset in
|
||||
un'unica interpretazione breve. Ogni paragrafo distingue i
|
||||
<strong>driver razionali</strong> (utili, politica, valutazione)
|
||||
dagli <strong>irrazionali</strong> (posizionamento, narrativa,
|
||||
flussi) e dà un nome al divario. Due livelli di lettura: Novice
|
||||
e Pro. È commento editoriale su dati pubblici — non una
|
||||
previsione e non un consiglio su nessuna decisione di
|
||||
investimento.
|
||||
shot_alt: "Log strategico — la lettura editoriale IA"
|
||||
shot_caption: >-
|
||||
Il log strategico. Il modello scrive un'interpretazione
|
||||
aggiornata durante la giornata, partendo dalla versione
|
||||
precedente come contesto, in modo da aggiornare invece di
|
||||
ricominciare. Gli utenti paganti ricevono un refresh ogni ora;
|
||||
gli utenti gratuiti uno ogni sei.
|
||||
|
||||
multilang_callout: >-
|
||||
Ogni superficie generata dall'IA — log strategico, letture degli
|
||||
indicatori, analisi di portafoglio, chat, digest giornaliero — è
|
||||
disponibile in <strong>Inglese</strong> e <strong>Italiano</strong>.
|
||||
Usa il selettore di lingua nell'header e i pannelli si aggiornano
|
||||
in tempo reale; simboli ticker, codici valuta e numeri restano
|
||||
invariati tra le lingue.
|
||||
|
||||
more_views:
|
||||
head: "Altre viste"
|
||||
chat:
|
||||
alt: "Fai domande di approfondimento su qualunque log passato"
|
||||
caption: >-
|
||||
Fai domande di approfondimento su qualunque log passato. Il
|
||||
pannello chat eredita tutto il contesto del log, così puoi
|
||||
tirare un filo senza re-incollare titoli o re-spiegare la
|
||||
situazione.
|
||||
caption_strong: "Chiedi qualsiasi cosa su un log"
|
||||
caption_span: "Domande conversazionali con il contesto della giornata già caricato."
|
||||
|
||||
portfolio_blurb: >-
|
||||
Gli utenti paganti possono anche caricare un CSV di portafoglio
|
||||
dal loro broker per un sense-check IA su concentrazione,
|
||||
coerenza con il regime di mercato ed esposizione valutaria. Le
|
||||
posizioni restano nel browser per impostazione predefinita;
|
||||
l'attivazione opzionale del cloud sync (crittografato)
|
||||
permette di ritrovarle su un altro dispositivo.
|
||||
|
||||
not_strip:
|
||||
head: "Cosa questo NON è."
|
||||
items:
|
||||
- "Non è consulenza finanziaria."
|
||||
- "Non sono segnali di trading."
|
||||
- "Non è uno strumento per day-trading."
|
||||
- "Nessuna chiamata buy/sell, mai."
|
||||
- "Nessuna previsione basata su pattern grafici."
|
||||
- "Non è un servizio regolamentato."
|
||||
|
||||
footer:
|
||||
legal: >-
|
||||
Iscrivendoti accetti i nostri <a href="/terms">Termini</a> e
|
||||
l'<a href="/privacy">Informativa privacy</a>, e confermi di aver
|
||||
letto il <a href="/disclaimer">disclaimer finanziario</a>.
|
||||
|
||||
meta:
|
||||
description: "Capisci i mercati. Non scommetterci sopra."
|
||||
Loading…
Add table
Add a link
Reference in a new issue