feat: Dynamisches Sprachpaket-System für die Bedienoberfläche
Teil 1 des "mehrsprachig variabel"-Umbaus (Speiseplan-Inhalte folgen
in einer späteren Version). Sprachen sind jetzt zur Laufzeit über eine
neue Admin-Seite "Sprachen" verwaltbar statt fest im Code zu stehen:
- Neue Tabellen languages/ui_translations (Migration 0004), bestehende
Englisch-/Polnisch-Texte per generiertem Seed automatisch übernommen
(Migration 0005) - keine manuelle Nacharbeit, nichts geht verloren.
- lib/i18n/flatten.ts: verschachtelte Dict-Objekte (inkl. Arrays wie
weekdays.long) <-> flache Schlüssel-Wert-Paare, Basis für Vorlage-
Export/-Import.
- lib/i18n/template.ts: Vollständigkeits-/Veraltet-Berechnung (Hash
über die DE-Schlüsselliste) und Import-Validierung (Platzhalter wie
{message} müssen erhalten bleiben, unbekannte Schlüssel werden
ignoriert statt Fehler zu werfen).
- getDictionary()/getLocale() (lib/i18n/index.ts) jetzt asynchron und
DB-gestützt für Nicht-Basis-Sprachen, mit Fallback auf Deutsch für
fehlende Schlüssel. Locale-Typ bewusst von festem TypeScript-Tupel
auf string generalisiert (Kompromiss: Compiler prüft Vollständigkeit
nicht mehr automatisch, das übernimmt jetzt die Veraltet-Erkennung
zur Laufzeit).
- LanguageSwitcher/LocaleProvider lesen aktive Sprachen jetzt aus dem
Context statt aus einer festen Konstante; blendet sich bei nur einer
aktiven Sprache automatisch aus.
- Neue Admin-Routen app/api/admin/languages/* (Liste inkl.
Vollständigkeit, Anlegen, Aktivieren/Deaktivieren mit
"mindestens eine muss aktiv bleiben"-Schutz, Löschen außer
Basis-Sprache, Vorlage-Download, Datei-Import) + LanguageManager.tsx.
Vollständig gegen echten DB-Zustand getestet: Vorlage-Export/-Import
inkl. Platzhalter-Validierung, neue Sprache anlegen, auf eine Sprache
reduzieren (Umschalter verschwindet, "letzte Sprache"-Schutz greift),
Veraltet-Erkennung nach simuliertem neuen Schlüssel, Cascade-Delete.
Version 1.10.0.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
-- Dynamisches Sprachpaket-System für die Bedienoberfläche: Sprachen
|
||||
-- sind ab jetzt zur Laufzeit im Admin-Bereich verwaltbar (aktivieren/
|
||||
-- deaktivieren, neue Sprache per Datei-Import hinzufügen) statt fest
|
||||
-- im Code zu stehen. Deutsch bleibt als "de"-Objekt in
|
||||
-- lib/i18n/dictionaries.ts die immer vollständige Basis-Sprache – sie
|
||||
-- braucht keine Zeilen in ui_translations, nur einen Eintrag in
|
||||
-- languages als Referenz für den Sprachumschalter.
|
||||
create table languages (
|
||||
code text primary key,
|
||||
label text not null,
|
||||
is_base boolean not null default false,
|
||||
active boolean not null default true,
|
||||
-- Hash der DE-Vorlage (siehe lib/i18n/flatten.ts + lib/db/languages.ts)
|
||||
-- zum Zeitpunkt des letzten Imports – weicht der aktuelle Hash davon
|
||||
-- ab, sind seit dem Import neue Begriffe hinzugekommen ("veraltet").
|
||||
-- Bei der Basis-Sprache immer null (nie veraltet, da Code = Vorlage).
|
||||
template_version text,
|
||||
updated_at timestamptz not null default now()
|
||||
);
|
||||
|
||||
-- Eine Zeile je Sprache + Übersetzungsschlüssel (z. B.
|
||||
-- "login.errorGeneric"), fehlende Schlüssel fallen zur Laufzeit
|
||||
-- automatisch auf die deutsche Vorlage zurück statt leer zu bleiben.
|
||||
create table ui_translations (
|
||||
language_code text not null references languages(code) on delete cascade,
|
||||
key text not null,
|
||||
value text not null,
|
||||
primary key (language_code, key)
|
||||
);
|
||||
|
||||
insert into languages (code, label, is_base, active, template_version) values
|
||||
('de', 'Deutsch', true, true, null),
|
||||
('en', 'English', false, true, '2da2662b794f019f6f7dba99ef93e2035eb38d1a78bd73bdccbb6b3cab447d5d'),
|
||||
('pl', 'Polski', false, true, '2da2662b794f019f6f7dba99ef93e2035eb38d1a78bd73bdccbb6b3cab447d5d');
|
||||
Reference in New Issue
Block a user