ADR-027 : Extraction de l'i18n vers forge-mvc-i18n¶
Statut¶
Acceptée
Amende ADR-004 (périmètre du core minimal) et prolonge
ADR-021 et ADR-022 :
poursuite du dégraissage du core vers des opt-ins.
Contexte¶
core/i18n/ (translator par catalogues JSON, locale par défaut et fallback,
cache, exceptions) échoue au test de légitimité d'ADR-004 : « si je retire
cette brique du core, une application Forge basique tourne-t-elle encore ? » →
oui. La traduction est un besoin fréquent mais n'est pas une primitive
générale du framework, et core/i18n/ est autonome (sa seule dépendance
core est core.forge pour les clés de configuration i18n_default_locale /
i18n_fallback_locale, disponible via forge-mvc).
Le module relève donc d'un opt-in, comme stats, workflow, pivot ou mail.
Particularité, le couplage au générateur CRUD. Contrairement à mail ou
pivot, trans() est tissé dans le générateur CRUD du cœur : forge make:crud
et les pages publiques émettent des templates qui appellent {{ trans(...) }}
(crud.edit, common.save, crud.confirm_delete…). Aujourd'hui le renderer
Jinja du cœur expose toujours trans comme global. Une extraction « en dur »
casserait au rendu tout CRUD généré tant que forge-mvc-i18n n'est pas installé.
Décision¶
Le translator runtime core/i18n/ est extrait vers l'opt-in
forge-mvc-i18n, et le cœur conserve un repli trans no-op.
| Avant | Après |
|---|---|
core/i18n/<module>.py |
forge_mvc_i18n.<module> (API réexportée par forge_mvc_i18n) |
from core.i18n import … |
from forge_mvc_i18n import … |
renderer : trans = vraie fonction (toujours) |
renderer : trans = repli no-op ; l'opt-in l'enrichit |
- Repli no-op du noyau. Le renderer Jinja (
integrations/jinja2/renderer.py)
expose toujours un globaltrans(_default_trans) qui retourne la clé telle
quelle. Les templates générés rendent donc sans erreur, traduction ou non.
Quandforge-mvc-i18nest installé, le renderer remplace ce repli par la
vraie fonctiontrans()chargeant les catalogues. C'est exactement le pattern
déjà utilisé pourcan()(RBAC fournit un défautlambda: False, l'opt-in
l'enrichit), deux lignes plus haut dans le même renderer. - Clés de configuration conservées dans le noyau.
i18n_default_localeet
i18n_fallback_localerestent dans le registre_DEFAULTSdecore.forge,
comme les clésmail_*après ADR-022 : le registre de configuration reste
centralisé, seul le code migre. - CLI de scaffolding conservée dans le noyau.
forge i18n:initet
forge i18n:check(cli/assets/i18n.py) sont autonomes : ils créent et
vérifienttranslations/fr.jsonsans importer le translator runtime. Ils
relèvent de l'outillage de projet du CLI cœur et restent disponibles sans
installerforge-mvc-i18n. Seul le translator runtime est extrait.
Pré-1.0 (convention bêta) : extraction sans alias déprécié dans le core. Les
anciens chemins core.i18n sont supprimés.
Conséquences¶
- Nouveau paquet
packages/forge-mvc-i18n/(distribution PyPI séparée, dépend de
forge-mvc). - Garde-fou d'extraction
I18N-EXTRACT-001: le core ne contient plusi18n, le
paquet expose l'API publique, le renderer garde un repli no-op. - Tests i18n protégés par
pytest.importorskip("forge_mvc_i18n")(core autonome,
garde-fouTESTS-OPTIN-IMPORTORSKIP-001). forge_mvc_i18najouté aux listes opt-in transverses (importorskip,
core-only-contract, classifiers PyPI, sweep imports docs) +release-policy.md.- DX : un CRUD généré sans
forge-mvc-i18naffiche les clés brutes (crud.edit)
au lieu du libellé traduit, dégradé mais lisible, jamais cassé.
Suite¶
- Publication PyPI de
forge-mvc-i18n(alignée sur la version du core) lors de la
prochaine release des opt-ins.