Reference detail moved out of
CLAUDE.mdto keep that file a terse map. This is the full text for this subsystem.
English / French, no build step; js/i18n.js (classic script, loaded early) is the
whole mechanism.
- Two string sources. UI strings live in the message catalogue inside
js/i18n.js(one object per language). Data strings (region/pathway/circuit names, descriptions, neurotransmitters, the group/kind/sign/receptor labels) are authored as{en,fr}objects ingenerate_data.py, but the emitted data is English-only: at serialization time every{en,fr}dict is collapsed to its English string and the English -> French pairs are deduplicated into a single side table,public/data/translations.fr.json.js/data.jsfetches that table (only in French) andpick(field)looks each English string up in it. - Generator side. Anatomy is authored in English; a single
FRtable (English -> French) is the French source, and_t("English")wraps any display string into{en, fr}. A string with noFRentry makesbuild_recordsraise listing every missing one, so it can't ship half-translated. Per-hemisphere names are composed by_side_name(Right/Left, and gender/number-agreed French tuned by an optionalfr_genderofm/f/mp/fp), not stored; each record also carries a hemisphere-strippedbase_name. The externalize pass (externalize()+TRANSLATIONSindata_generators/i18n.py, driven bywrite_artifacts) does the collapse: it walks each record +meta, replaces every{en,fr}dict with its English string, and accumulatesTRANSLATIONS[en] = fr. Identicalen == frpairs are skipped (the viewer falls back to English), and one English string mapping to two different French values is a hard error (the FR model assumes en -> fr is a function). This is a pure serialization step: records are still built bilingual. - Language pick.
detectLang():?lang=en|fr(persisted to localStorage) > saved choice > browser localefr*> English.window.__I18N__exposeslang,t(key, vars)(UI,{token}interpolation, falls back to English then the key),pick(field)(in French, translate a plain English data string via the side table, falling back to English; a legacy{en,fr}object still collapses defensively),setDataTranslations(obj)(install the side table, called byjs/data.jsbefore any localize runs),setLang. - Static markup in
index.htmlcarriesdata-i18n(textContent),data-i18n-html(innerHTML),data-i18n-attr="attr:key,...", filled atDOMContentLoaded; dynamic UI callst()directly.setLangsaves the choice and reloads (data is resolved at load), and writes<html lang>. The#lang-switch(EN/FR) is pinned at the top of the panel body.
Important
Any new user-visible string goes in both language tables in js/i18n.js (UI)
or as an {en, fr} object in generate_data.py (data). Source citations + URLs
are intentionally not translated.