Frontend:
- Fix Framer Motion / motion-dom build error by pinning framer-motion to
11.18.2 (compatible with React 19 and Next.js 16).
- Add cross-env and build:local script to bypass standalone symlink errors
on Windows without Developer Mode.
- Allow NEXT_OUTPUT=default to disable standalone output for local builds.
- Refactor i18n: split 14,177-line src/lib/i18n.tsx into per-locale,
per-namespace JSON files under src/lib/i18n/messages/.
- Load English synchronously; other locales loaded on demand via dynamic
imports (reduces initial bundle, improves maintainability).
- Remove unused next-intl message files src/messages/en.json and fr.json.
Backend:
- Remove insecure legacy /api/v1/download/{filename} and /api/v1/cleanup/{filename}
endpoints. The job-based /api/v1/download/{job_id} already enforces ownership.
- Deduplicate texts in TranslationService.translate_batch before sending them
to the provider, reducing API calls for repeated strings.
- Pin httpx to <0.28 to fix TestClient incompatibility with starlette 0.35.1.
- Add pytest-cov and ruff dev dependencies/config.
DevOps:
- Remove hardcoded Grafana password from docker-compose.yml and
docker-compose.monitoring.yml; use GRAFANA_PASSWORD env var.
- Change default TRANSLATION_SERVICE from ollama to google in
docker-compose.yml (Ollama is an optional profile).
- Add GRAFANA_PASSWORD to .env.example.
- Add .coverage and frontend/pnpm-workspace.yaml to .gitignore.
Tests:
- Update API versioning tests for removed legacy endpoints.
- Add tests/test_translation_service.py for deduplication behavior.
Verified:
- pnpm run build:local passes.
- uv run pytest tests/test_providers/* tests/test_translation_service.py
tests/test_story_3_5_api_versioning.py tests/test_download_endpoint.py
tests/test_translators/test_excel_translator.py: provider/translator tests
pass; one pre-existing French error-message test still fails (message is
returned in English, unrelated to this change).
Avant : getDisplaySource(term, 'en') lisait term.translations.en
(qui n'existe pas) puis fallback sur term.source = francais.
C'est ce qui affichait du francais et du néerlandais au mauvais endroit.
Apres : le mapping reflete la structure reelle des donnees :
- FR (lang='fr') → term.source
- EN (lang='en') → term.target
- autres (de, es, it, pt, nl, ru, ja, ko, zh, ar, fa)
→ term.translations[lang]
- si manquant → '' (placeholder, JAMAIS une autre langue en fallback)
Memes regles pour getDisplayTarget, inversees (defaut = target).
Edition (handleTermChange) ecrit au bon endroit :
- FR → term.source
- EN (ou multi) → term.target
- autres → translations[lang]
Le remap automatique de term.target au changement de targetLanguage
est supprime (lecture a la volee maintenant, plus besoin de modifier
l'etat des termes).
Aucun changement de donnees, aucun changement backend, aucun
changement de schema. Fix purement frontend.
Revert du commit e11a6b1 : la langue source doit etre selectionnable
(car l'utilisateur peut vouloir traduire depuis n'importe quelle
des 12 langues supportees, pas seulement le francais).
Le data modele support deja le cas : chaque terme a un champ
\ ranslations\ (dict de 11 langues) qui contient la traduction du
terme source. Donc pour traduire depuis l'italien, on lit
\ erm.translations.it\ comme source, et \ erm.translations.es\
comme cible si la cible est l'espagnol.
Changements :
- Le combobox 'Langue source' est restaure (12 langues)
- Nouvelle fonction \getDisplaySource(term, lang)\ :
* 'fr' ou 'multi' → term.source (le francais original)
* autre → term.translations[lang] (la traduction dans la langue)
* fallback → term.source si la traduction manque
- handleTermChange ecrit au bon endroit selon la langue :
* source FR → term.source
* autre source → term.translations[sourceLanguage]
* target 'multi'/'en' → term.target
* autre target → term.translations[targetLanguage]
- hasUnsavedChanges compare aussi le dict translations (avant
il ne comparait que source|target, donc un edit dans une autre
langue ne declenchait pas l'alerte 'non enregistre')
- Note sous le combobox source explique la regle
(FR = source originale, autre = champ translations)
- i18n : nouvelle cle \glossaries.detail.sourceLangNote\
ajoutee aux 13 locales (FR + EN traduit)
L'utilisateur peut maintenant choisir 'Italien' comme source et
'Espagnol' comme cible, et voir les termes correspondants.
Les templates data/glossaires/*.json ne stockent les termes sources
qu'en francais. Le combobox 'Langue source' laissait l'utilisateur
croire qu'il pouvait traduire depuis une autre langue, mais le
backend renverrait toujours des termes en francais.
Fix : remplacer le select par un label fixe 'Francais' avec un badge
'fixe' et une note explicative indiquant que le multilingue source
est sur la roadmap.
Le select 'Langue cible' reste : il determine quelle traduction du
terme est affichee dans la colonne 'Cible' (FR+10 langues via le
champ translations).
Le index.json avait ete mis a jour '→ Multilingue' mais les fichiers
data/glossaries/*.json gardaient l'ancien nom '→ Anglais' (commit c66252b
n'avait touche que l'index, pas les donnees). Consequence : importer un
template creait un glossaire avec le nom '→ Anglais' alors que les termes
sont en 11 langues (multilingues).
Sync de name + description des 8 fichiers sur l'index.
UX refonte :
- Retire la section 'Glossaires professionnels' de la vue principale
(les 8 cartes de templates sont maintenant dans le dialog de creation)
- Cartes 'Vos glossaires' plus simples : nom, langues, termes, date
- Cliquer sur la carte navigue vers /dashboard/glossaries/[id]
- Plus de boutons Edit/Delete sur la carte (deplaces dans la page detail)
- Recherche par nom (visible si > 3 glossaires)
- Badge 'Non enregistre' si modifications non sauvegardees
Nouvelle page /dashboard/glossaries/[id] :
- Edition inline du nom (input), langues source/cible (select)
- Tableau des termes avec recherche et edition en place
- Ajout/suppression de termes (max 500)
- Export / Import CSV (meme logique que l'edit dialog)
- Zone danger : confirmation en 2 temps pour la suppression
- Back link vers la liste
- i18n : 40 nouvelles cles ajoutees aux 13 locales (FR + EN traduit,
les autres utilisent le fallback EN)
Design preserve : editorial-card, brand-accent, meme typographie,
meme palette. Refactor structurel uniquement, pas de restyling.
Le system prompt (Instructions de contexte) reste tel quel, au-dessus
de la liste des glossaires, comme dans le design actuel.