Implement en/fr localization across admin and user UIs
Introduce client-side localization helper and en/fr locale bundles. Route admin control, picks, movies, stats, winners and settings UIs through i18n keys instead of hardcoded text. Remove French text from the English UI and standardize shared messages (saving, network errors, confirmations). Update .gitignore to ignore editor metadata and localization helper artifacts.
This commit is contained in:
+35
-16
@@ -3,11 +3,29 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pool Oscars - Films</title>
|
||||
<title data-i18n="movies.title">Oscar Pool - Films</title>
|
||||
<script src="./js/app_theme.js"></script>
|
||||
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="./css/app.css" rel="stylesheet">
|
||||
<link rel="preload" as="image" href="img/logo_w.png">
|
||||
<style>
|
||||
/* Hide translatable content until translations are ready - prevents flash during page navigation */
|
||||
body:not(.i18n-ready) [data-i18n] {
|
||||
opacity: 0;
|
||||
transition: opacity 0.1s ease-in;
|
||||
}
|
||||
body.i18n-ready [data-i18n] {
|
||||
opacity: 1;
|
||||
}
|
||||
/* Fallback: show content after 2 seconds even if JS fails */
|
||||
body:not(.i18n-ready) [data-i18n] {
|
||||
animation: show-after-delay 0.1s 2s forwards;
|
||||
}
|
||||
@keyframes show-after-delay {
|
||||
to { opacity: 1; }
|
||||
}
|
||||
</style>
|
||||
<script src="./js/localization.js" defer></script>
|
||||
<script src="./js/app_header_boot.js" defer></script>
|
||||
<style>
|
||||
.navbar-custom {
|
||||
@@ -39,7 +57,7 @@
|
||||
<!-- Preloaded loader overlay to avoid initial "clear" flash -->
|
||||
<div id="page-loader-overlay" class="page-loader-overlay" data-preloaded="true" role="status" aria-live="polite" aria-busy="true">
|
||||
<div class="page-loader-card page-loader-card--baronly">
|
||||
<span class="visually-hidden">Chargement…</span>
|
||||
<span class="visually-hidden" data-i18n="common.loading">Loading…</span>
|
||||
<div class="page-loader-progress" aria-hidden="true">
|
||||
<div class="page-loader-bar" id="page-loader-bar" style="width: 8%;"></div>
|
||||
</div>
|
||||
@@ -58,16 +76,16 @@
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
<div class="navbar-nav">
|
||||
<a href="movies.html" class="nav-link btn btn-outline-light me-2">Films</a>
|
||||
<a href="checklist.html" class="nav-link btn btn-outline-light me-2">Checklist</a>
|
||||
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2">Stats</a>
|
||||
<a href="picks.html" class="nav-link btn btn-outline-light me-2" id="nav-link-picks" style="display: none;">Mes picks</a>
|
||||
<a id="admin-control-link" href="control.html" class="nav-link btn btn-warning me-2 d-none">Admin</a>
|
||||
<a href="movies.html" class="nav-link btn btn-outline-light me-2" data-i18n="nav.films">Films</a>
|
||||
<a href="checklist.html" class="nav-link btn btn-outline-light me-2" data-i18n="nav.checklist">Checklist</a>
|
||||
<a href="user-stat.html" class="nav-link btn btn-outline-light me-2" data-i18n="nav.stats">Stats</a>
|
||||
<a href="picks.html" class="nav-link btn btn-outline-light me-2" id="nav-link-picks" style="display: none;" data-i18n="nav.myPicks">My picks</a>
|
||||
<a id="admin-control-link" href="control.html" class="nav-link btn btn-warning me-2 d-none" data-i18n="nav.admin">Admin</a>
|
||||
</div>
|
||||
<!-- Move user info inside collapsible navbar and align it properly -->
|
||||
<div class="d-flex ms-auto mt-2 mt-lg-0 align-items-center gap-2 navbar-user">
|
||||
<span id="user-name" class="navbar-text" data-user-name></span>
|
||||
<button class="theme-toggle" type="button" data-theme-toggle role="switch" aria-checked="false" aria-label="Basculer le mode sombre">
|
||||
<button class="theme-toggle" type="button" data-theme-toggle role="switch" aria-checked="false" data-i18n-aria-label="common.toggleDarkMode" aria-label="Toggle dark mode">
|
||||
<span class="theme-toggle-icon theme-toggle-icon-sun" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="4"></circle>
|
||||
@@ -88,7 +106,7 @@
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<button id="log-off" class="btn btn-danger">Déconnexion</button>
|
||||
<button id="log-off" class="btn btn-danger" data-i18n="nav.logout">Log out</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -100,34 +118,35 @@
|
||||
<div class="card-body">
|
||||
<div class="d-flex flex-column gap-1">
|
||||
<div class="text-muted small">
|
||||
Dernière mise à jour des films: <span class="fw-semibold text-dark" id="movies-last-updated">—</span>
|
||||
<span data-i18n="movies.lastUpdated">Last movie update:</span> <span class="fw-semibold text-dark" id="movies-last-updated">—</span>
|
||||
</div>
|
||||
<div id="watched-ratio" class="fw-semibold">—</div>
|
||||
<div class="text-muted small">
|
||||
Temps avant les Oscars (<span id="oscar-date-day-month">—</span> <span id="oscar-year">—</span>) — <span id="time-left">—</span>
|
||||
<div class="text-muted small" id="time-until-oscars-container">
|
||||
<span data-i18n="movies.timeUntilOscarsLabel">Time until the Oscars</span>
|
||||
(<span id="oscar-date-day-month">—</span> <span id="oscar-year">—</span>) — <span id="time-left">—</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column flex-md-row align-items-start align-items-md-center justify-content-between gap-2 mt-3">
|
||||
<div class="form-check form-switch m-0">
|
||||
<input class="form-check-input" type="checkbox" id="flexSwitchCheckDefault">
|
||||
<label class="form-check-label" for="flexSwitchCheckDefault">Films non regardés seulement</label>
|
||||
<label class="form-check-label" for="flexSwitchCheckDefault" data-i18n="movies.unwatchedOnly">Unwatched films only</label>
|
||||
</div>
|
||||
<div class="text-muted small">Clique sur l’affiche ou le titre pour ouvrir le lecteur.</div>
|
||||
<div class="text-muted small" data-i18n="movies.clickToPlay">Click the poster or title to open the player.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="movies-list" class="row g-3 mt-1">
|
||||
<div class="col-12">
|
||||
<div class="text-center py-4 text-muted" aria-live="polite" aria-busy="true">Chargement…</div>
|
||||
<div class="text-center py-4 text-muted" aria-live="polite" aria-busy="true" data-i18n="common.loading">Loading…</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Footer Section -->
|
||||
<footer>
|
||||
<p id="footer-copy">Oscar Pool <span aria-hidden="true">·</span> <a id="copy" href="https://github.com/quoije/oscars-pool">quoije</a></p>
|
||||
<p id="footer-copy"><span data-i18n="footer.oscarPool">Oscar Pool</span> <span aria-hidden="true">·</span> <a id="copy" href="https://github.com/quoije/oscars-pool">quoije</a></p>
|
||||
<p id="footer-text"></p>
|
||||
</footer>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user