Add multilingual support, competition close/reopen, and backup directory

This commit is contained in:
Jan Meinl
2026-05-17 09:18:34 +02:00
parent bb9f3cd3eb
commit 777f11d93c
18 changed files with 1039 additions and 433 deletions
+6 -13
View File
@@ -55,6 +55,9 @@ function navigate(page, params) {
// onlyIfMustChange: true — redirect AWAY if user must NOT change
async function bootstrapAuth(options) {
options = options || {};
// Make sure English (fallback) and the browser-detected language are loaded
// before we attempt to render anything.
await setLang(detectInitialLang());
let user = null;
try {
user = await API.me();
@@ -66,7 +69,7 @@ async function bootstrapAuth(options) {
return null;
}
if (!user) return null;
setLang(user.language || CURRENT_LANG);
await setLang(user.language || CURRENT_LANG);
if (user.must_change_password && options.forbidIfMustChange) {
navigate("forcePassword");
return null;
@@ -86,7 +89,7 @@ function renderTopbar(user, opts) {
const lang = e.target.value;
try { await API.updateMe({ language: lang }); } catch (_) {}
user.language = lang;
setLang(lang);
await setLang(lang);
location.reload();
} },
...I18N_AVAILABLE.map((l) => el("option", { value: l, selected: l === user.language }, I18N_NAMES[l]))
@@ -150,7 +153,7 @@ function openProfileModal(user) {
const u = await API.updateMe(body);
if (u.language !== user.language) {
user.language = u.language;
setLang(u.language);
await setLang(u.language);
}
ok.textContent = t("saved");
ok.style.display = "block";
@@ -174,13 +177,3 @@ function queryParams() {
return out;
}
// Initialize language from saved/browser preference before authenticated state
// is known.
(function initInitialLang() {
const userLang = navigator.language ? navigator.language.slice(0, 2) : "en";
if (typeof I18N_AVAILABLE !== "undefined" && I18N_AVAILABLE.includes(userLang)) {
setLang(userLang);
} else {
setLang("en");
}
})();