i18n(session): add missing translations

This commit is contained in:
Edouard Vanbelle
2026-08-09 14:04:42 +02:00
parent bbef8afb7b
commit 321f3ad733
19 changed files with 373 additions and 3 deletions
+9 -2
View File
@@ -35,7 +35,10 @@ const SERVER_STATUS_HEADER = 'x-server-status';
const REFRESH_ENDPOINT = '/api/auth/refresh';
/** Auth primitives — a 401 here is genuine, never an expired access token. */
/** Auth primitives — a 401 here is genuine, never an expired access token.
* Also used by the session-teardown gate to exempt endpoints that must
* still fire during / immediately after a logout (the logout POST itself,
* and every login path a user might retry on the /login landing). */
const AUTH_PRIMITIVES = [
'/api/auth/login',
'/api/auth/logout',
@@ -43,7 +46,11 @@ const AUTH_PRIMITIVES = [
'/api/auth/register',
'/api/auth/setup',
'/api/auth/oidc/',
'/api/auth/device/'
'/api/auth/device/',
'/api/auth/opaque/',
'/api/auth/magic-link/',
'/api/auth/status',
'/api/auth/dpop/'
];
export type FetchFn = typeof fetch;
+5 -1
View File
@@ -524,7 +524,11 @@
// landing from `?source=session_expired` (auto-divert on 401 →
// refresh 401). The login page reads the flag, shows the success
// notice, and skips its existing-session probe.
await goto(resolve('/login?source=logged_out'));
// `resolve()` from `$app/paths` normalises a route-id (adds base
// path prefix); it does NOT accept a query string. Concatenate
// the `?source=logged_out` marker AFTER resolve so the login
// page's onMount branch actually sees it.
await goto(resolve('/login') + '?source=logged_out');
}
</script>
@@ -7,6 +7,7 @@
* folder and land on the shared-with-me view.
*/
import { bindDpopIfPossible, fetchMe, tryRefresh } from '$lib/api/endpoints/auth';
import { setLogoutInProgress } from '$lib/api/client';
import { drives } from '$lib/stores/drives.svelte';
import type { User } from '$lib/api/types';
import { ensureActiveUser } from '$lib/utils/localStoragePrefs';
@@ -77,6 +78,12 @@ class SessionStore {
setUser(user: User): void {
this.user = user;
ensureActiveUser(user.id);
// Any successful login clears the session-teardown gate. Without
// this, a logout → login within the same SPA session leaves the
// gate stuck at `true` — the login POST is exempted via
// `AUTH_PRIMITIVES`, but the /me + /drives + … fetches the app
// fires post-login would all abort with "Session terminated".
setLogoutInProgress(false);
}
/**
+22
View File
@@ -843,6 +843,28 @@
"quotas": "الحصص",
"reset_pw_for": "كلمة مرور جديدة لـ",
"role": "الدور",
"sessions": {
"filter_user": "المستخدم (UUID)",
"include_revoked": "تضمين الملغاة / المنتهية",
"refresh": "تحديث",
"col_user": "المستخدم",
"col_created": "تم الإنشاء",
"col_expires": "تنتهي في",
"col_ip": "IP",
"col_user_agent": "وكيل المستخدم",
"col_bound": "مرتبطة",
"col_status": "الحالة",
"current_tooltip": "هذه هي الجلسة التي تستخدمها حاليًا — إلغاؤها سيؤدي إلى تسجيل خروجك.",
"bound_tooltip": "مرتبطة بـ DPoP (jkt {{prefix}}…)",
"unbound": "غير مرتبطة",
"revoked": "ملغاة",
"expired": "منتهية",
"active": "نشطة",
"revoke": "إلغاء",
"empty": "لا توجد جلسات مطابقة للتصفية الحالية.",
"revoke_self_confirm": "⚠️ هذه جلستك الحالية. إلغاؤها سيؤدي إلى تسجيل خروجك فورًا وعليك تسجيل الدخول مرة أخرى. هل تريد المتابعة؟",
"revoke_confirm": "إلغاء هذه الجلسة؟ سيتلقى المتصفح رمز 401 عند الطلب التالي."
},
"smtp_fail": "فشل الإرسال.",
"smtp_send": "إرسال",
"smtp_test": "إرسال بريد اختباري",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "Kontingente",
"reset_pw_for": "Neues Passwort für",
"role": "Rolle",
"sessions": {
"filter_user": "Benutzer (UUID)",
"include_revoked": "Widerrufene / abgelaufene einschließen",
"refresh": "Aktualisieren",
"col_user": "Benutzer",
"col_created": "Erstellt",
"col_expires": "Läuft ab",
"col_ip": "IP",
"col_user_agent": "User Agent",
"col_bound": "Gebunden",
"col_status": "Status",
"current_tooltip": "Dies ist die Sitzung, die Sie gerade nutzen — der Widerruf meldet Sie ab.",
"bound_tooltip": "DPoP-gebunden (jkt {{prefix}}…)",
"unbound": "ungebunden",
"revoked": "widerrufen",
"expired": "abgelaufen",
"active": "aktiv",
"revoke": "Widerrufen",
"empty": "Keine Sitzungen entsprechen dem aktuellen Filter.",
"revoke_self_confirm": "⚠️ Dies ist IHRE aktuelle Sitzung. Wenn Sie sie widerrufen, werden Sie sofort abgemeldet und müssen sich neu anmelden. Fortfahren?",
"revoke_confirm": "Diese Sitzung widerrufen? Die nächste Anfrage von diesem Browser erhält 401."
},
"smtp_fail": "Senden fehlgeschlagen.",
"smtp_send": "Senden",
"smtp_test": "Test-E-Mail senden",
+22
View File
@@ -1115,6 +1115,28 @@
"registration_disabled_warning": "Public registration is disabled. Only admins can create new accounts.",
"reset_pw_for": "New password for",
"role": "Role",
"sessions": {
"filter_user": "User (UUID)",
"include_revoked": "Include revoked / expired",
"refresh": "Refresh",
"col_user": "User",
"col_created": "Created",
"col_expires": "Expires",
"col_ip": "IP",
"col_user_agent": "User agent",
"col_bound": "Bound",
"col_status": "Status",
"current_tooltip": "This is the session you're using right now — revoking it will log you out.",
"bound_tooltip": "DPoP-bound (jkt {{prefix}}…)",
"unbound": "unbound",
"revoked": "revoked",
"expired": "expired",
"active": "active",
"revoke": "Revoke",
"empty": "No sessions match the current filter.",
"revoke_self_confirm": "⚠️ This is YOUR current session. Revoking it will log YOU out immediately and you'll have to sign back in. Continue?",
"revoke_confirm": "Revoke this session? The next request from that browser will 401."
},
"settings_saved_ok": "Settings saved.",
"smtp": "Email (SMTP)",
"smtp_fail": "Send failed.",
+22
View File
@@ -848,6 +848,28 @@
"quotas": "Cuotas",
"reset_pw_for": "Nueva contraseña para",
"role": "Rol",
"sessions": {
"filter_user": "Usuario (UUID)",
"include_revoked": "Incluir revocadas / caducadas",
"refresh": "Actualizar",
"col_user": "Usuario",
"col_created": "Creada",
"col_expires": "Caduca",
"col_ip": "IP",
"col_user_agent": "Agente de usuario",
"col_bound": "Vinculada",
"col_status": "Estado",
"current_tooltip": "Esta es la sesión que está usando ahora mismo — al revocarla se cerrará su sesión.",
"bound_tooltip": "Vinculada con DPoP (jkt {{prefix}}…)",
"unbound": "no vinculada",
"revoked": "revocada",
"expired": "caducada",
"active": "activa",
"revoke": "Revocar",
"empty": "Ninguna sesión coincide con el filtro actual.",
"revoke_self_confirm": "⚠️ Esta es SU sesión actual. Al revocarla se cerrará su sesión inmediatamente y tendrá que iniciar sesión de nuevo. ¿Continuar?",
"revoke_confirm": "¿Revocar esta sesión? La próxima petición desde ese navegador devolverá 401."
},
"smtp_fail": "Fallo al enviar.",
"smtp_send": "Enviar",
"smtp_test": "Enviar correo de prueba",
+22
View File
@@ -826,6 +826,28 @@
"quotas": "سهمیه‌ها",
"reset_pw_for": "رمز جدید برای",
"role": "نقش",
"sessions": {
"filter_user": "کاربر (UUID)",
"include_revoked": "شامل لغو‌شده‌ها / منقضی‌شده‌ها",
"refresh": "به‌روزرسانی",
"col_user": "کاربر",
"col_created": "ایجاد شده",
"col_expires": "انقضا",
"col_ip": "IP",
"col_user_agent": "عامل کاربر",
"col_bound": "متصل",
"col_status": "وضعیت",
"current_tooltip": "این همان نشستی است که هم‌اکنون از آن استفاده می‌کنید — لغو آن شما را خارج می‌کند.",
"bound_tooltip": "متصل به DPoP (jkt {{prefix}}…)",
"unbound": "متصل نیست",
"revoked": "لغو شده",
"expired": "منقضی",
"active": "فعال",
"revoke": "لغو",
"empty": "هیچ نشستی با فیلتر فعلی مطابقت ندارد.",
"revoke_self_confirm": "⚠️ این نشست فعلی شماست. با لغو آن، بلافاصله خارج می‌شوید و باید دوباره وارد شوید. ادامه؟",
"revoke_confirm": "این نشست لغو شود؟ درخواست بعدی از آن مرورگر با 401 پاسخ داده می‌شود."
},
"smtp_fail": "ارسال ناموفق.",
"smtp_send": "ارسال",
"smtp_test": "ارسال ایمیل آزمایشی",
+22
View File
@@ -854,6 +854,28 @@
"quotas": "Quotas",
"reset_pw_for": "Nouveau mot de passe pour",
"role": "Rôle",
"sessions": {
"filter_user": "Utilisateur (UUID)",
"include_revoked": "Inclure les révoquées / expirées",
"refresh": "Actualiser",
"col_user": "Utilisateur",
"col_created": "Créée",
"col_expires": "Expire",
"col_ip": "IP",
"col_user_agent": "Agent utilisateur",
"col_bound": "Liée",
"col_status": "Statut",
"current_tooltip": "Il s'agit de la session que vous utilisez actuellement — la révoquer vous déconnectera.",
"bound_tooltip": "Liée par DPoP (jkt {{prefix}}…)",
"unbound": "non liée",
"revoked": "révoquée",
"expired": "expirée",
"active": "active",
"revoke": "Révoquer",
"empty": "Aucune session ne correspond au filtre actuel.",
"revoke_self_confirm": "⚠️ Il s'agit de VOTRE session actuelle. La révoquer vous déconnectera immédiatement et vous devrez vous reconnecter. Continuer ?",
"revoke_confirm": "Révoquer cette session ? La prochaine requête depuis ce navigateur renverra 401."
},
"smtp_fail": "Échec de l'envoi.",
"smtp_send": "Envoyer",
"smtp_test": "Envoyer l'e-mail de test",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "कोटा",
"reset_pw_for": "नया पासवर्ड",
"role": "भूमिका",
"sessions": {
"filter_user": "उपयोगकर्ता (UUID)",
"include_revoked": "रद्द / समाप्त शामिल करें",
"refresh": "ताज़ा करें",
"col_user": "उपयोगकर्ता",
"col_created": "बनाई गई",
"col_expires": "समाप्त होगी",
"col_ip": "IP",
"col_user_agent": "उपयोगकर्ता एजेंट",
"col_bound": "बद्ध",
"col_status": "स्थिति",
"current_tooltip": "यह वह सत्र है जिसे आप अभी उपयोग कर रहे हैं — इसे रद्द करने पर आप साइन आउट हो जाएंगे।",
"bound_tooltip": "DPoP से बद्ध (jkt {{prefix}}…)",
"unbound": "अबद्ध",
"revoked": "रद्द की गई",
"expired": "समाप्त",
"active": "सक्रिय",
"revoke": "रद्द करें",
"empty": "वर्तमान फ़िल्टर से कोई सत्र मेल नहीं खाता।",
"revoke_self_confirm": "⚠️ यह आपका वर्तमान सत्र है। इसे रद्द करने पर आप तुरंत साइन आउट हो जाएंगे और आपको दोबारा साइन इन करना होगा। जारी रखें?",
"revoke_confirm": "इस सत्र को रद्द करें? उस ब्राउज़र से अगला अनुरोध 401 होगा।"
},
"smtp_fail": "भेजना विफल।",
"smtp_send": "भेजें",
"smtp_test": "परीक्षण ईमेल भेजें",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "Quote",
"reset_pw_for": "Nuova password per",
"role": "Ruolo",
"sessions": {
"filter_user": "Utente (UUID)",
"include_revoked": "Includi revocate / scadute",
"refresh": "Aggiorna",
"col_user": "Utente",
"col_created": "Creata",
"col_expires": "Scade",
"col_ip": "IP",
"col_user_agent": "User agent",
"col_bound": "Collegata",
"col_status": "Stato",
"current_tooltip": "Questa è la sessione che stai usando adesso — revocarla ti disconnetterà.",
"bound_tooltip": "Collegata a DPoP (jkt {{prefix}}…)",
"unbound": "non collegata",
"revoked": "revocata",
"expired": "scaduta",
"active": "attiva",
"revoke": "Revoca",
"empty": "Nessuna sessione corrisponde al filtro attuale.",
"revoke_self_confirm": "⚠️ Questa è la TUA sessione corrente. Revocarla ti disconnetterà immediatamente e dovrai accedere di nuovo. Continuare?",
"revoke_confirm": "Revocare questa sessione? La prossima richiesta da quel browser risponderà 401."
},
"smtp_fail": "Invio non riuscito.",
"smtp_send": "Invia",
"smtp_test": "Invia email di prova",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "クォータ",
"reset_pw_for": "新しいパスワード:",
"role": "役割",
"sessions": {
"filter_user": "ユーザー (UUID)",
"include_revoked": "取り消し済み / 期限切れを含む",
"refresh": "更新",
"col_user": "ユーザー",
"col_created": "作成日時",
"col_expires": "有効期限",
"col_ip": "IP",
"col_user_agent": "ユーザーエージェント",
"col_bound": "バインド",
"col_status": "状態",
"current_tooltip": "これは現在使用中のセッションです — 取り消すとサインアウトされます。",
"bound_tooltip": "DPoP にバインド済み (jkt {{prefix}}…)",
"unbound": "バインドなし",
"revoked": "取り消し済み",
"expired": "期限切れ",
"active": "有効",
"revoke": "取り消し",
"empty": "現在のフィルターに一致するセッションはありません。",
"revoke_self_confirm": "⚠️ これはあなたの現在のセッションです。取り消すと直ちにサインアウトされ、再度サインインが必要になります。続行しますか?",
"revoke_confirm": "このセッションを取り消しますか? そのブラウザからの次のリクエストは 401 になります。"
},
"smtp_fail": "送信に失敗しました。",
"smtp_send": "送信",
"smtp_test": "テストメールを送信",
+22
View File
@@ -970,6 +970,28 @@
"quotas": "할당량",
"reset_pw_for": "새 비밀번호:",
"role": "역할",
"sessions": {
"filter_user": "사용자 (UUID)",
"include_revoked": "취소됨 / 만료됨 포함",
"refresh": "새로 고침",
"col_user": "사용자",
"col_created": "생성일",
"col_expires": "만료일",
"col_ip": "IP",
"col_user_agent": "사용자 에이전트",
"col_bound": "바인딩",
"col_status": "상태",
"current_tooltip": "지금 사용 중인 세션입니다 — 이 세션을 취소하면 로그아웃됩니다.",
"bound_tooltip": "DPoP 바인딩됨 (jkt {{prefix}}…)",
"unbound": "미바인딩",
"revoked": "취소됨",
"expired": "만료됨",
"active": "활성",
"revoke": "취소",
"empty": "현재 필터와 일치하는 세션이 없습니다.",
"revoke_self_confirm": "⚠️ 현재 사용 중인 세션입니다. 취소하면 즉시 로그아웃되고 다시 로그인해야 합니다. 계속하시겠습니까?",
"revoke_confirm": "이 세션을 취소하시겠습니까? 해당 브라우저의 다음 요청은 401을 받게 됩니다."
},
"smtp_fail": "전송 실패.",
"smtp_send": "보내기",
"smtp_test": "테스트 이메일 보내기",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "Quota",
"reset_pw_for": "Nieuw wachtwoord voor",
"role": "Rol",
"sessions": {
"filter_user": "Gebruiker (UUID)",
"include_revoked": "Ingetrokken / verlopen tonen",
"refresh": "Vernieuwen",
"col_user": "Gebruiker",
"col_created": "Aangemaakt",
"col_expires": "Verloopt",
"col_ip": "IP",
"col_user_agent": "User agent",
"col_bound": "Gebonden",
"col_status": "Status",
"current_tooltip": "Dit is de sessie die u nu gebruikt — intrekken meldt u af.",
"bound_tooltip": "Gebonden met DPoP (jkt {{prefix}}…)",
"unbound": "niet gebonden",
"revoked": "ingetrokken",
"expired": "verlopen",
"active": "actief",
"revoke": "Intrekken",
"empty": "Geen sessies komen overeen met het huidige filter.",
"revoke_self_confirm": "⚠️ Dit is UW huidige sessie. Intrekken meldt u direct af en u moet opnieuw inloggen. Doorgaan?",
"revoke_confirm": "Deze sessie intrekken? Het volgende verzoek van die browser krijgt 401."
},
"smtp_fail": "Verzenden mislukt.",
"smtp_send": "Verzenden",
"smtp_test": "Test-e-mail verzenden",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "Przydziały",
"reset_pw_for": "Nowe hasło dla",
"role": "Rola",
"sessions": {
"filter_user": "Użytkownik (UUID)",
"include_revoked": "Uwzględnij unieważnione / wygasłe",
"refresh": "Odśwież",
"col_user": "Użytkownik",
"col_created": "Utworzono",
"col_expires": "Wygasa",
"col_ip": "IP",
"col_user_agent": "User agent",
"col_bound": "Powiązana",
"col_status": "Stan",
"current_tooltip": "To sesja, której obecnie używasz — unieważnienie jej wyloguje Cię.",
"bound_tooltip": "Powiązana z DPoP (jkt {{prefix}}…)",
"unbound": "niepowiązana",
"revoked": "unieważniona",
"expired": "wygasła",
"active": "aktywna",
"revoke": "Unieważnij",
"empty": "Żadne sesje nie pasują do bieżącego filtra.",
"revoke_self_confirm": "⚠️ To TWOJA bieżąca sesja. Unieważnienie jej wyloguje Cię natychmiast i musisz zalogować się ponownie. Kontynuować?",
"revoke_confirm": "Unieważnić tę sesję? Następne żądanie z tej przeglądarki otrzyma 401."
},
"smtp_fail": "Wysłanie nie powiodło się.",
"smtp_send": "Wyślij",
"smtp_test": "Wyślij e-mail testowy",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "Cotas",
"reset_pw_for": "Nova senha para",
"role": "Função",
"sessions": {
"filter_user": "Utilizador (UUID)",
"include_revoked": "Incluir revogadas / expiradas",
"refresh": "Atualizar",
"col_user": "Utilizador",
"col_created": "Criada",
"col_expires": "Expira",
"col_ip": "IP",
"col_user_agent": "Agente de utilizador",
"col_bound": "Vinculada",
"col_status": "Estado",
"current_tooltip": "Esta é a sessão que está a utilizar agora — revogá-la irá terminar a sua sessão.",
"bound_tooltip": "Vinculada por DPoP (jkt {{prefix}}…)",
"unbound": "não vinculada",
"revoked": "revogada",
"expired": "expirada",
"active": "ativa",
"revoke": "Revogar",
"empty": "Nenhuma sessão corresponde ao filtro atual.",
"revoke_self_confirm": "⚠️ Esta é a SUA sessão atual. Revogá-la irá terminar a sessão imediatamente e terá de iniciar sessão novamente. Continuar?",
"revoke_confirm": "Revogar esta sessão? O próximo pedido desse browser receberá 401."
},
"smtp_fail": "Falha no envio.",
"smtp_send": "Enviar",
"smtp_test": "Enviar e-mail de teste",
+22
View File
@@ -843,6 +843,28 @@
"quotas": "Квоты",
"reset_pw_for": "Новый пароль для",
"role": "Роль",
"sessions": {
"filter_user": "Пользователь (UUID)",
"include_revoked": "Включая отозванные / истёкшие",
"refresh": "Обновить",
"col_user": "Пользователь",
"col_created": "Создан",
"col_expires": "Истекает",
"col_ip": "IP",
"col_user_agent": "Агент пользователя",
"col_bound": "Привязан",
"col_status": "Статус",
"current_tooltip": "Это сеанс, который вы сейчас используете — при отзыве вы будете разлогинены.",
"bound_tooltip": "Привязан к DPoP (jkt {{prefix}}…)",
"unbound": "не привязан",
"revoked": "отозван",
"expired": "истёк",
"active": "активен",
"revoke": "Отозвать",
"empty": "Нет сеансов, соответствующих текущему фильтру.",
"revoke_self_confirm": "⚠️ Это ВАШ текущий сеанс. При отзыве вы будете немедленно разлогинены и придётся войти снова. Продолжить?",
"revoke_confirm": "Отозвать этот сеанс? Следующий запрос из этого браузера получит 401."
},
"smtp_fail": "Сбой отправки.",
"smtp_send": "Отправить",
"smtp_test": "Отправить тестовое письмо",
+22
View File
@@ -826,6 +826,28 @@
"quotas": "配額",
"reset_pw_for": "新密碼用於",
"role": "角色",
"sessions": {
"filter_user": "使用者 (UUID)",
"include_revoked": "包含已撤銷 / 已過期",
"refresh": "重新整理",
"col_user": "使用者",
"col_created": "建立於",
"col_expires": "過期於",
"col_ip": "IP",
"col_user_agent": "使用者代理",
"col_bound": "已繫結",
"col_status": "狀態",
"current_tooltip": "這是您正在使用的工作階段 — 撤銷會將您登出。",
"bound_tooltip": "已繫結 DPoP (jkt {{prefix}}…)",
"unbound": "未繫結",
"revoked": "已撤銷",
"expired": "已過期",
"active": "使用中",
"revoke": "撤銷",
"empty": "沒有工作階段符合目前的篩選條件。",
"revoke_self_confirm": "⚠️ 這是您目前的工作階段。撤銷後將立即登出,您必須重新登入。要繼續嗎?",
"revoke_confirm": "撤銷此工作階段?該瀏覽器的下一次請求將回傳 401。"
},
"smtp_fail": "傳送失敗。",
"smtp_send": "傳送",
"smtp_test": "傳送測試郵件",
+22
View File
@@ -826,6 +826,28 @@
"quotas": "配额",
"reset_pw_for": "新密码用于",
"role": "角色",
"sessions": {
"filter_user": "用户 (UUID)",
"include_revoked": "包含已撤销 / 已过期",
"refresh": "刷新",
"col_user": "用户",
"col_created": "创建于",
"col_expires": "过期于",
"col_ip": "IP",
"col_user_agent": "用户代理",
"col_bound": "已绑定",
"col_status": "状态",
"current_tooltip": "这是您正在使用的会话 — 撤销将使您退出登录。",
"bound_tooltip": "已绑定 DPoP (jkt {{prefix}}…)",
"unbound": "未绑定",
"revoked": "已撤销",
"expired": "已过期",
"active": "活动",
"revoke": "撤销",
"empty": "没有会话与当前筛选条件匹配。",
"revoke_self_confirm": "⚠️ 这是您当前的会话。撤销后您将立即被注销并需要重新登录。是否继续?",
"revoke_confirm": "撤销此会话吗?该浏览器的下一次请求将返回 401。"
},
"smtp_fail": "发送失败。",
"smtp_send": "发送",
"smtp_test": "发送测试邮件",