Skip to content

feat(i18n): add Italian (it) locale - #785

Open
SandroHub013 wants to merge 1 commit into
666ghj:mainfrom
SandroHub013:feat/italian-locale
Open

feat(i18n): add Italian (it) locale#785
SandroHub013 wants to merge 1 commit into
666ghj:mainfrom
SandroHub013:feat/italian-locale

Conversation

@SandroHub013

@SandroHub013 SandroHub013 commented Aug 22, 2026

Copy link
Copy Markdown

Summary

Adds Italian (it) as a UI language, following the community-contribution path described in #428 ("7 languages pre-registered for community contribution; contributors only need to add a JSON file").

Italian was not among the pre-registered codes, so this adds both halves that the loaders need:

  • locales/it.json — new, all 631 keys translated
  • locales/languages.json — one entry: "it": { "label": "Italiano", "llmInstruction": "Per favore, rispondi in italiano." }

Both are required: frontend/src/i18n/index.js:11 only registers a locale whose file and registry entry exist, while backend/app/utils/locale.py:31 only accepts an Accept-Language value that is present in the loaded translations.

Because get_language_instruction() feeds the LLM prompts in report_agent.py, ontology_generator.py, simulation_config_generator.py and oasis_profile_generator.py, this also makes generated reports and simulated personas respond in Italian, not just the UI chrome.

Why this touches three .vue files

The locale-specific typography is keyed to html[lang="en"] alone. With only the JSON files added, Italian silently inherits the CJK defaults. Measured on the home page at 1440px:

Element lang="en" lang="it" before lang="it" after
.main-title 56px, Space Grotesk, -1px 72px, JetBrains Mono, -2px 56px, Space Grotesk, -1px
.hero-desc -apple-system JetBrains Mono -apple-system
.workflow-list .step-desc 11.52px 13.6px 11.52px
.main-title height 136px 263px (clipped) 136px

The practical effect is that the hero title wrapped to three oversized monospace lines and pushed the Reality Seed upload panel below the fold.

The fix is deliberately minimal: each html[lang="en"] rule in Home.vue (11 rules), Step4Report.vue and Step5Interaction.vue (1 each) becomes a two-selector list html[lang="en"], html[lang="it"]. No declaration inside any rule body was changed — only selectors, plus the two comments that now describe more than English.

I kept this explicit rather than generalising to something like html:not([lang="zh"]), to stay in scope. Happy to send that generalisation as a separate PR if you'd prefer it, since it would let the next Latin-script locale be a pure JSON contribution again — which is what #428 promised.

Translation conventions

  • Structure identical to en.json: same keys, same order, same nesting, main.stepNames still a 5-element array
  • Every {placeholder} preserved verbatim — 230 keys contain one
  • Not translated: MiroFish, GraphRAG, ReportAgent, OASIS, Zep, API paths, env var names, simulationId/project_id identifiers, / v0.1-Preview, Engine: MiroFish-V1.0, $5/sim
  • Decoration preserved: the >_ , // , 01 / prefixes, box-drawing characters in log lines, trailing ellipses
  • Terminology kept consistent across the file; where the same English string appears under several keys it always maps to the same Italian string. Two deliberate exceptions: step4.expandAll / step4.expandAllEntities differ ("tutti" vs "tutte") because Italian requires gender agreement and entità is feminine.
  • UI labels kept short so the layout holds — e.g. "Env Setup" is "Setup Ambiente", not the longer literal rendering

Verification

No CI runs on pull requests in this repo, so I verified locally.

Backend — loaded backend/app/utils/locale.py directly and asserted:

  • it.json is discovered and it is declared
  • set_locale('it') propagates through the thread-local
  • all 631 keys resolve through t() — none returns the raw key, none silently falls back to another locale
  • placeholder substitution works on all 230 keys that use it
  • an unknown locale still falls back without raising
  • get_language_instruction() returns the Italian instruction

Frontend — ran the dev server and exercised the real UI:

  • Italian appears in the language switcher automatically, labelled "Italiano"
  • document.documentElement.lang becomes it, on switch and on reload
  • walked the home page and the workflow list; no clipping, no overflow, no untranslated strings
  • computed styles now match the English treatment exactly (table above)

Regression — Chinese and English are untouched: t('common.confirm') still returns 确认 / Confirm with their original LLM instructions, and lang="zh" still computes to 72px JetBrains Mono -2px, identical to before this change.

vite build could not be used as a check here because esbuild fails on a temp-file permission error in my Windows environment, unrelated to this change; the dev server and the module graph build fine.

Notes

Two things I noticed while working on this but deliberately left out of scope:

  1. meta.title and meta.description exist in every locale file but are never read — frontend/index.html hardcodes the Chinese <title> and description, so the browser tab stays Chinese in every language.
  2. backend/app/utils/locale.py:31 matches Accept-Language by exact string, so a real browser value such as it-IT,it;q=0.9 falls back to Chinese. It works today only because the axios interceptor always sends a bare code.

Happy to open issues or follow-up PRs for either if useful.


Suggested label: enhancement (I don't have permission to set labels on this repo).

Adds the Italian translation of the shared locale files, following the
community-contribution path described in 666ghj#428: a new locales/it.json plus
an entry in locales/languages.json. No loader change is needed, since both
frontend/src/i18n/index.js and backend/app/utils/locale.py discover locale
files automatically.

All 631 keys are translated. Placeholders, technical identifiers, API
paths, and strings that must not be translated (MiroFish, GraphRAG,
ReportAgent, the version and engine badges) are preserved verbatim.

The locale-specific typography in Home.vue, Step4Report.vue and
Step5Interaction.vue was keyed to html[lang=en] alone. Without extending
those selectors Italian falls back to the CJK defaults (JetBrains Mono at
72px with -2px letter-spacing), which clips the hero title and pushes the
upload panel below the fold. Italian is added alongside English as a
selector list; no declaration inside those rules was changed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant