- Implement PKCE (Proof Key for Code Exchange) with S256 method - Add crypto/pkce module with code verifier and challenge generation - Modify OAuth flow to include code_challenge in authorization requests - Update HandleCallback to validate code_verifier during token exchange - Extend session lifetime from 7 to 30 days - Add comprehensive unit tests for PKCE functions - Maintain backward compatibility with fallback for non-PKCE sessions - Add detailed logging for OAuth flow with PKCE tracking PKCE enhances security by preventing authorization code interception attacks, as recommended by OAuth 2.1 and OIDC standards. feat: add encrypted refresh token storage with automatic cleanup - Add oauth_sessions table for storing encrypted refresh tokens - Implement AES-256-GCM encryption for refresh tokens using cookie secret - Create OAuth session repository with full CRUD operations - Add SessionWorker for automatic cleanup of expired sessions - Configure cleanup to run every 24h for sessions older than 37 days - Modify OAuth flow to store refresh tokens after successful authentication - Track client IP and user agent for session security validation - Link OAuth sessions to user sessions via session ID - Add comprehensive encryption tests with security validations - Integrate SessionWorker into server lifecycle with graceful shutdown This enables persistent OAuth sessions with secure token storage, reducing the need for frequent re-authentication from 7 to 30 days.
5.6 KiB
Internationalisation (i18n)
Support multilingue complet du frontend Ackify.
Langues Supportées
- 🇫🇷 Français (par défaut)
- 🇬🇧 English (fallback)
- 🇪🇸 Español
- 🇩🇪 Deutsch
- 🇮🇹 Italiano
Frontend (Vue.js)
Sélection de Langue
Le frontend détecte automatiquement la langue via :
- localStorage - Choix utilisateur sauvegardé
- navigator.language - Langue du navigateur
- Fallback - English si non supportée
Switcher de Langue
Interface utilisateur avec drapeaux Unicode :
🇫🇷 FR | 🇬🇧 EN | 🇪🇸 ES | 🇩🇪 DE | 🇮🇹 IT
Clic → Langue change + sauvegarde dans localStorage
Fichiers de Traduction
Localisés dans /webapp/src/locales/ :
locales/
├── fr.json # Français
├── en.json # English
├── es.json # Español
├── de.json # Deutsch
└── it.json # Italiano
Structure JSON
{
"home": {
"title": "Ackify - Proof of Read",
"subtitle": "Signatures cryptographiques de lecture"
},
"document": {
"sign": "Signer ce document",
"signed": "Document signé",
"signatures": "{count} confirmation | {count} confirmations"
}
}
Pluralisation :
"signatures": "{count} confirmation | {count} confirmations"
Usage :
{{ $t('document.signatures', { count: 42 }) }}
// → "42 confirmations"
Backend (Go)
Templates Email
Les emails utilisent des templates multilingues dans /backend/templates/emails/ :
templates/emails/
├── fr/
│ ├── reminder.html
│ └── reminder.txt
├── en/
│ ├── reminder.html
│ └── reminder.txt
├── es/...
├── de/...
└── it/...
Envoi avec Locale
POST /api/v1/admin/documents/doc_id/reminders
Content-Type: application/json
{
"emails": ["user@company.com"],
"locale": "fr"
}
Le backend charge le template fr/reminder.html.
Configuration
# Langue par défaut pour les emails (défaut: en)
ACKIFY_MAIL_DEFAULT_LOCALE=fr
Ajouter une Langue
Frontend
- Créer le fichier de traduction :
cd webapp/src/locales
cp en.json pt.json # Portugais
- Traduire :
{
"home": {
"title": "Ackify - Prova de Leitura",
"subtitle": "Assinaturas criptográficas de leitura"
}
}
- Enregistrer dans i18n :
// webapp/src/i18n.ts
import pt from './locales/pt.json'
const i18n = createI18n({
locale: 'fr',
fallbackLocale: 'en',
messages: {
fr, en, es, de, it,
pt // Ajouter ici
}
})
- Ajouter au sélecteur :
<!-- components/LanguageSwitcher.vue -->
<button @click="changeLocale('pt')">🇵🇹 PT</button>
Backend
- Créer le répertoire :
mkdir -p backend/templates/emails/pt
- Créer les templates :
cp backend/templates/emails/en/reminder.html backend/templates/emails/pt/
cp backend/templates/emails/en/reminder.txt backend/templates/emails/pt/
-
Traduire les templates
-
Rebuild :
docker compose up -d --force-recreate ackify-ce --build
Vérification i18n
Script de Validation
Le projet inclut un script pour vérifier la complétude des traductions :
cd webapp
npm run lint:i18n
Output :
✅ fr.json - 156 keys
✅ en.json - 156 keys
✅ es.json - 156 keys
✅ de.json - 156 keys
✅ it.json - 156 keys
All translations are complete!
CI/CD
Le script s'exécute automatiquement dans GitHub Actions pour bloquer les PRs avec traductions manquantes.
Bonnes Pratiques
Clés de Traduction
- ✅ Utiliser des clés structurées :
feature.action.label - ✅ Grouper par page/composant
- ✅ Éviter les clés trop génériques (
button,title) - ✅ Utiliser des placeholders :
{count},{name}
Exemple :
{
"admin": {
"documents": {
"list": {
"title": "Liste des documents",
"count": "{count} document | {count} documents"
}
}
}
}
Synchronisation
Lors de l'ajout de nouvelles clés en français :
# Sync script (à créer)
node scripts/sync-i18n-from-fr.js
Copie automatiquement les nouvelles clés vers les autres langues avec [TODO].
Textes Longs
Pour les textes longs, utiliser des arrays :
{
"help": {
"intro": [
"Ackify permet de créer des signatures cryptographiques.",
"Chaque signature est horodatée et non-répudiable.",
"Les données sont stockées de manière immuable."
]
}
}
Usage :
<p v-for="line in $tm('help.intro')" :key="line">
{{ line }}
</p>
Formats Spécifiques
Dates
// Formater avec la locale courante
import { useI18n } from 'vue-i18n'
const { locale } = useI18n()
const formatted = new Date().toLocaleDateString(locale.value, {
year: 'numeric',
month: 'long',
day: 'numeric'
})
// fr: "15 janvier 2025"
// en: "January 15, 2025"
Nombres
const formatted = (42000).toLocaleString(locale.value)
// fr: "42 000"
// en: "42,000"
SEO & Meta Tags
Les meta tags sont traduits dynamiquement :
<script setup>
import { useI18n } from 'vue-i18n'
import { useHead } from '@vueuse/head'
const { t } = useI18n()
useHead({
title: t('home.title'),
meta: [
{ name: 'description', content: t('home.description') }
]
})
</script>
Documentation Complète
Pour plus de détails sur l'implémentation i18n du frontend, voir :
Ce fichier contient :
- Architecture complète vue-i18n
- Guide de contribution
- Scripts de synchronisation
- Exemples avancés