feat: i18n system - French/English internationalization
CI / lint (push) Failing after 20s
CI / test (push) Has been skipped
CI / build (push) Has been skipped
CI / e2e (push) Has been skipped
CI / security (push) Failing after 9s

Core: i18n.js module with t(), setLocale(), initI18n()
- Flat key→string JSON locale files (fr.json + en.json, 165 keys)
- data-i18n / data-i18n-placeholder / data-i18n-attr DOM attributes
- Live locale switch via setLocale() - no page reload
- Language detection: localStorage > navigator.language > 'fr'
- Fallback: missing key → French → raw key

Wired into:
- app.js: await initI18n() early in init()
- config.js: profile save → await setLocale(), toasts + confirm via t()
- auth.js: network error toast via t()
- index.html: data-i18n on login form, profile section, search placeholder
This commit is contained in:
2026-06-18 13:31:11 -04:00
parent daab917ed1
commit f85482214e
7 changed files with 718 additions and 24 deletions
+16 -15
View File
@@ -184,11 +184,11 @@
<span class="login-logo-icon">📖</span>
<span class="login-logo-text">ObsiGate</span>
</div>
<p class="login-subtitle">Accès sécurisé à vos vaults</p>
<p class="login-subtitle" data-i18n="auth.login_title">Accès sécurisé à vos vaults</p>
</div>
<form id="login-form" class="login-form" autocomplete="on">
<div class="form-group">
<label for="login-username">Nom d'utilisateur</label>
<label for="login-username" data-i18n="auth.username">Nom d'utilisateur</label>
<input
type="text"
id="login-username"
@@ -200,7 +200,7 @@
/>
</div>
<div class="form-group">
<label for="login-password">Mot de passe</label>
<label for="login-password" data-i18n="auth.password">Mot de passe</label>
<div class="password-input-wrapper">
<input
type="password"
@@ -227,12 +227,12 @@
id="remember-me"
name="remember_me"
/>
<span>Se souvenir de moi (30 jours)</span>
<span data-i18n="auth.remember_me">Se souvenir de moi (30 jours)</span>
</label>
</div>
<div id="login-error" class="login-error hidden"></div>
<button type="submit" id="login-btn" class="btn-login">
<span class="btn-text">Se connecter</span>
<span class="btn-text" data-i18n="auth.login_button">Se connecter</span>
<span class="btn-spinner hidden">⏳</span>
</button>
</form>
@@ -290,6 +290,7 @@
<input
type="text"
id="search-input"
data-i18n-placeholder="header.search_placeholder"
placeholder="Rechercher ..."
autocomplete="off"
/>
@@ -2021,29 +2022,29 @@
class="config-section help-section"
id="cfg-profile"
>
<h2>👤 Profil utilisateur</h2>
<p class="config-description">
Preferences personnelles pour personnaliser
l'experience ObsiGate.
<h2 data-i18n="config.profile">👤 Profil utilisateur</h2>
<p class="config-description" data-i18n="config.profile_desc">
Préférences personnelles pour personnaliser
l'expérience ObsiGate.
</p>
<div class="profile-form" id="profile-form">
<div class="profile-field">
<label for="profile-lang">Langue preferee</label>
<label for="profile-lang" data-i18n="config.lang_label">Langue préférée</label>
<select id="profile-lang" class="config-select">
<option value="fr">Francais</option>
<option value="en">English</option>
<option value="es">Espanol</option>
<option value="de">Deutsch</option>
</select>
<span class="profile-hint">Utilisee par l'autocompletion et le ghost text.</span>
<span class="profile-hint" data-i18n="config.lang_hint">Utilisée par l'autocomplétion et le ghost text.</span>
</div>
<div class="profile-field">
<label for="profile-name">Nom d'affichage</label>
<label for="profile-name" data-i18n="config.display_name">Nom d'affichage</label>
<input type="text" id="profile-name" class="config-input" placeholder="Votre nom" maxlength="60">
</div>
<button class="config-save-btn" id="profile-save">Enregistrer</button>
<button class="config-save-btn" id="profile-logout" style="background:var(--danger-bg);color:var(--danger);border-color:var(--danger);margin-left:8px">Deconnexion</button>
<span class="profile-saved" id="profile-saved" style="display:none">✓ Sauvegarde</span>
<button class="config-save-btn" id="profile-save" data-i18n="config.save">Enregistrer</button>
<button class="config-save-btn" id="profile-logout" style="background:var(--danger-bg);color:var(--danger);border-color:var(--danger);margin-left:8px" data-i18n="config.logout">Déconnexion</button>
<span class="profile-saved" id="profile-saved" style="display:none" data-i18n="config.saved">✓ Sauvegardé</span>
</div>
</section>