15 KiB
| title | description | slug | weight | date |
|---|---|---|---|---|
| Guides pratiques | Recettes pas à pas pour les tâches courantes de contribution : langues, thèmes, déploiement, migrations. | guides-pratiques | 2 | 2026-06-16 |
Ajouter une nouvelle langue
TrainUs propose déjà trois langues aujourd'hui — anglais, français et danois (
da) — pas seulement la paire EN/FR mise en avant sur le site du projet. Les étapes ci-dessous montrent comment en ajouter une de plus, avec l'espagnol (es) comme exemple travaillé.
Ajouter une langue demande quatre points de contact : un nouveau fichier de traduction, son enregistrement dans l'initialiseur i18n, une option dans le sélecteur des Réglages, et une entrée dans le journal de décisions.
src/i18n/locales/<code>.json— créer le fichier de traductionsrc/i18n/index.js— importer et enregistrer la localesrc/views/SettingsView.vue— ajouter l'<option>dans le sélecteur de languedocs/decisions-log.md— consigner la décision
1. Créer le fichier de traduction
Copiez src/i18n/locales/en.json vers src/i18n/locales/<code>.json, où <code> est le code de langue à deux lettres BCP 47 (par exemple es, de, it).
Traduisez chaque valeur de chaîne. Ne changez aucun nom de clé. Conservez tous les marqueurs d'interpolation ({{date}}, {{title}}, etc.) et les entités HTML exactement comme dans la source.
2. Enregistrer la locale dans i18next
Ouvrez src/i18n/index.js. Ajoutez un import en haut, à côté des autres :
import es from './locales/es.json'
Puis ajoutez la locale à l'objet resources dans i18next.init :
resources: {
en: { translation: en },
fr: { translation: fr },
da: { translation: da },
es: { translation: es }, // ← nouveau
},
3. Ajouter l'option dans le sélecteur des Réglages
Ouvrez src/views/SettingsView.vue et repérez l'élément <select> avec id="settings-language". Ajoutez une <option> après les autres :
<option value="es">Español</option>
Utilisez le nom natif de la langue comme libellé (pas le nom anglais), pour que les locuteurs puissent l'identifier sans avoir à lire l'anglais.
4. Mettre à jour le journal de décisions
Ajoutez une entrée dans docs/decisions-log.md consignant l'ajout et sa raison.
Liste de vérification
src/i18n/locales/<code>.jsoncréé et entièrement traduit- Import ajouté dans
src/i18n/index.js <option>ajoutée danssrc/views/SettingsView.vue- La langue est sélectionnable dans les Réglages et l'interface change correctement
docs/decisions-log.mdmis à jour
Ajouter un nouveau thème
Un thème est un ensemble nommé de surcharges de variables CSS, scopées à un attribut [data-theme='<name>']. L'application lit le thème actif depuis la base de données et pose cet attribut sur <html> avant le premier rendu.
src/styles/variables.css— définir le bloc de variables CSSsrc/i18n/locales/{en,fr,da}.json— ajouter le libellé d'affichage, dans toutes les langues prises en chargesrc/views/SettingsView.vue— ajouter l'<option>dans le sélecteur de thème- Test manuel dans le navigateur
docs/decisions-log.md— consigner la décision
1. Définir les variables CSS
Ouvrez src/styles/variables.css et ajoutez un nouveau bloc à la fin. Copiez le bloc :root comme point de départ et ne changez que les valeurs qui diffèrent du thème clair par défaut.
/* Mon thème */
[data-theme='<name>'] {
--bg-color1: ...;
--bg-color2: ...;
--front-color1: ...;
--front-color2: ...;
--navbar-bg-color: ...;
--navbar-front-color: ...;
--navbar-hover-bg-color: ...;
--navbar-hover-front-color: ...;
--actionbar-bg-color: ...;
--actionbar-font-color: ...;
--border-color: ...;
--input-bg: ...;
--input-border: ...;
--btn-primary-bg: ...;
--btn-primary-color: ...;
--btn-danger-bg: ...;
--btn-danger-color: ...;
--success-color: ...;
--warning-color: ...;
}
La valeur du sélecteur (par exemple trainus) devient la clé du thème partout ailleurs. Voir la table de référence des variables en bas de cette recette pour savoir ce que chacune affecte.
2. Ajouter le libellé d'affichage dans toutes les langues prises en charge
TrainUs propose déjà trois langues aujourd'hui — anglais, français et danois (voir « Ajouter une nouvelle langue » ci-dessus) — donc le libellé du nouveau thème doit avoir une entrée dans les trois fichiers de locale, pas seulement en anglais et en français. Ajoutez "themeMyName" à l'objet "settings", après "themeDark", dans chacun :
src/i18n/locales/en.json :
"themeMyName": "My Theme Label"
src/i18n/locales/fr.json :
"themeMyName": "Mon thème"
src/i18n/locales/da.json :
"themeMyName": "Mit tema"
Si une langue se retrouve sans la clé, i18next retombe sur fallbackLng: 'en' plutôt que de planter — mais ça vaut quand même le coup de le repérer pendant le test manuel ci-dessous, car un libellé resté en anglais dans une autre langue passe facilement inaperçu.
3. Ajouter l'option dans le sélecteur des réglages
Dans src/views/SettingsView.vue, repérez le bloc <select> du thème (recherchez settings-theme). Ajoutez une <option> après les autres :
<option value="<name>">{{ $t('settings.themeMyName') }}</option>
La value doit correspondre au nom du sélecteur défini à l'étape 1.
4. Test manuel
npm run dev- Ouvrez Réglages → Thème → sélectionnez votre nouveau thème.
- Vérifiez : la barre de navigation, le fond, les boutons et les champs s'affichent tous avec la nouvelle palette.
- Rechargez la page pour confirmer que le thème persiste (chargé depuis la base de données au démarrage).
- Parcourez chaque langue (anglais, français, danois) et vérifiez que le libellé du thème est bien traduit, sans retomber sur l'anglais.
- Exportez les réglages puis réimportez-les pour confirmer que la clé du thème survit à l'aller-retour.
5. Mettre à jour le journal de décisions
Ajoutez une entrée dans docs/decisions-log.md consignant l'ajout et sa raison.
Référence des variables
| Variable | Affecte |
|---|---|
--bg-color1 |
Fond principal de la page |
--bg-color2 |
Fond des cartes / surfaces secondaires |
--front-color1 |
Texte principal |
--front-color2 |
Texte secondaire / discret |
--navbar-bg-color |
Fond du menu de navigation latéral |
--navbar-front-color |
Texte et icônes du menu latéral |
--navbar-hover-bg-color |
Fond au survol d'un élément de menu |
--navbar-hover-front-color |
Texte au survol d'un élément de menu |
--actionbar-bg-color |
Fond de la barre d'action en haut |
--actionbar-font-color |
Texte et icônes de la barre d'action |
--border-color |
Bordures des cartes et des champs |
--input-bg |
Fond des champs de saisie |
--input-border |
Bordure des champs de saisie |
--btn-primary-bg |
Fond du bouton principal |
--btn-primary-color |
Texte du bouton principal |
--btn-danger-bg |
Fond du bouton danger / suppression |
--btn-danger-color |
Texte du bouton danger |
--success-color |
Messages et indicateurs de succès |
--warning-color |
Messages et indicateurs d'avertissement |
Liste de vérification
- Bloc de variables CSS ajouté dans
src/styles/variables.css - Libellé d'affichage ajouté dans toutes les langues prises en charge (anglais, français, danois)
<option>ajoutée danssrc/views/SettingsView.vue- Thème sélectionnable, persistant au rechargement, et qui survit à l'export/import
docs/decisions-log.mdmis à jour
Ajouter une migration de base de données
Demandez d'abord. Selon les règles du projet,
SCHEMA_VERSIONn'est incrémenté qu'une fois un schéma réellement déployé auprès des utilisateurs — et seulement après confirmation avec le responsable du projet. Ajouter une colonne directement dansSCHEMA_SQL(danssrc/db/schema.js) suffit pour les changements en place avant une publication ; aucune des étapes ci-dessous n'est nécessaire dans ce cas. Ne passez par une vraie migration que lorsque des utilisateurs existants ont déjà des données sous l'ancien schéma.
Une augmentation de SCHEMA_VERSION s'accompagne toujours d'exactement une entrée dans le registre RELEASES (src/db/releases.js), qui est la source de vérité unique lue à la fois par la migration au démarrage et par la vérification de compatibilité de Restaurer la base de données.
- Augmentez
SCHEMA_VERSIONdanssrc/db/schema.js. - Écrivez le SQL qui fait passer une base de données existante de l'ancienne version à la nouvelle.
- Ajoutez l'entrée correspondante dans
RELEASESdanssrc/db/releases.js. - Testez le chemin de mise à niveau sur une base encore à l'ancienne version.
- Mettez à jour la documentation de référence.
1. Augmenter la version
// src/db/schema.js
export const SCHEMA_VERSION = 2 // était 1
2. Écrire le script de migration
Un script de migration est du SQL classique — ALTER TABLE, remplissage de données, tout ce qui est nécessaire pour amener l'ancien schéma au niveau du nouveau. Il s'exécute dans la même transaction que l'estampillage schema_version, donc un échec partiel se rétablit proprement.
3. Déclarer la release
// src/db/releases.js
export const RELEASES = [
{ schemaVersion: 1, appVersion: '1.0.0', dbBreak: false, migrationScript: null },
{
schemaVersion: 2,
appVersion: '1.1.0',
dbBreak: true,
migrationScript: `ALTER TABLE exercise ADD COLUMN category TEXT;`,
},
]
dbBreak: falseavecmigrationScript: nullest une entrée « no-op » valide (seule la ligneschema_versionest estampillée) — à utiliser pour une augmentation de version qui n'a pas besoin de toucher aux données existantes.dbBreak: trueexige unmigrationScriptnon nul ;getMigrationScripts()lève une erreur si un script manque pour une release « breaking » dans la plage demandée.
4. Tester le chemin de mise à niveau
Deux chemins de code lisent RELEASES, et les deux doivent être vérifiés :
- Migration au démarrage : ouvrez l'application avec une base existante estampillée à l'ancien
schema_version. L'application doit afficher l'écran bloquant « téléchargez d'abord une sauvegarde », puis appliquer votre script et continuer avec les données intactes. - Restaurer la base de données : restaurez une sauvegarde
.sqlite3prise à l'ancienne version de schéma dans une version de l'application tournant sur la nouvelle —checkCompatibility()doit détecter l'écart et exécuter le même script pendant l'étape d'adaptation de la restauration.
Voir la [Référence]({{< relref "technical.fr.md" >}}) pour la machine à états complète de la migration et son diagramme de flux, et [Comprendre l'architecture]({{< relref "understanding-the-architecture.fr.md" >}}) pour le pourquoi de cette conception (sauvegarde forcée, migrations transactionnelles, échec sécurisé sur une base plus récente que l'application).
5. Mettre à jour la documentation
- Le tableau du schéma et le diagramme entité-relation dans la [Référence]({{< relref "technical.fr.md" >}})
docs/decisions-log.md, avec la date, la décision et la justification
Liste de vérification
- Confirmation obtenue du responsable du projet qu'une vraie augmentation de version (pas un changement en place) est justifiée
SCHEMA_VERSIONaugmenté- Entrée
RELEASESajoutée avec unmigrationScriptcorrect (ounullpour un no-op) - Migration au démarrage testée sur une base à l'ancienne version
- Adaptation de Restaurer la base de données testée sur une sauvegarde à l'ancienne version
- Documentation de référence et
docs/decisions-log.mdmis à jour
Déployer TrainUs
TrainUs est un site statique : npm run build génère tout ce qu'il faut dans dist/, prêt à être copié sur n'importe quel serveur web ou CDN. Le déploiement est unique : chaque nouvelle build remplace la précédente à la racine du site, sans dossiers par version. Le service worker gère les mises à jour de code côté client, et le système de migration au démarrage (voir [Référence]({{< relref "technical.fr.md" >}})) gère les changements de schéma de base de données, si bien que les mêmes données OPFS sont simplement conservées.
npm run build # génère les fichiers statiques dans dist/
npm run preview # prévisualiser la build de production en local
TrainUs utilise le VFS opfs-sahpool (voir la [Référence]({{< relref "technical.fr.md" >}})), qui n'a pas strictement besoin des en-têtes COOP/COEP. Les poser tout de même est recommandé par défense en profondeur, et ils pourraient devenir nécessaires si le VFS utilisé venait à changer — le serveur de développement les pose déjà par précaution :
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Nginx
location / {
add_header Cross-Origin-Opener-Policy "same-origin";
add_header Cross-Origin-Embedder-Policy "require-corp";
}
Apache
<IfModule mod_headers.c>
Header always set Cross-Origin-Opener-Policy "same-origin"
Header always set Cross-Origin-Embedder-Policy "require-corp"
</IfModule>
Caddy
header {
Cross-Origin-Opener-Policy "same-origin"
Cross-Origin-Embedder-Policy "require-corp"
}
Netlify (public/_headers)
/*
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
Vercel (vercel.json)
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
{ "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }
]
}
]
}
Liste de vérification
npm run buildterminé sans erreurdist/déployé à la racine du site, en remplaçant la build précédente- En-têtes COOP/COEP configurés sur le serveur (recommandé, pas strictement requis pour
opfs-sahpool) - L'application se charge et OPFS s'initialise correctement