Skip to content

Commit 7aa395e

Browse files
Add support for Spanish
1 parent 8f34466 commit 7aa395e

11 files changed

Lines changed: 411 additions & 164 deletions

File tree

app.js

Lines changed: 129 additions & 37 deletions
Large diffs are not rendered by default.

bootstrap.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
if (window.motusI18nReady && typeof window.motusI18nReady.then === "function") {
8989
await window.motusI18nReady;
9090
}
91+
if (typeof window.applyLanguage === "function") {
92+
await window.applyLanguage(window.motusInitialLanguage || runtimeState.currentLanguage || "en");
93+
}
9194

9295
async function loadInitialEntity(entityId, frenchType) {
9396
if (window.ui && window.ui.etat) {

bundle.js

Lines changed: 74 additions & 56 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.html

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html lang="fr">
2+
<html lang="en">
33

44
<head>
55
<meta charset="UTF-8">
@@ -41,9 +41,11 @@ <h1 id="brand-title">MotusArtium</h1>
4141

4242
<div class="lang-status" role="group" aria-label="Interface settings">
4343
<div class="lang-controls">
44-
<button type="button" class="lang-button is-active" data-language="fr" aria-pressed="true" title="French interface">FR</button>
44+
<button type="button" class="lang-button" data-language="fr" aria-pressed="false" title="French interface">FR</button>
4545
<span class="lang-sep" aria-hidden="true">·</span>
46-
<button type="button" class="lang-button" data-language="en" aria-pressed="false" title="English interface">EN</button>
46+
<button type="button" class="lang-button is-active" data-language="en" aria-pressed="true" title="English interface">EN</button>
47+
<span class="lang-sep" aria-hidden="true">·</span>
48+
<button type="button" class="lang-button" data-language="es" aria-pressed="false" title="Spanish interface">ES</button>
4749
</div>
4850
<button type="button" class="theme-toggle" id="theme-toggle" aria-label="Toggle between dark and light color modes" title="Toggle theme">
4951
<svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true">
@@ -280,7 +282,7 @@ <h3>Observatory Constellation</h3>
280282
</div>
281283
<div class="query-list" role="complementary" aria-label="Active query information">
282284
<span class="chip" id="active-doc-chip" aria-label="Active GraphQL document">movement_details.graphql</span>
283-
<span class="chip" aria-label="Interface language">languageCode: <span id="active-language-chip">fr</span></span>
285+
<span class="chip" aria-label="Interface language">languageCode: <span id="active-language-chip">en</span></span>
284286
<span class="chip mobile-only" aria-label="Current visualization mode">Mode: Observatory</span>
285287
</div>
286288
</div>
@@ -380,7 +382,7 @@ <h3 class="section-title">Session Flow</h3>
380382
<h3 class="section-title">Variables</h3>
381383
<pre class="code-box" id="query-variables">{
382384
"id": "Q40415",
383-
"languageCode": "fr"
385+
"languageCode": "en"
384386
}</pre>
385387
</section>
386388

src/donnees/requetes.multi

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -274,13 +274,13 @@ asynchrone déf _recuperer_mouvements_catalogue() -> liste:
274274
# Requêtes pour les mouvements artistiques
275275
# ============================================================================
276276

277-
asynchrone déf obtenir_mouvement_details(mouvement_id: chaine) -> dictionnaire:
277+
asynchrone déf obtenir_mouvement_details(mouvement_id: chaine, langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
278278
"""Récupère les détails d'un mouvement artistique via GraphQL"""
279279
donnees = attendre executer_requete_graphql(
280280
"movement_details.graphql",
281281
{
282282
"id": mouvement_id,
283-
"languageCode": LANGUE_PAR_DEFAUT
283+
"languageCode": langue
284284
}
285285
)
286286

@@ -337,13 +337,13 @@ asynchrone déf obtenir_mouvements_evolution(mouvement_id: chaine) -> dictionnai
337337
# Requêtes pour les artistes
338338
# ============================================================================
339339

340-
asynchrone déf obtenir_artiste_details(artiste_id: chaine) -> dictionnaire:
340+
asynchrone déf obtenir_artiste_details(artiste_id: chaine, langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
341341
"""Récupère les détails d'un artiste via GraphQL"""
342342
donnees = attendre executer_requete_graphql(
343343
"artist_details.graphql",
344344
{
345345
"id": artiste_id,
346-
"languageCode": LANGUE_PAR_DEFAUT
346+
"languageCode": langue
347347
}
348348
)
349349

@@ -353,13 +353,13 @@ asynchrone déf obtenir_artiste_details(artiste_id: chaine) -> dictionnaire:
353353
retour {}
354354

355355

356-
asynchrone déf obtenir_artistes_mouvement(mouvement_id: chaine, limite: nombre = 50) -> liste:
356+
asynchrone déf obtenir_artistes_mouvement(mouvement_id: chaine, limite: nombre = 50, langue: chaine = LANGUE_PAR_DEFAUT) -> liste:
357357
"""Récupère les artistes associés à un mouvement via GraphQL"""
358358
donnees = attendre executer_requete_graphql(
359359
"artists_by_movement.graphql",
360360
{
361361
"movementId": mouvement_id,
362-
"languageCode": LANGUE_PAR_DEFAUT
362+
"languageCode": langue
363363
}
364364
)
365365

@@ -374,13 +374,13 @@ asynchrone déf obtenir_artistes_mouvement(mouvement_id: chaine, limite: nombre
374374
retour resultats
375375

376376

377-
asynchrone déf obtenir_influences_artiste(artiste_id: chaine) -> dictionnaire:
377+
asynchrone déf obtenir_influences_artiste(artiste_id: chaine, langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
378378
"""Récupère le réseau d'influences d'un artiste via GraphQL"""
379379
donnees = attendre executer_requete_graphql(
380380
"artist_influences.graphql",
381381
{
382382
"id": artiste_id,
383-
"languageCode": LANGUE_PAR_DEFAUT
383+
"languageCode": langue
384384
}
385385
)
386386

@@ -422,13 +422,13 @@ asynchrone déf obtenir_influences_artiste_complet(artiste_id: chaine) -> dictio
422422
# Requêtes pour les œuvres d'art
423423
# ============================================================================
424424

425-
asynchrone déf obtenir_oeuvre_details(oeuvre_id: chaine) -> dictionnaire:
425+
asynchrone déf obtenir_oeuvre_details(oeuvre_id: chaine, langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
426426
"""Récupère les détails d'une œuvre via GraphQL"""
427427
donnees = attendre executer_requete_graphql(
428428
"artwork_details.graphql",
429429
{
430430
"id": oeuvre_id,
431-
"languageCode": LANGUE_PAR_DEFAUT
431+
"languageCode": langue
432432
}
433433
)
434434

@@ -438,13 +438,13 @@ asynchrone déf obtenir_oeuvre_details(oeuvre_id: chaine) -> dictionnaire:
438438
retour {}
439439

440440

441-
asynchrone déf obtenir_oeuvres_artiste(artiste_id: chaine, limite: nombre = 50) -> liste:
441+
asynchrone déf obtenir_oeuvres_artiste(artiste_id: chaine, limite: nombre = 50, langue: chaine = LANGUE_PAR_DEFAUT) -> liste:
442442
"""Récupère les œuvres notables d'un artiste via GraphQL"""
443443
donnees = attendre executer_requete_graphql(
444444
"artworks_by_artist.graphql",
445445
{
446446
"artistId": artiste_id,
447-
"languageCode": LANGUE_PAR_DEFAUT
447+
"languageCode": langue
448448
}
449449
)
450450

@@ -459,13 +459,13 @@ asynchrone déf obtenir_oeuvres_artiste(artiste_id: chaine, limite: nombre = 50)
459459
retour resultats
460460

461461

462-
asynchrone déf obtenir_oeuvres_par_sujet(sujet_id: chaine, limite: nombre = 50) -> liste:
462+
asynchrone déf obtenir_oeuvres_par_sujet(sujet_id: chaine, limite: nombre = 50, langue: chaine = LANGUE_PAR_DEFAUT) -> liste:
463463
"""Récupère les œuvres qui dépeignent un sujet via GraphQL"""
464464
donnees = attendre executer_requete_graphql(
465465
"artworks_by_subject.graphql",
466466
{
467467
"subjectId": sujet_id,
468-
"languageCode": LANGUE_PAR_DEFAUT
468+
"languageCode": langue
469469
}
470470
)
471471

@@ -537,13 +537,13 @@ asynchrone déf obtenir_diffusion_geographique(mouvement_id: chaine) -> liste:
537537
retour resultats
538538

539539

540-
asynchrone déf obtenir_oeuvres_musee(musee_id: chaine, limite: nombre = 50) -> liste:
540+
asynchrone déf obtenir_oeuvres_musee(musee_id: chaine, limite: nombre = 50, langue: chaine = LANGUE_PAR_DEFAUT) -> liste:
541541
"""Récupère les œuvres d'un musée via GraphQL"""
542542
donnees = attendre executer_requete_graphql(
543543
"artworks_by_museum.graphql",
544544
{
545545
"museumId": musee_id,
546-
"languageCode": LANGUE_PAR_DEFAUT
546+
"languageCode": langue
547547
}
548548
)
549549

@@ -599,7 +599,7 @@ asynchrone déf obtenir_etiquette_entite(entite_id: chaine, langue: chaine = LAN
599599
}
600600

601601

602-
asynchrone déf obtenir_etiquettes_entite(entite_id: chaine, langues: liste = ["fr", "en"]) -> dictionnaire:
602+
asynchrone déf obtenir_etiquettes_entite(entite_id: chaine, langues: liste = ["fr", "en", "es"]) -> dictionnaire:
603603
"""Recuperer plusieurs etiquettes d'une meme entite."""
604604
etiquettes = {}
605605

@@ -613,22 +613,22 @@ asynchrone déf obtenir_etiquettes_entite(entite_id: chaine, langues: liste = ["
613613
retour etiquettes
614614

615615

616-
asynchrone déf obtenir_graphe_mouvement(mouvement_id: chaine, limite: nombre = 50) -> dictionnaire:
616+
asynchrone déf obtenir_graphe_mouvement(mouvement_id: chaine, limite: nombre = 50, langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
617617
"""Retourner le contrat de graphe canonique pour un mouvement."""
618-
mouvement = attendre obtenir_mouvement_details(mouvement_id)
619-
artistes = attendre obtenir_artistes_mouvement(mouvement_id, limite)
618+
mouvement = attendre obtenir_mouvement_details(mouvement_id, langue)
619+
artistes = attendre obtenir_artistes_mouvement(mouvement_id, limite, langue)
620620

621621
retour {
622622
"mouvement": mouvement,
623623
"artistes": artistes
624624
}
625625

626626

627-
asynchrone déf obtenir_graphe_artiste(artiste_id: chaine, limite: nombre = 50) -> dictionnaire:
627+
asynchrone déf obtenir_graphe_artiste(artiste_id: chaine, limite: nombre = 50, langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
628628
"""Retourner le contrat de graphe canonique pour un artiste."""
629-
artiste = attendre obtenir_artiste_details(artiste_id)
630-
oeuvres = attendre obtenir_oeuvres_artiste(artiste_id, limite)
631-
influences = attendre obtenir_influences_artiste(artiste_id)
629+
artiste = attendre obtenir_artiste_details(artiste_id, langue)
630+
oeuvres = attendre obtenir_oeuvres_artiste(artiste_id, limite, langue)
631+
influences = attendre obtenir_influences_artiste(artiste_id, langue)
632632

633633
retour {
634634
"artiste": artiste,
@@ -637,13 +637,13 @@ asynchrone déf obtenir_graphe_artiste(artiste_id: chaine, limite: nombre = 50)
637637
}
638638

639639

640-
asynchrone déf obtenir_graphe_oeuvre(oeuvre_id: chaine) -> dictionnaire:
640+
asynchrone déf obtenir_graphe_oeuvre(oeuvre_id: chaine, langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
641641
"""Retourner le contrat de graphe canonique pour une oeuvre."""
642642
donnees = attendre executer_requete_graphql(
643643
"artwork_details.graphql",
644644
{
645645
"id": oeuvre_id,
646-
"languageCode": LANGUE_PAR_DEFAUT
646+
"languageCode": langue
647647
}
648648
)
649649

@@ -666,11 +666,11 @@ asynchrone déf obtenir_graphe_oeuvre(oeuvre_id: chaine) -> dictionnaire:
666666
# Requêtes paginées (curseur) pour le chargement progressif
667667
# ============================================================================
668668

669-
asynchrone déf obtenir_artistes_mouvement_page(mouvement_id: chaine, premier: nombre = 20, apres: chaine = "") -> dictionnaire:
669+
asynchrone déf obtenir_artistes_mouvement_page(mouvement_id: chaine, premier: nombre = 20, apres: chaine = "", langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
670670
"""Récupère une page d'artistes pour un mouvement avec pagination curseur."""
671671
variables = {
672672
"movementId": mouvement_id,
673-
"languageCode": LANGUE_PAR_DEFAUT,
673+
"languageCode": langue,
674674
"first": premier
675675
}
676676
si apres:
@@ -694,11 +694,11 @@ asynchrone déf obtenir_artistes_mouvement_page(mouvement_id: chaine, premier: n
694694
}
695695

696696

697-
asynchrone déf obtenir_oeuvres_artiste_page(artiste_id: chaine, premier: nombre = 20, apres: chaine = "") -> dictionnaire:
697+
asynchrone déf obtenir_oeuvres_artiste_page(artiste_id: chaine, premier: nombre = 20, apres: chaine = "", langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
698698
"""Récupère une page d'œuvres pour un artiste avec pagination curseur."""
699699
variables = {
700700
"artistId": artiste_id,
701-
"languageCode": LANGUE_PAR_DEFAUT,
701+
"languageCode": langue,
702702
"first": premier
703703
}
704704
si apres:
@@ -722,11 +722,11 @@ asynchrone déf obtenir_oeuvres_artiste_page(artiste_id: chaine, premier: nombre
722722
}
723723

724724

725-
asynchrone déf obtenir_oeuvres_musee_page(musee_id: chaine, premier: nombre = 20, apres: chaine = "") -> dictionnaire:
725+
asynchrone déf obtenir_oeuvres_musee_page(musee_id: chaine, premier: nombre = 20, apres: chaine = "", langue: chaine = LANGUE_PAR_DEFAUT) -> dictionnaire:
726726
"""Récupère une page d'œuvres pour un musée avec pagination curseur."""
727727
variables = {
728728
"museumId": musee_id,
729-
"languageCode": LANGUE_PAR_DEFAUT,
729+
"languageCode": langue,
730730
"first": premier
731731
}
732732
si apres:

src/i18n/locales/en.json

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,29 @@
3333
"search.placeholder.subject": "Artworks depicting dog, cat, flower...",
3434
"search.placeholder.nationality": "Artists from France, Japan, Mexico...",
3535
"search.placeholder.material": "Works made with oil, marble, bronze...",
36+
"tier.story": "Story",
37+
"tier.story.title": "Story - read narratives, browse themes",
38+
"tier.explorer": "Explorer",
39+
"tier.explorer.title": "Explorer - search, compare, find connections",
40+
"tier.observatory": "Observatory",
41+
"tier.observatory.title": "Observatory - graph constellation and data tools",
42+
"story.heading": "Read the story of any artwork, artist, or movement.",
43+
"story.subheading": "Click a theme tile or a journey step to begin. No graph, no jargon - just the story.",
44+
"story.action.explorer": "Explore deeper ->",
45+
"story.action.observatory": "See the constellation ->",
46+
"story.section.featuredJourney": "Featured Journey",
47+
"story.section.browseByTheme": "Browse by Theme",
48+
"explorer.heading": "Search, compare, and find connections.",
49+
"explorer.comparison.hint": "Use <em>+ Compare</em> in search results to add entities here.",
50+
"explorer.trajectory.hint": "Use <em>+ Trajectory</em> on artist results to trace influence paths.",
51+
"search.mode.entity": "Find entity",
52+
"search.mode.entity.title": "Search for any named entity",
53+
"search.mode.subject": "Artworks of...",
54+
"search.mode.subject.title": "Find artworks that depict a subject",
55+
"search.mode.nationality": "Artists from...",
56+
"search.mode.nationality.title": "Artists by nationality - coming next",
57+
"search.mode.material": "By material...",
58+
"search.mode.material.title": "Artworks by material - coming next",
3659
"modeSummary.observatory.explanation": "Observatory mode keeps the semantic field central while the Query Mirror remains continuously visible.",
3760
"modeSummary.observatory.lens": "Influence-aware, movement-centered, French surface",
3861
"modeSummary.query-theater.explanation": "Query Theater makes the GraphQL document itself a primary storytelling surface for demos and teaching.",
@@ -44,9 +67,14 @@
4467
"modeSummary.recit.explanation": "Recit mode presents the selected entity as a readable narrative, with no graph required.",
4568
"modeSummary.recit.lens": "Story-first, prose-driven, accessible narrative surface",
4669
"languageSurface.fr.primary": "Rechercher un mouvement, un artiste, une oeuvre...",
47-
"languageSurface.fr.secondary": "Trace a movement, artist, work, or place...",
70+
"languageSurface.fr.secondary1": "Trace a movement, artist, work, or place...",
71+
"languageSurface.fr.secondary2": "Explorar un movimiento, artista, obra o lugar...",
4872
"languageSurface.en.primary": "Trace a movement, artist, work, or place...",
49-
"languageSurface.en.secondary": "Explorer un courant, un createur, une oeuvre...",
73+
"languageSurface.en.secondary1": "Explorer un courant, un createur, une oeuvre...",
74+
"languageSurface.en.secondary2": "Explorar un movimiento, artista, obra o lugar...",
75+
"languageSurface.es.primary": "Explorar un movimiento, artista, obra o lugar...",
76+
"languageSurface.es.secondary1": "Trace a movement, artist, work, or place...",
77+
"languageSurface.es.secondary2": "Explorer un courant, un createur, une oeuvre...",
5078
"compassLens.movement.title": "Movement",
5179
"compassLens.movement.summary": "Movement-anchored view for succession, schools, and artistic branches.",
5280
"compassLens.movement.copy": "The compass brings movements forward: prioritize movement nodes and succession lines to read the evolution of styles.",
@@ -243,6 +271,8 @@
243271
"polyglot.surface.fr.label": "Francais",
244272
"polyglot.surface.en.title": "English surface (Ctrl+L)",
245273
"polyglot.surface.en.label": "English",
274+
"polyglot.surface.es.title": "Spanish surface (Ctrl+L)",
275+
"polyglot.surface.es.label": "Espanol",
246276
"polyglot.viewToggle.title": "Toggle between side-by-side and tab view (Ctrl+V)",
247277
"polyglot.viewToggle.aria": "View mode toggle",
248278
"polyglot.viewToggle.label": "Change view",

0 commit comments

Comments
 (0)