From 9ee767f5763b1f201800986aebd7156de0286441 Mon Sep 17 00:00:00 2001
From: Linus Rath <139418639+rathlinus@users.noreply.github.com>
Date: Wed, 28 Oct 2026 03:52:40 +0100
Subject: [PATCH] fix: show a translated 404 to a signed-in user who mistypes a
URL instead of the login page
---
app/(main)/[locale]/[...rest]/page.tsx | 8 +++
app/(main)/[locale]/not-found.tsx | 10 +++
app/(main)/not-found.tsx | 47 +++---------
.../error/__tests__/not-found-view.test.tsx | 54 ++++++++++++++
components/error/not-found-view.tsx | 71 +++++++++++++++++++
locales/ar/common.json | 4 ++
locales/ca/common.json | 4 ++
locales/cs/common.json | 4 ++
locales/da/common.json | 4 ++
locales/de/common.json | 4 ++
locales/en/common.json | 4 ++
locales/es/common.json | 4 ++
locales/et/common.json | 4 ++
locales/fa/common.json | 4 ++
locales/fr/common.json | 4 ++
locales/he/common.json | 4 ++
locales/hu/common.json | 4 ++
locales/it/common.json | 4 ++
locales/ja/common.json | 4 ++
locales/ko/common.json | 4 ++
locales/lv/common.json | 4 ++
locales/mn/common.json | 4 ++
locales/nb/common.json | 4 ++
locales/nl/common.json | 4 ++
locales/pl/common.json | 4 ++
locales/pt/common.json | 4 ++
locales/ro/common.json | 4 ++
locales/ru/common.json | 4 ++
locales/sk/common.json | 4 ++
locales/th/common.json | 4 ++
locales/tr/common.json | 4 ++
locales/uk/common.json | 4 ++
locales/zh-TW/common.json | 4 ++
locales/zh/common.json | 4 ++
scripts/lite/lib.mjs | 1 +
35 files changed, 269 insertions(+), 38 deletions(-)
create mode 100644 app/(main)/[locale]/[...rest]/page.tsx
create mode 100644 app/(main)/[locale]/not-found.tsx
create mode 100644 components/error/__tests__/not-found-view.test.tsx
create mode 100644 components/error/not-found-view.tsx
diff --git a/app/(main)/[locale]/[...rest]/page.tsx b/app/(main)/[locale]/[...rest]/page.tsx
new file mode 100644
index 000000000..75c6193d9
--- /dev/null
+++ b/app/(main)/[locale]/[...rest]/page.tsx
@@ -0,0 +1,8 @@
+import { notFound } from 'next/navigation';
+
+// Unknown paths below a locale (/de/typo) end here, so the 404 renders
+// inside the locale layout and is translated ([locale]/not-found.tsx).
+// Removed from the static Lite export, like (main)/[...rest].
+export default function LocaleCatchAll() {
+ notFound();
+}
diff --git a/app/(main)/[locale]/not-found.tsx b/app/(main)/[locale]/not-found.tsx
new file mode 100644
index 000000000..e1bcd8fe4
--- /dev/null
+++ b/app/(main)/[locale]/not-found.tsx
@@ -0,0 +1,10 @@
+"use client";
+
+import { useTranslations } from "next-intl";
+import { NotFoundView } from "@/components/error/not-found-view";
+
+export default function LocaleNotFound() {
+ const t = useTranslations("not_found");
+ const tErrors = useTranslations("errors");
+ return ;
+}
diff --git a/app/(main)/not-found.tsx b/app/(main)/not-found.tsx
index 8e9c79550..38b171963 100644
--- a/app/(main)/not-found.tsx
+++ b/app/(main)/not-found.tsx
@@ -1,14 +1,14 @@
"use client";
import { useEffect } from "react";
-import { useAuthStore } from "@/stores/auth-store";
import { getPathPrefix } from "@/lib/browser-navigation";
+import { NotFoundView } from "@/components/error/not-found-view";
import { IS_LITE } from "@/lib/lite";
import { liteSurfaceRootFor, stashPendingLitePath } from "@/lib/lite-link-segments";
+// Outside the locale tree there are no translations: paths below a locale
+// get the translated page in [locale]/not-found.tsx.
export default function NotFound() {
- const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
-
useEffect(() => {
// Static Lite build on a host without rewrite rules (GitHub Pages): a deep
// link such as /en/mail/thread/abc lands here as 404.html. Park the link
@@ -21,42 +21,13 @@ export default function NotFound() {
return;
}
}
- if (!isAuthenticated) {
- const prefix = getPathPrefix();
- // Don't redirect admin routes to the webmail login page. Admin paths
- // are mounted relative to the deployment prefix, so account for it.
- const adminBase = `${prefix}/admin`;
- const isAdminRoute = window.location.pathname === adminBase || window.location.pathname.startsWith(`${adminBase}/`);
- if (!isAdminRoute) {
- window.location.href = `${prefix}/login`;
- }
- }
- }, [isAuthenticated]);
-
- if (!isAuthenticated) {
- let isAdmin = false;
- if (typeof window !== 'undefined') {
- const prefix = getPathPrefix();
- const adminBase = `${prefix}/admin`;
- isAdmin = window.location.pathname === adminBase || window.location.pathname.startsWith(`${adminBase}/`);
- }
- if (!isAdmin) return null;
- }
-
- const prefix = typeof window !== 'undefined' ? getPathPrefix() : '';
+ }, []);
return (
-
+
);
}
diff --git a/components/error/__tests__/not-found-view.test.tsx b/components/error/__tests__/not-found-view.test.tsx
new file mode 100644
index 000000000..f0869b3ac
--- /dev/null
+++ b/components/error/__tests__/not-found-view.test.tsx
@@ -0,0 +1,54 @@
+import { act, render, screen } from '@testing-library/react';
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+
+// A mistyped URL with a still valid session: the 404 waits for the session
+// to be restored instead of sending the user to the login page.
+
+const { default: LocaleNotFound } = await import('@/app/(main)/[locale]/not-found');
+const { useAuthStore } = await import('@/stores/auth-store');
+
+const realLocation = window.location;
+let href = '';
+
+beforeEach(() => {
+ href = 'http://localhost/de/gibtsnicht';
+ Object.defineProperty(window, 'location', {
+ configurable: true,
+ value: {
+ ...realLocation,
+ pathname: '/de/gibtsnicht',
+ get href() { return href; },
+ set href(v: string) { href = v; },
+ },
+ });
+});
+afterEach(() => {
+ Object.defineProperty(window, 'location', { configurable: true, value: realLocation });
+});
+
+describe('404 page', () => {
+ it('restores the session before deciding, and shows the translated page to a signed-in user', async () => {
+ let finish: () => void = () => {};
+ const checkAuth = vi.fn(() => new Promise((resolve) => {
+ finish = () => { useAuthStore.setState({ isAuthenticated: true } as never); resolve(); };
+ }));
+ useAuthStore.setState({ isAuthenticated: false, checkAuth } as never);
+
+ render();
+ expect(checkAuth).toHaveBeenCalled();
+ expect(href).not.toContain('/login');
+
+ await act(async () => { finish(); });
+ expect(href).not.toContain('/login');
+ expect(screen.getByRole('heading', { name: 'title' })).toBeInTheDocument();
+ expect(screen.getByRole('link', { name: 'go_home' })).toBeInTheDocument();
+ });
+
+ it('sends a visitor without a session to the login page once that is known', async () => {
+ const checkAuth = vi.fn(() => Promise.resolve());
+ useAuthStore.setState({ isAuthenticated: false, checkAuth } as never);
+ render();
+ await act(async () => {});
+ expect(href).toBe('/login');
+ });
+});
diff --git a/components/error/not-found-view.tsx b/components/error/not-found-view.tsx
new file mode 100644
index 000000000..aa42c06b4
--- /dev/null
+++ b/components/error/not-found-view.tsx
@@ -0,0 +1,71 @@
+"use client";
+
+import { useEffect, useState } from "react";
+import { SearchX } from "@/components/icons";
+import { useAuthStore } from "@/stores/auth-store";
+import { getPathPrefix } from "@/lib/browser-navigation";
+
+/** Whether the current URL is an admin page, which has its own sign-in. */
+function isAdminPath(): boolean {
+ if (typeof window === "undefined") return false;
+ const adminBase = `${getPathPrefix()}/admin`;
+ const path = window.location.pathname;
+ return path === adminBase || path.startsWith(`${adminBase}/`);
+}
+
+/**
+ * Who is looking at a missing page: "checking" until the stored session has
+ * been restored, then signed in or not. Deciding before that sent a signed-in
+ * user with a mistyped URL to the login page.
+ */
+export function useNotFoundAuth(): "checking" | "signed-in" | "signed-out" {
+ const isAuthenticated = useAuthStore((s) => s.isAuthenticated);
+ const [checked, setChecked] = useState(() => useAuthStore.getState().isAuthenticated);
+
+ useEffect(() => {
+ if (useAuthStore.getState().isAuthenticated) {
+ setChecked(true);
+ return;
+ }
+ let cancelled = false;
+ void useAuthStore.getState().checkAuth().finally(() => { if (!cancelled) setChecked(true); });
+ return () => { cancelled = true; };
+ }, []);
+
+ useEffect(() => {
+ if (!checked || isAuthenticated || isAdminPath()) return;
+ window.location.href = `${getPathPrefix()}/login`;
+ }, [checked, isAuthenticated]);
+
+ if (isAuthenticated) return "signed-in";
+ return checked ? "signed-out" : "checking";
+}
+
+export interface NotFoundViewProps {
+ title: string;
+ description: string;
+ homeLabel: string;
+}
+
+/** The 404 page: what happened and the way back. Signed out, it shows only on admin paths. */
+export function NotFoundView({ title, description, homeLabel }: NotFoundViewProps) {
+ const auth = useNotFoundAuth();
+ if (auth !== "signed-in" && !isAdminPath()) return null;
+
+ const prefix = typeof window !== "undefined" ? getPathPrefix() : "";
+ return (
+
+ );
+}
diff --git a/locales/ar/common.json b/locales/ar/common.json
index 85b15c79f..9680a164b 100644
--- a/locales/ar/common.json
+++ b/locales/ar/common.json
@@ -2625,6 +2625,10 @@
"retry": "إعادة المحاولة",
"go_home": "الانتقال إلى البريد الوارد"
},
+ "not_found": {
+ "title": "الصفحة غير موجودة",
+ "description": "هذه الصفحة غير موجودة أو نُقلت. تحقّق من العنوان أو عُد إلى صندوق الوارد."
+ },
"context_menu": {
"reply": "رد",
"reply_all": "الرد على الجميع",
diff --git a/locales/ca/common.json b/locales/ca/common.json
index f0614d43e..76cc628b9 100644
--- a/locales/ca/common.json
+++ b/locales/ca/common.json
@@ -2625,6 +2625,10 @@
"retry": "Reintenta",
"go_home": "Vés a la safata d'entrada"
},
+ "not_found": {
+ "title": "No s'ha trobat la pàgina",
+ "description": "Aquesta pàgina no existeix o s'ha mogut. Comproveu l'adreça o torneu a la safata d'entrada."
+ },
"context_menu": {
"reply": "Respon",
"reply_all": "Respon a tots",
diff --git a/locales/cs/common.json b/locales/cs/common.json
index b921779e1..b2a16fcb7 100644
--- a/locales/cs/common.json
+++ b/locales/cs/common.json
@@ -2625,6 +2625,10 @@
"retry": "Opakovat",
"go_home": "Přejít do doručené pošty"
},
+ "not_found": {
+ "title": "Stránka nenalezena",
+ "description": "Tato stránka neexistuje nebo byla přesunuta. Zkontrolujte adresu nebo se vraťte do doručené pošty."
+ },
"context_menu": {
"reply": "Odpovědět",
"reply_all": "Odpovědět všem",
diff --git a/locales/da/common.json b/locales/da/common.json
index 9e39f9bb6..6ba2d2f33 100644
--- a/locales/da/common.json
+++ b/locales/da/common.json
@@ -2625,6 +2625,10 @@
"retry": "Prøv igen",
"go_home": "Gå til indbakke"
},
+ "not_found": {
+ "title": "Siden blev ikke fundet",
+ "description": "Siden findes ikke eller er flyttet. Tjek adressen, eller gå tilbage til din indbakke."
+ },
"context_menu": {
"reply": "Svar",
"reply_all": "Svar alle",
diff --git a/locales/de/common.json b/locales/de/common.json
index 288cfb3c6..1461e4a8b 100644
--- a/locales/de/common.json
+++ b/locales/de/common.json
@@ -2625,6 +2625,10 @@
"retry": "Wiederholen",
"go_home": "Zum Posteingang"
},
+ "not_found": {
+ "title": "Seite nicht gefunden",
+ "description": "Diese Seite gibt es nicht oder sie wurde verschoben. Prüfen Sie die Adresse oder kehren Sie zu Ihrem Posteingang zurück."
+ },
"context_menu": {
"reply": "Antworten",
"reply_all": "Allen antworten",
diff --git a/locales/en/common.json b/locales/en/common.json
index fedbaeb2b..78719b817 100644
--- a/locales/en/common.json
+++ b/locales/en/common.json
@@ -2625,6 +2625,10 @@
"retry": "Retry",
"go_home": "Go to inbox"
},
+ "not_found": {
+ "title": "Page not found",
+ "description": "This page doesn't exist or has moved. Check the address, or go back to your inbox."
+ },
"context_menu": {
"reply": "Reply",
"reply_all": "Reply All",
diff --git a/locales/es/common.json b/locales/es/common.json
index 572b3a824..c98e82ab6 100644
--- a/locales/es/common.json
+++ b/locales/es/common.json
@@ -2625,6 +2625,10 @@
"retry": "Reintentar",
"go_home": "Ir a bandeja de entrada"
},
+ "not_found": {
+ "title": "No se ha encontrado la página",
+ "description": "Esta página no existe o se ha movido. Comprueba la dirección o vuelve a tu bandeja de entrada."
+ },
"context_menu": {
"reply": "Responder",
"reply_all": "Responder a Todos",
diff --git a/locales/et/common.json b/locales/et/common.json
index dd8aa0c6b..eaca8757c 100644
--- a/locales/et/common.json
+++ b/locales/et/common.json
@@ -2625,6 +2625,10 @@
"retry": "Proovi uuesti",
"go_home": "Mine postkasti"
},
+ "not_found": {
+ "title": "Lehte ei leitud",
+ "description": "Seda lehte pole olemas või see on teisaldatud. Kontrollige aadressi või minge tagasi postkasti."
+ },
"context_menu": {
"reply": "Vasta",
"reply_all": "Vasta kõigile",
diff --git a/locales/fa/common.json b/locales/fa/common.json
index c45aa6ef0..2ee1e9747 100644
--- a/locales/fa/common.json
+++ b/locales/fa/common.json
@@ -2625,6 +2625,10 @@
"retry": "تلاش مجدد",
"go_home": "رفتن به صندوق ورودی"
},
+ "not_found": {
+ "title": "صفحه پیدا نشد",
+ "description": "این صفحه وجود ندارد یا جابهجا شده است. نشانی را بررسی کنید یا به صندوق ورودی برگردید."
+ },
"context_menu": {
"reply": "پاسخ",
"reply_all": "پاسخ به همه",
diff --git a/locales/fr/common.json b/locales/fr/common.json
index 5e35bc960..051a31a6c 100644
--- a/locales/fr/common.json
+++ b/locales/fr/common.json
@@ -2625,6 +2625,10 @@
"retry": "Réessayer",
"go_home": "Aller à la boîte de réception"
},
+ "not_found": {
+ "title": "Page introuvable",
+ "description": "Cette page n'existe pas ou a été déplacée. Vérifiez l'adresse ou revenez à votre boîte de réception."
+ },
"context_menu": {
"reply": "Répondre",
"reply_all": "Répondre à tous",
diff --git a/locales/he/common.json b/locales/he/common.json
index 701d22da7..bfa7059f4 100644
--- a/locales/he/common.json
+++ b/locales/he/common.json
@@ -2591,6 +2591,10 @@
"retry": "נסה שוב",
"go_home": "עבור לתיבת הדואר הנכנס"
},
+ "not_found": {
+ "title": "הדף לא נמצא",
+ "description": "הדף הזה לא קיים או שהועבר. בדקו את הכתובת או חזרו לתיבת הדואר הנכנס."
+ },
"context_menu": {
"reply": "השב",
"reply_all": "השב לכולם",
diff --git a/locales/hu/common.json b/locales/hu/common.json
index 44f2ea9a1..9efe67330 100644
--- a/locales/hu/common.json
+++ b/locales/hu/common.json
@@ -2625,6 +2625,10 @@
"retry": "Újra",
"go_home": "Ugrás a beérkezőhöz"
},
+ "not_found": {
+ "title": "Az oldal nem található",
+ "description": "Ez az oldal nem létezik, vagy áthelyezték. Ellenőrizze a címet, vagy térjen vissza a beérkezett üzenetekhez."
+ },
"context_menu": {
"reply": "Válasz",
"reply_all": "Válasz mindenkinek",
diff --git a/locales/it/common.json b/locales/it/common.json
index 24874ca00..38c756512 100644
--- a/locales/it/common.json
+++ b/locales/it/common.json
@@ -2625,6 +2625,10 @@
"retry": "Riprova",
"go_home": "Vai alla posta in arrivo"
},
+ "not_found": {
+ "title": "Pagina non trovata",
+ "description": "Questa pagina non esiste o è stata spostata. Controlla l'indirizzo o torna alla posta in arrivo."
+ },
"context_menu": {
"reply": "Rispondi",
"reply_all": "Rispondi a tutti",
diff --git a/locales/ja/common.json b/locales/ja/common.json
index 38922e1e6..d4978091c 100644
--- a/locales/ja/common.json
+++ b/locales/ja/common.json
@@ -2625,6 +2625,10 @@
"retry": "リトライ",
"go_home": "受信トレイに移動"
},
+ "not_found": {
+ "title": "ページが見つかりません",
+ "description": "このページは存在しないか、移動されました。アドレスを確認するか、受信トレイに戻ってください。"
+ },
"context_menu": {
"reply": "返信",
"reply_all": "全員に返信",
diff --git a/locales/ko/common.json b/locales/ko/common.json
index 95172af3e..a74721f69 100644
--- a/locales/ko/common.json
+++ b/locales/ko/common.json
@@ -2625,6 +2625,10 @@
"retry": "재시도",
"go_home": "받은편지함으로 이동"
},
+ "not_found": {
+ "title": "페이지를 찾을 수 없습니다",
+ "description": "이 페이지가 없거나 이동되었습니다. 주소를 확인하거나 받은편지함으로 돌아가세요."
+ },
"context_menu": {
"reply": "답장",
"reply_all": "전체 답장",
diff --git a/locales/lv/common.json b/locales/lv/common.json
index 5294d6063..5cb9cbe76 100644
--- a/locales/lv/common.json
+++ b/locales/lv/common.json
@@ -2625,6 +2625,10 @@
"retry": "Mēģināt vēlreiz",
"go_home": "Uz iesūtni"
},
+ "not_found": {
+ "title": "Lapa nav atrasta",
+ "description": "Šī lapa nepastāv vai ir pārvietota. Pārbaudiet adresi vai atgriezieties iesūtnē."
+ },
"context_menu": {
"reply": "Atbildēt",
"reply_all": "Atbildēt visiem",
diff --git a/locales/mn/common.json b/locales/mn/common.json
index 5b13cf362..5b62a975f 100644
--- a/locales/mn/common.json
+++ b/locales/mn/common.json
@@ -2625,6 +2625,10 @@
"retry": "Дахин оролдох",
"go_home": "Ирсэн имэйл рүү очих"
},
+ "not_found": {
+ "title": "Хуудас олдсонгүй",
+ "description": "Энэ хуудас байхгүй эсвэл зөөгдсөн байна. Хаягаа шалгах эсвэл ирсэн захидал руу буцна уу."
+ },
"context_menu": {
"reply": "Хариулах",
"reply_all": "Бүгдэд нь хариулах",
diff --git a/locales/nb/common.json b/locales/nb/common.json
index f563da68b..1d646f905 100644
--- a/locales/nb/common.json
+++ b/locales/nb/common.json
@@ -2625,6 +2625,10 @@
"retry": "Prøv på nytt",
"go_home": "Gå til innboksen"
},
+ "not_found": {
+ "title": "Fant ikke siden",
+ "description": "Denne siden finnes ikke eller er flyttet. Sjekk adressen, eller gå tilbake til innboksen."
+ },
"context_menu": {
"reply": "Svar",
"reply_all": "Svar alle",
diff --git a/locales/nl/common.json b/locales/nl/common.json
index afa37bff1..f4e4dd7f3 100644
--- a/locales/nl/common.json
+++ b/locales/nl/common.json
@@ -2625,6 +2625,10 @@
"retry": "Opnieuw proberen",
"go_home": "Ga naar postvak IN"
},
+ "not_found": {
+ "title": "Pagina niet gevonden",
+ "description": "Deze pagina bestaat niet of is verplaatst. Controleer het adres of ga terug naar je inbox."
+ },
"context_menu": {
"reply": "Beantwoorden",
"reply_all": "Allen beantwoorden",
diff --git a/locales/pl/common.json b/locales/pl/common.json
index 9b2c3f7f4..4a7f4ea29 100644
--- a/locales/pl/common.json
+++ b/locales/pl/common.json
@@ -2625,6 +2625,10 @@
"retry": "Ponów",
"go_home": "Przejdź do skrzynki odbiorczej"
},
+ "not_found": {
+ "title": "Nie znaleziono strony",
+ "description": "Ta strona nie istnieje lub została przeniesiona. Sprawdź adres albo wróć do skrzynki odbiorczej."
+ },
"context_menu": {
"reply": "Odpowiedz",
"reply_all": "Odpowiedz wszystkim",
diff --git a/locales/pt/common.json b/locales/pt/common.json
index d08ff7d30..344c3d826 100644
--- a/locales/pt/common.json
+++ b/locales/pt/common.json
@@ -2625,6 +2625,10 @@
"retry": "Tentar novamente",
"go_home": "Ir para caixa de entrada"
},
+ "not_found": {
+ "title": "Página não encontrada",
+ "description": "Esta página não existe ou foi movida. Verifique o endereço ou volte à caixa de entrada."
+ },
"context_menu": {
"reply": "Responder",
"reply_all": "Responder a Todos",
diff --git a/locales/ro/common.json b/locales/ro/common.json
index e9cb8c328..6daa65529 100644
--- a/locales/ro/common.json
+++ b/locales/ro/common.json
@@ -2625,6 +2625,10 @@
"retry": "Reîncearcă",
"go_home": "Accesați căsuța de intrare"
},
+ "not_found": {
+ "title": "Pagina nu a fost găsită",
+ "description": "Această pagină nu există sau a fost mutată. Verificați adresa sau reveniți la Inbox."
+ },
"context_menu": {
"reply": "Răspunde",
"reply_all": "Răspunde tuturor",
diff --git a/locales/ru/common.json b/locales/ru/common.json
index c25814daa..bba4f47b5 100644
--- a/locales/ru/common.json
+++ b/locales/ru/common.json
@@ -2625,6 +2625,10 @@
"retry": "Повторить",
"go_home": "В папку «Входящие»"
},
+ "not_found": {
+ "title": "Страница не найдена",
+ "description": "Этой страницы нет или она перемещена. Проверьте адрес или вернитесь во «Входящие»."
+ },
"context_menu": {
"reply": "Ответить",
"reply_all": "Ответить всем",
diff --git a/locales/sk/common.json b/locales/sk/common.json
index c5ee5065f..2f686d928 100644
--- a/locales/sk/common.json
+++ b/locales/sk/common.json
@@ -2625,6 +2625,10 @@
"retry": "Opakovať",
"go_home": "Prejsť do doručenej pošty"
},
+ "not_found": {
+ "title": "Stránka sa nenašla",
+ "description": "Táto stránka neexistuje alebo bola presunutá. Skontrolujte adresu alebo sa vráťte do doručenej pošty."
+ },
"context_menu": {
"reply": "Odpovedať",
"reply_all": "Odpovedať všetkým",
diff --git a/locales/th/common.json b/locales/th/common.json
index 34d52b387..896b8b600 100644
--- a/locales/th/common.json
+++ b/locales/th/common.json
@@ -101,6 +101,10 @@
"retry": "ลองใหม่",
"go_home": "ไปยังกล่องข้อความ"
},
+ "not_found": {
+ "title": "ไม่พบหน้านี้",
+ "description": "ไม่มีหน้านี้หรือหน้านี้ถูกย้ายแล้ว ตรวจสอบที่อยู่ หรือกลับไปที่กล่องจดหมายเข้า"
+ },
"login": {
"title": "เข้าสู่ระบบจดหมายอิเล็กทรอนิกส์",
"username_label": "อีเมล",
diff --git a/locales/tr/common.json b/locales/tr/common.json
index 67d832661..284279d5a 100644
--- a/locales/tr/common.json
+++ b/locales/tr/common.json
@@ -2625,6 +2625,10 @@
"retry": "Yeniden dene",
"go_home": "Gelen kutusuna git"
},
+ "not_found": {
+ "title": "Sayfa bulunamadı",
+ "description": "Bu sayfa yok veya taşınmış. Adresi kontrol edin ya da gelen kutunuza dönün."
+ },
"context_menu": {
"reply": "Yanıtla",
"reply_all": "Tümünü Yanıtla",
diff --git a/locales/uk/common.json b/locales/uk/common.json
index 66d650572..a44d9612d 100644
--- a/locales/uk/common.json
+++ b/locales/uk/common.json
@@ -2625,6 +2625,10 @@
"retry": "Повторіть спробу",
"go_home": "Перейти до папки \"Вхідні\"."
},
+ "not_found": {
+ "title": "Сторінку не знайдено",
+ "description": "Цієї сторінки немає або її переміщено. Перевірте адресу або поверніться до вхідних."
+ },
"context_menu": {
"reply": "Відповісти",
"reply_all": "Відповісти всім",
diff --git a/locales/zh-TW/common.json b/locales/zh-TW/common.json
index 53f7a2671..caf616f90 100644
--- a/locales/zh-TW/common.json
+++ b/locales/zh-TW/common.json
@@ -2625,6 +2625,10 @@
"retry": "重試",
"go_home": "前往收件匣"
},
+ "not_found": {
+ "title": "找不到頁面",
+ "description": "此頁面不存在或已移動。請檢查網址,或返回收件匣。"
+ },
"context_menu": {
"reply": "回覆",
"reply_all": "全部回覆",
diff --git a/locales/zh/common.json b/locales/zh/common.json
index 1b6b532ef..303e158b4 100644
--- a/locales/zh/common.json
+++ b/locales/zh/common.json
@@ -2625,6 +2625,10 @@
"retry": "重试",
"go_home": "前往收件箱"
},
+ "not_found": {
+ "title": "找不到页面",
+ "description": "此页面不存在或已移动。请检查地址,或返回收件箱。"
+ },
"context_menu": {
"reply": "回复",
"reply_all": "全部回复",
diff --git a/scripts/lite/lib.mjs b/scripts/lite/lib.mjs
index 6692f6c79..7cee6c0d0 100644
--- a/scripts/lite/lib.mjs
+++ b/scripts/lite/lib.mjs
@@ -39,6 +39,7 @@ export const LITE_REMOVED_PATHS = [
"instrumentation.ts",
"instrumentation.node.ts",
"app/(main)/[...rest]",
+ "app/(main)/[locale]/[...rest]",
"app/(main)/protocol",
"e2e",
"integration",