Workstream 1: Projekt-Fundament & Design-System (Phase 0)
Greenfield-Next.js-15-App-Router-Gerüst (TS strict) mit: - Route-Groups (auth)/(app) inkl. loading/error/not-found je Group; Guard-Slot-Kommentar im (app)/layout.tsx (vom Auth-WS zu füllen). - "Amtlich"/Netzknoten-Designsystem: Tailwind-Tokens (Navy #1B3A5B, Signalrot #E2231A, Anthrazit, Nebelgrau, bereit/Wartung), tabular-nums, Serif-Display/Inter-Sans via CSS-Variablen, Inline-SVG-Logo. - Radix-Basiskomponenten (button/input/label/badge/tabs/dialog/select/ switch/slider); StatusBadge entspricht asset_status. - Kanonisches src/lib/env.ts (Zod, Fail-Fast) mit ALLEN DB-/Auth-/Geo-Slots inkl. AUTH_URL; isHttps-Ableitung. Zentrale i18n-Tabelle de.ts + t(). - Drizzle-Setup: client.ts (Pool-Singleton), leeres schema/index.ts-Barrel (KEIN Migrations-Eigentümer), drizzle.config.ts, .env.example. - next.config.ts: output:standalone, experimental.authInterrupts, Security-Header. Vitest + Fail-Fast-Env-Test (TDD, 5/5 grün). Bewusst KEINE Auth-Logik und KEINE fachlichen Tabellen. Verifikation: typecheck/lint/test grün; npm run build erzeugt .next/standalone/server.js; curl /anmelden -> lang="de" + FlorianNetz. next/font/google durch CSS-Variablen ersetzt (air-gapped-Build). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
55
src/lib/i18n/de.ts
Normal file
55
src/lib/i18n/de.ts
Normal file
@@ -0,0 +1,55 @@
|
||||
export const de = {
|
||||
app: { name: "FlorianNetz" },
|
||||
nav: {
|
||||
fahrzeuge: "Fahrzeuge",
|
||||
geraete: "Geräte",
|
||||
wehren: "Wehren",
|
||||
verwaltung: "Verwaltung",
|
||||
admin: "Administration",
|
||||
},
|
||||
auth: {
|
||||
anmelden: "Anmelden",
|
||||
abmelden: "Abmelden",
|
||||
erforderlich: "Anmeldung erforderlich.",
|
||||
},
|
||||
status: {
|
||||
einsatzbereit: "einsatzbereit",
|
||||
wartung: "Wartung",
|
||||
ausser_dienst: "außer Dienst",
|
||||
},
|
||||
search: {
|
||||
meinStandort: "Meinen Standort verwenden",
|
||||
suchen: "Suchen",
|
||||
keineTreffer: "Keine Treffer.",
|
||||
luftlinie: "Luftlinie (geschätzt)",
|
||||
},
|
||||
detail: {
|
||||
eckdaten: "Eckdaten",
|
||||
beladung: "Beladung",
|
||||
keineEckdaten: "Keine Eckdaten erfasst.",
|
||||
imGeraetehaus: "im Gerätehaus",
|
||||
},
|
||||
fehler: {
|
||||
allgemein: "Es ist ein Fehler aufgetreten.",
|
||||
keineBerechtigung: "Keine Berechtigung.",
|
||||
nichtGefunden: "Seite nicht gefunden.",
|
||||
},
|
||||
aktion: {
|
||||
erneutVersuchen: "Erneut versuchen",
|
||||
laden: "Wird geladen …",
|
||||
zurueckZurStartseite: "Zur Startseite",
|
||||
},
|
||||
} as const;
|
||||
|
||||
type Leaf = string;
|
||||
type Paths<T> = T extends Leaf
|
||||
? ""
|
||||
: {
|
||||
[K in keyof T & string]: T[K] extends Leaf ? K : `${K}.${Paths<T[K]>}`;
|
||||
}[keyof T & string];
|
||||
|
||||
export function t(path: Paths<typeof de>): string {
|
||||
return path
|
||||
.split(".")
|
||||
.reduce<unknown>((o, k) => (o as Record<string, unknown>)[k], de) as string;
|
||||
}
|
||||
Reference in New Issue
Block a user