Add i18n support: per-locale catalogs, URL-driven locale, translated core and examples
CI / full-gate (push) Successful in 2m37s

This commit is contained in:
2026-08-03 22:37:27 +02:00
parent c30cd95ebd
commit 245d1ad5b5
93 changed files with 2480 additions and 464 deletions
+11 -4
View File
@@ -6,6 +6,8 @@
// the local part; anonymous ⇒ "Guest".
import type { User } from "../http/context.ts";
import { ENGLISH } from "../i18n/english.ts";
import type { Translate } from "../i18n/translate.ts";
import { type MenuConfig } from "./menu-config.ts";
export interface ShellUser {
@@ -24,8 +26,11 @@ export interface ShellModel {
user: ShellUser;
}
export function shellUser(user: User | null | undefined): ShellUser {
if (!user) return { email: "", initials: "G", name: "Guest" };
export function shellUser(user: User | null | undefined, t: Translate = ENGLISH): ShellUser {
if (!user) {
const guest = t("shell.guest");
return { email: "", initials: guest.slice(0, 1).toUpperCase(), name: guest };
}
const local = user.email.split("@")[0] || user.email;
return { email: user.email, initials: (local.slice(0, 2) || "U").toUpperCase(), name: local };
}
@@ -35,17 +40,19 @@ export function buildShellContext(opts: {
csrfToken?: string;
menu: MenuConfig;
signInHref?: string;
t?: Translate;
title: string;
user?: User | null;
}): ShellModel {
const b = opts.menu.branding;
const t = opts.t ?? ENGLISH;
return {
brand: { ...(b.logo != null ? { logo: b.logo } : {}), name: b.name, ...(b.sub != null ? { sub: b.sub } : {}) },
brand: { ...(b.logo != null ? { logo: b.logo } : {}), name: t(b.name), ...(b.sub != null ? { sub: t(b.sub) } : {}) },
...(opts.breadcrumbs ? { breadcrumbs: opts.breadcrumbs } : {}),
csrfToken: opts.csrfToken ?? "",
...(opts.signInHref != null ? { signInHref: opts.signInHref } : {}),
...(b.theme != null ? { theme: b.theme } : {}),
title: opts.title,
user: shellUser(opts.user),
user: shellUser(opts.user, t),
};
}