Files
AfiS-Aktensystem/web/lib/i18n/shell.ts
T
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

209 lines
6.7 KiB
TypeScript

/**
* Rahmen der Anwendung: Name, Navigation, Anmeldung, Übersicht, Zustand.
*
* Nach Bereichen getrennt, weil eine **Client-Komponente die ganze Datei ins
* Bündel zieht**, in der ihr Text steht. Lägen alle Texte in einer, trüge jede
* Ansicht die der ganzen Anwendung mit sich herum - das Budget aus
* docs/09-performance-und-ux.md wäre nach wenigen Phasen aufgebraucht.
*
* Serverkomponenten nehmen weiter `de` aus `lib/i18n/de.ts`: was dorthin
* gezogen wird, verlässt den Server nicht.
*/
export const appText = {
name: 'AfiS-Aktensystem',
shortName: 'AfiS',
description: 'Fallakten, Personalakten und Ermittlungen der Abteilung für innere Sicherheit',
} as const
export const navText = {
dashboard: 'Übersicht',
cases: 'Fallakten',
personnel: 'Personalakten',
departments: 'Abteilungen',
search: 'Suche',
admin: 'Admin',
skipToContent: 'Zum Inhalt springen',
} as const
export const authText = {
signIn: 'Mit Discord anmelden',
signOut: 'Abmelden',
signedInAs: 'Angemeldet als',
intro:
'Die Anmeldung läuft über Discord. Zugriff haben Mitglieder der Abteilung für innere Sicherheit.',
reasons: {
'keine-mitgliedschaft': {
title: 'Du bist nicht auf dem AfiS-Discord',
body: 'Die Anmeldung setzt eine Mitgliedschaft auf dem Discord-Server voraus. Wende dich an die Abteilungsleitung.',
},
'keine-afis-rolle': {
title: 'Keine Berechtigung für das Aktensystem',
body: 'Du bist auf dem Server, trägst aber keine Rolle der Abteilung. Wende dich an die Abteilungsleitung.',
},
'discord-nicht-erreichbar': {
title: 'Discord antwortet nicht',
body: 'Die Mitgliedschaft war nicht prüfbar. In einigen Minuten erneut versuchen.',
},
} as Record<string, { title: string; body: string }>,
sessionEnded: {
title: 'Sitzung beendet',
body: 'Deine Rollen haben sich geändert. Melde dich neu an.',
},
error: {
title: 'Anmeldung nicht möglich',
body: 'Der Anmeldevorgang wurde abgebrochen. Erneut versuchen.',
},
backToSignIn: 'Zurück zur Anmeldung',
} as const
export const dashboardText = {
heading: 'Übersicht',
mine: 'Meine Fälle',
mineEmpty: 'Du bist an keiner offenen Akte beteiligt.',
due: 'Fristen',
dueEmpty: 'Nichts steht an.',
dueAt: (datum: string) => `fällig ${datum}`,
overdue: 'überfällig',
unread: 'Ungelesen',
unreadEmpty: 'Nichts Neues.',
unreadCount: (n: number) => (n === 1 ? '1 Nachricht' : `${n} Nachrichten`),
watched: 'Beobachtet',
watchedEmpty: 'Keine Akte beobachtet.',
recent: 'Zuletzt geändert',
recentEmpty: 'Noch keine Akte.',
opened: 'Zuletzt geöffnet',
openedClear: 'Liste leeren',
access: 'Dein Zugang',
} as const
export const watchText = {
watch: 'Beobachten',
unwatch: 'Nicht mehr beobachten',
hint: 'Beobachtete Akten stehen auf deiner Übersicht und melden sich, auch ohne Beteiligung.',
} as const
export const overviewText = {
heading: 'Dein Zugang',
intro: 'Was das System über dich weiss und was daraus folgt.',
person: 'Person',
discordId: 'Discord-Kennung',
roles: 'Rollen auf dem Discord',
clearance: 'Errechnete Freigabestufe',
permissions: 'Rechte',
noPermissions: 'Keine Rechte. Die Abteilungsleitung vergibt sie in der Rollenverwaltung.',
noRoles: 'Keine Rollen.',
bootstrapAdmin: 'Notfallzugang aus der Konfiguration, unabhängig vom Rollen-Mapping',
unmapped: 'nicht zugeordnet',
} as const
export const healthText = {
heading: 'Systemzustand',
service: 'Dienst',
state: 'Zustand',
checkedAt: (when: string) => `Zustand der Dienste, abgefragt ${when}`,
ok: 'Betriebsbereit',
degraded: 'Eingeschränkt',
down: 'Gestört',
components: {
database: 'Datenbank',
discordGateway: 'Discord-Gateway',
clamav: 'Virenprüfung',
} as Record<string, string>,
} as const
export const notifyText = {
heading: 'Benachrichtigungen',
intro:
'Discord erfährt nie den Inhalt einer Akte. Bei Akten ab Stufe 3 auch nicht den Titel - nur, dass sich etwas getan hat, und einen Link.',
mode: 'Was soll dich erreichen?',
save: 'Übernehmen',
saved: 'Übernommen',
modes: {
ALL: 'Alles, was ich sehen darf',
OWN_CASES: 'Nur meine Fälle',
MENTIONS: 'Nur Erwähnungen',
OFF: 'Nichts',
} as Record<string, string>,
} as const
export const searchText = {
heading: 'Suche',
placeholder: 'Aktenzeichen, Titel, Inhalt',
kinds: {
all: 'Alle',
case: 'Fallakten',
document: 'Dokumente',
personnel: 'Personalakten',
} as Record<string, string>,
showAllOfKind: (label: string) => `Alle ${label} zeigen`,
asParticipant: (name: string, rolle: string) => `${name} als ${rolle}`,
filters: 'Filter',
reset: 'Filter zurücksetzen',
empty: 'Kein Treffer. Anderen Begriff oder weniger Filter versuchen.',
emptyNoQuery: 'Begriff eingeben oder einen Filter wählen.',
countLabel: (n: number) => (n === 1 ? '1 Treffer' : `${n} Treffer`),
elsewhere: (label: string, n: number) =>
n === 1 ? `1 Treffer unter ${label}` : `${n} Treffer unter ${label}`,
more: 'Weitere laden',
truncated:
'Sehr viele Treffer. Angezeigt werden die besten; mit einem genaueren Begriff wird die Liste vollständig.',
views: 'Ansichten',
saveView: 'Ansicht speichern',
saveViewName: 'Name der Ansicht',
deleteView: 'Ansicht löschen',
builtin: {
mine: 'Meine Fälle',
dueThisWeek: 'Wiedervorlage diese Woche',
idle: 'Unbearbeitet seit 14 Tagen',
open: 'Offene Fälle',
sinceLastVisit: 'Seit deinem letzten Besuch geändert',
} as Record<string, string>,
} as const
export const paletteText = {
open: 'Springen',
placeholder: 'Aktenzeichen, Akte oder Seite',
hint: 'Strg+K',
empty: 'Nichts gefunden.',
close: 'Schliessen',
sections: {
cases: 'Fallakten',
personnel: 'Personalakten',
pages: 'Seiten',
recent: 'Zuletzt geöffnet',
} as Record<string, string>,
/**
* Die Sprungziele der Palette. Sie stehen hier und nicht in der Komponente,
* weil sie Oberflächentext sind - die Adressen daneben sind es nicht.
*/
pages: [
{ href: '/uebersicht', label: 'Übersicht' },
{ href: '/faelle', label: 'Fallakten' },
{ href: '/faelle/neu', label: 'Neue Fallakte' },
{ href: '/personalakten', label: 'Personalakten' },
{ href: '/abteilungen', label: 'Abteilungen' },
{ href: '/suche', label: 'Suche' },
{ href: '/admin', label: 'Admin' },
{ href: '/admin/protokoll', label: 'Protokoll' },
{ href: '/einstellungen', label: 'Benachrichtigungen' },
],
} as const
export const profileText = {
open: 'Konto und Einstellungen',
signedInAs: 'Angemeldet als',
} as const
export const searchBarText = {
label: 'Suchen',
placeholder: 'Aktenzeichen, Titel, Name',
} as const
export const themeText = {
label: 'Thema',
system: 'Wie das System',
dark: 'Dunkel',
light: 'Hell',
} as const