refactor(ui): i18n: remove unnecessary wrappers

This commit is contained in:
Edouard Vanbelle
2026-04-25 23:19:36 +02:00
parent 4e2029969e
commit 75d3984b8f
8 changed files with 223 additions and 272 deletions
+27 -32
View File
@@ -3,11 +3,6 @@ import { i18n } from '../../core/i18n.js';
const API = '/api';
/* ── i18n helper ── */
function t(key, params) {
return i18n.t(key, params);
}
function headers() {
return { 'Content-Type': 'application/json', ...getCsrfHeaders() };
}
@@ -21,14 +16,14 @@ function formatBytes(bytes) {
}
function timeAgo(dateStr) {
if (!dateStr) return t('profile.never');
if (!dateStr) return i18n.t('profile.never');
const d = new Date(dateStr);
const now = new Date();
const secs = Math.floor((now - d) / 1000);
if (secs < 60) return t('profile.just_now');
if (secs < 3600) return t('profile.minutes_ago', { n: Math.floor(secs / 60) });
if (secs < 86400) return t('profile.hours_ago', { n: Math.floor(secs / 3600) });
if (secs < 2592000) return t('profile.days_ago', { n: Math.floor(secs / 86400) });
if (secs < 60) return i18n.t('profile.just_now');
if (secs < 3600) return i18n.t('profile.minutes_ago', { n: Math.floor(secs / 60) });
if (secs < 86400) return i18n.t('profile.hours_ago', { n: Math.floor(secs / 3600) });
if (secs < 2592000) return i18n.t('profile.days_ago', { n: Math.floor(secs / 86400) });
return d.toLocaleDateString();
}
@@ -52,15 +47,15 @@ async function init() {
const badge = document.getElementById('p-role-badge');
if (user.role === 'admin') {
badge.className = 'role-badge role-badge-admin';
badge.innerHTML = `<i class="fas fa-shield-alt"></i> ${t('profile.role_admin')}`;
badge.innerHTML = `<i class="fas fa-shield-alt"></i> ${i18n.t('profile.role_admin')}`;
} else {
badge.className = 'role-badge role-badge-user';
badge.innerHTML = `<i class="fas fa-user"></i> ${t('profile.role_user')}`;
badge.innerHTML = `<i class="fas fa-user"></i> ${i18n.t('profile.role_user')}`;
}
document.getElementById('p-detail-username').textContent = user.username;
document.getElementById('p-detail-email').textContent = user.email || '—';
document.getElementById('p-detail-role').textContent = user.role === 'admin' ? t('profile.role_admin') : t('profile.role_user');
document.getElementById('p-detail-role').textContent = user.role === 'admin' ? i18n.t('profile.role_admin') : i18n.t('profile.role_user');
document.getElementById('p-detail-login').textContent = timeAgo(user.last_login_at);
const used = user.storage_used_bytes || 0;
@@ -74,7 +69,7 @@ async function init() {
const bar = document.getElementById('p-storage-bar');
bar.style.width = `${pct}%`;
bar.className = `storage-fill ${pct > 90 ? 'red' : pct > 70 ? 'orange' : 'green'}`;
document.getElementById('p-storage-text').textContent = `${formatBytes(used)} / ${quota > 0 ? formatBytes(quota) : t('profile.unlimited')}`;
document.getElementById('p-storage-text').textContent = `${formatBytes(used)} / ${quota > 0 ? formatBytes(quota) : i18n.t('profile.unlimited')}`;
if (user.auth_provider && user.auth_provider !== 'local') {
document.getElementById('password-section').classList.add('hidden');
@@ -115,18 +110,18 @@ async function changePassword(e) {
const statusEl = document.getElementById('pw-status');
if (newPw !== confirmPw) {
statusEl.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${escapeHtml(t('profile.passwords_no_match'))}</div>`;
statusEl.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${escapeHtml(i18n.t('profile.passwords_no_match'))}</div>`;
return false;
}
if (newPw.length < 8) {
statusEl.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${escapeHtml(t('profile.password_too_short'))}</div>`;
statusEl.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${escapeHtml(i18n.t('profile.password_too_short'))}</div>`;
return false;
}
const btn = document.getElementById('pw-submit');
btn.disabled = true;
btn.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${escapeHtml(t('profile.updating'))}`;
btn.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${escapeHtml(i18n.t('profile.updating'))}`;
try {
const resp = await fetch(`${API}/auth/change-password`, {
@@ -140,24 +135,24 @@ async function changePassword(e) {
});
if (resp.ok) {
statusEl.innerHTML = `<div class="alert alert-success"><i class="fas fa-check-circle"></i> ${escapeHtml(t('profile.password_updated'))}</div>`;
statusEl.innerHTML = `<div class="alert alert-success"><i class="fas fa-check-circle"></i> ${escapeHtml(i18n.t('profile.password_updated'))}</div>`;
document.getElementById('password-form').reset();
} else {
const err = await resp.json().catch(() => ({}));
statusEl.innerHTML =
'<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' +
escapeHtml(err.message || t('profile.password_change_failed')) +
escapeHtml(err.message || i18n.t('profile.password_change_failed')) +
'</div>';
}
} catch (err) {
statusEl.innerHTML =
'<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' +
escapeHtml(t('profile.error_network', { message: err.message })) +
escapeHtml(i18n.t('profile.error_network', { message: err.message })) +
'</div>';
}
btn.disabled = false;
btn.innerHTML = `<i class="fas fa-save"></i> ${escapeHtml(t('profile.update_password'))}`;
btn.innerHTML = `<i class="fas fa-save"></i> ${escapeHtml(i18n.t('profile.update_password'))}`;
return false;
}
@@ -176,15 +171,15 @@ function renderPwRow(pw) {
const created = document.createElement('td');
created.textContent = new Date(pw.created_at).toLocaleDateString();
const lastUsed = document.createElement('td');
lastUsed.textContent = pw.last_used_at ? timeAgo(pw.last_used_at) : t('profile.never');
lastUsed.textContent = pw.last_used_at ? timeAgo(pw.last_used_at) : i18n.t('profile.never');
const status = document.createElement('td');
const badge = document.createElement('span');
if (pw.active !== false) {
badge.className = 'badge badge-active';
badge.textContent = t('profile.active');
badge.textContent = i18n.t('profile.active');
} else {
badge.className = 'badge badge-expired';
badge.textContent = t('profile.revoked');
badge.textContent = i18n.t('profile.revoked');
}
status.appendChild(badge);
const actions = document.createElement('td');
@@ -192,7 +187,7 @@ function renderPwRow(pw) {
const btn = document.createElement('button');
btn.className = 'btn btn-danger-sm';
btn.innerHTML = '<i class="fas fa-trash"></i>';
btn.title = t('profile.revoke_title');
btn.title = i18n.t('profile.revoke_title');
btn.addEventListener('click', () => {
revokeAppPassword(pw.id, pw.label);
});
@@ -264,12 +259,12 @@ async function createAppPassword() {
const btn = document.getElementById('app-pw-generate');
if (!label) {
statusEl.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${escapeHtml(t('profile.error_label_required'))}</div>`;
statusEl.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${escapeHtml(i18n.t('profile.error_label_required'))}</div>`;
return;
}
btn.disabled = true;
btn.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${escapeHtml(t('profile.generating'))}`;
btn.innerHTML = `<i class="fas fa-spinner fa-spin"></i> ${escapeHtml(i18n.t('profile.generating'))}`;
statusEl.innerHTML = '';
try {
@@ -283,7 +278,7 @@ async function createAppPassword() {
const err = await resp.json().catch(() => ({}));
statusEl.innerHTML =
'<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ' +
escapeHtml(err.message || t('profile.error_create_pw')) +
escapeHtml(err.message || i18n.t('profile.error_create_pw')) +
'</div>';
return;
}
@@ -297,7 +292,7 @@ async function createAppPassword() {
statusEl.innerHTML = `<div class="alert alert-error"><i class="fas fa-exclamation-circle"></i> ${err.message}</div>`;
} finally {
btn.disabled = false;
btn.innerHTML = `<i class="fas fa-plus"></i> ${escapeHtml(t('profile.generate'))}`;
btn.innerHTML = `<i class="fas fa-plus"></i> ${escapeHtml(i18n.t('profile.generate'))}`;
}
}
@@ -313,7 +308,7 @@ function copyAppPassword() {
}
async function revokeAppPassword(id, label) {
if (!confirm(t('profile.confirm_revoke', { label: label }))) return;
if (!confirm(i18n.t('profile.confirm_revoke', { label: label }))) return;
try {
const resp = await fetch(`${API}/auth/app-passwords/${encodeURIComponent(id)}`, {
method: 'DELETE',
@@ -325,10 +320,10 @@ async function revokeAppPassword(id, label) {
loadAppPasswords();
} else {
const err = await resp.json().catch(() => ({}));
alert(err.message || t('profile.error_revoke'));
alert(err.message || i18n.t('profile.error_revoke'));
}
} catch (err) {
alert(t('profile.error_network', { message: err.message }));
alert(i18n.t('profile.error_network', { message: err.message }));
}
}