Neue Migration 0002_labeling_notice.sql: settings.labeling_mode
("detailed"/"notice") + labeling_notice(_en/_pl). Auf der Seite
"Allergene & Zusatzstoffe" (LabelingNoticeEditor) kann zwischen der
detaillierten Auswahl je Gericht und einem editierbaren Hinweistext
umgeschaltet werden. Im Hinweismodus entfällt auf der öffentlichen
Speisekarte (Desktop + Mobile) die Legende und die Kürzel an den
Gerichten, in der Gerichte-Verwaltung wird die Chip-Auswahl beim
Bearbeiten ausgeblendet. Umschalten/Bearbeiten ist für staff und admin
freigegeben, Farben in /api/settings bleiben admin-only.
Version 1.8.0.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
864 lines
34 KiB
TypeScript
864 lines
34 KiB
TypeScript
// Übersetzungswörterbücher für die komplette Oberfläche.
|
||
// "de" ist die Referenzstruktur; en/pl werden dagegen typgeprüft,
|
||
// damit kein Schlüssel in einer Sprache fehlt.
|
||
|
||
const de = {
|
||
common: {
|
||
save: "Speichern",
|
||
cancel: "Abbrechen",
|
||
delete: "Löschen",
|
||
edit: "Bearbeiten",
|
||
add: "Hinzufügen",
|
||
back: "Zurück",
|
||
login: "Anmelden",
|
||
logout: "Abmelden",
|
||
loading: "Lade…",
|
||
you: "(du)",
|
||
name: "Name",
|
||
email: "E-Mail-Adresse",
|
||
password: "Passwort",
|
||
role: "Rolle",
|
||
roleAdmin: "Administrator",
|
||
roleStaff: "Kantinenmitarbeiter",
|
||
},
|
||
weekdays: {
|
||
long: ["Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag"],
|
||
short: ["Mo", "Di", "Mi", "Do", "Fr"],
|
||
},
|
||
dateLocale: "de-DE",
|
||
header: {
|
||
canteen: "Kantine",
|
||
menuGroup: "Speiseplan",
|
||
weekPlan: "Wochenplan",
|
||
sections: "Essenszeiten",
|
||
dishes: "Gerichte",
|
||
labels: "Allergene & Zusatzstoffe",
|
||
adminGroup: "Verwaltung",
|
||
users: "Benutzer",
|
||
design: "Design",
|
||
suggestions: "Vorschläge",
|
||
openSuggestions: "{count} offene Rezeptvorschläge",
|
||
viewMenu: "Speisekarte ansehen",
|
||
myAccount: "Mein Konto",
|
||
},
|
||
login: {
|
||
title: "Anmeldung",
|
||
submit: "Anmelden",
|
||
or: "oder",
|
||
passkeyButton: "Mit Passkey anmelden",
|
||
backToMenu: "← Zur Speisekarte",
|
||
errorInvalidCredentials: "E-Mail-Adresse oder Passwort ist falsch.",
|
||
errorPasskeyCancelled: "Passkey-Anmeldung wurde abgebrochen.",
|
||
errorGeneric: "Anmeldung fehlgeschlagen: {message}",
|
||
errorPasswordDisabled:
|
||
"Die Anmeldung mit Passwort ist für dieses Konto deaktiviert. Bitte mit Passkey anmelden.",
|
||
},
|
||
publicMenu: {
|
||
prevWeek: "← Vorherige Woche",
|
||
nextWeek: "Nächste Woche →",
|
||
prevWeekShort: "← Woche",
|
||
nextWeekShort: "Woche →",
|
||
today: "Heute",
|
||
dayTab: "Tag",
|
||
weekTab: "Woche",
|
||
allergens: "Allergene",
|
||
additives: "Zusatzstoffe",
|
||
labelingNoticeTitle: "Allergene & Zusatzstoffe",
|
||
suggestDish: "Rezept vorschlagen",
|
||
noEntry: "–",
|
||
rssFeed: "RSS-Feed abonnieren",
|
||
},
|
||
weekEditor: {
|
||
title: "Wochenplan",
|
||
loading: "Lade Wochenplan…",
|
||
changeDish: "Anderes Gericht wählen",
|
||
addMeal: "Mahlzeit hinzufügen",
|
||
newDishesHint: "Neue Gerichte legst du unter {link} an.",
|
||
newDishesLinkLabel: "Gerichte",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
duplicateEntry: "Dieses Gericht ist an diesem Tag bereits zugewiesen.",
|
||
saveError: "Speichern fehlgeschlagen: {message}",
|
||
deleteError: "Löschen fehlgeschlagen: {message}",
|
||
},
|
||
dishManager: {
|
||
title: "Gerichte",
|
||
newDish: "Neues Gericht",
|
||
editDish: "Gericht bearbeiten",
|
||
nameLabel: "Bezeichnung",
|
||
nameEnLabel: "Name (Englisch)",
|
||
namePlLabel: "Name (Polnisch)",
|
||
autoTranslate: "Automatisch übersetzen",
|
||
translating: "Übersetze…",
|
||
translated: "Übersetzt.",
|
||
priceLabel: "Preis in €",
|
||
pricePlaceholder: "3,50",
|
||
searchPlaceholder: "Gericht suchen…",
|
||
selectAll: "Alle auswählen",
|
||
selectedCount: "{count} ausgewählt",
|
||
deleteSelected: "Ausgewählte löschen",
|
||
deleteSelectedCount: "Ausgewählte löschen ({count})",
|
||
empty: "Noch keine Gerichte angelegt.",
|
||
noResults: "Keine Treffer für „{query}“.",
|
||
confirmDelete:
|
||
"„{name}“ wirklich löschen? Das Gericht wird auch aus allen Wochenplänen entfernt.",
|
||
confirmDeleteSelected:
|
||
"{count} Gericht(e) wirklich löschen? Sie werden auch aus allen Wochenplänen entfernt.",
|
||
invalidPrice: "Bitte einen gültigen Preis angeben, z. B. 3,50",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
saveError: "Speichern fehlgeschlagen: {message}",
|
||
deleteError: "Löschen fehlgeschlagen: {message}",
|
||
exportButton: "Exportieren",
|
||
importButton: "Importieren",
|
||
exportError: "Export fehlgeschlagen: {message}",
|
||
importError: "Import fehlgeschlagen: {message}",
|
||
importSuccess: "{created} neu angelegt, {updated} aktualisiert.",
|
||
importSkipped: "{count} Zeile(n) übersprungen: {reasons}",
|
||
importSkippedRow: "Zeile {row}: {reason}",
|
||
labelingDisabledHint:
|
||
"Allergene/Zusatzstoffe sind aktuell deaktiviert (Hinweismodus aktiv, siehe „Allergene & Zusatzstoffe“).",
|
||
},
|
||
codeList: {
|
||
allergensTitle: "Allergene",
|
||
additivesTitle: "Zusatzstoffe",
|
||
allergenCodeLabel: "Kürzel (z. B. A)",
|
||
additiveCodeLabel: "Kürzel (z. B. 1)",
|
||
nameLabel: "Bezeichnung",
|
||
empty: "Keine Einträge.",
|
||
confirmDelete: "„{code} – {name}“ wirklich löschen?",
|
||
duplicateCode: "Das Kürzel „{code}“ existiert bereits.",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
saveError: "Speichern fehlgeschlagen: {message}",
|
||
deleteError: "Löschen fehlgeschlagen: {message}",
|
||
exportButton: "Exportieren",
|
||
importButton: "Importieren",
|
||
exportError: "Export fehlgeschlagen: {message}",
|
||
importError: "Import fehlgeschlagen: {message}",
|
||
importSuccess: "{created} neu angelegt, {updated} aktualisiert.",
|
||
importSkipped: "{count} Zeile(n) übersprungen: {reasons}",
|
||
importSkippedRow: "Zeile {row}: {reason}",
|
||
},
|
||
sectionManager: {
|
||
title: "Essenszeiten",
|
||
newSection: "Neue Essenszeit",
|
||
editSection: "Essenszeit bearbeiten",
|
||
nameLabel: "Bezeichnung",
|
||
nameEnLabel: "Bezeichnung (Englisch)",
|
||
namePlLabel: "Bezeichnung (Polnisch)",
|
||
timeFrom: "Von",
|
||
timeTo: "Bis",
|
||
moveUp: "Nach oben",
|
||
moveDown: "Nach unten",
|
||
empty: "Noch keine Essenszeiten angelegt.",
|
||
confirmDelete:
|
||
"„{name}“ wirklich löschen? Zugewiesene Gerichte werden auch aus allen Wochenplänen entfernt.",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
saveError: "Speichern fehlgeschlagen: {message}",
|
||
deleteError: "Löschen fehlgeschlagen: {message}",
|
||
},
|
||
userManager: {
|
||
title: "Benutzer",
|
||
newUser: "Neuer Benutzer",
|
||
editUser: "Benutzer bearbeiten",
|
||
newPasswordLabel: "Neues Passwort (optional)",
|
||
repeatPasswordLabel: "Passwort wiederholen",
|
||
passwordMismatch: "Die Passwörter stimmen nicht überein.",
|
||
confirmDelete:
|
||
"Benutzer „{email}“ wirklich löschen? Der Zugang wird dauerhaft entfernt.",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
},
|
||
designEditor: {
|
||
title: "Design",
|
||
logoTitle: "Logo",
|
||
logoHint: "Das Logo wird zentriert über der Speisekarte angezeigt.",
|
||
logoNone: "Kein Logo hinterlegt.",
|
||
logoUpload: "Logo hochladen",
|
||
logoRemove: "Logo entfernen",
|
||
logoUpdated: "Logo aktualisiert.",
|
||
logoRemoved: "Logo entfernt.",
|
||
faviconTitle: "Favicon",
|
||
faviconHint:
|
||
"Wird als Icon im Browser-Tab angezeigt. Ohne eigenes Favicon gilt das Standard-Icon der Anwendung.",
|
||
faviconNone: "Kein eigenes Favicon hinterlegt.",
|
||
faviconUpload: "Favicon hochladen",
|
||
faviconRemove: "Favicon entfernen",
|
||
faviconUpdated: "Favicon aktualisiert.",
|
||
faviconRemoved: "Favicon entfernt.",
|
||
invalidImage: "Bitte eine Bilddatei auswählen (PNG, JPG, SVG, WebP, ICO).",
|
||
colorsTitle: "Farbgebung",
|
||
colorsSave: "Farben speichern",
|
||
colorsReset: "Auf Standard zurücksetzen",
|
||
colorsSaved: "Farben gespeichert.",
|
||
colorPrimary: "Primärfarbe (Tabellenkopf)",
|
||
colorPrimaryDark: "Primärfarbe dunkel (Kopfleiste intern)",
|
||
colorAccent: "Akzentfarbe",
|
||
colorHeaderText: "Schriftfarbe im Tabellenkopf",
|
||
colorRowBg: "Zellen-Hintergrund",
|
||
colorRowBgAlt: "Zellen-Hintergrund (alternierend)",
|
||
colorAddBtn: "Button „Hinzufügen“",
|
||
colorDeleteBtn: "Button „Löschen“",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
saveError: "Speichern fehlgeschlagen: {message}",
|
||
uploadError: "Upload fehlgeschlagen: {message}",
|
||
confirmRemoveLogo: "Logo wirklich entfernen?",
|
||
confirmRemoveFavicon: "Favicon wirklich entfernen?",
|
||
},
|
||
labelingNotice: {
|
||
title: "Anzeige von Allergenen & Zusatzstoffen",
|
||
hint:
|
||
"Standardmäßig sieht jeder Gast eine detaillierte Auswahl der Allergene/Zusatzstoffe je Gericht. Alternativ kann stattdessen nur ein Hinweistext angezeigt werden – die Auswahl je Gericht wird dann auch in der Gerichte-Verwaltung ausgeblendet.",
|
||
modeDetailed: "Detaillierte Auswahl je Gericht anzeigen",
|
||
modeNotice: "Nur Hinweistext anzeigen",
|
||
noticeDeLabel: "Hinweistext (Deutsch)",
|
||
noticeEnLabel: "Hinweistext (Englisch)",
|
||
noticePlLabel: "Hinweistext (Polnisch)",
|
||
save: "Speichern",
|
||
saved: "Gespeichert.",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
saveError: "Speichern fehlgeschlagen: {message}",
|
||
},
|
||
passkeys: {
|
||
title: "Passkeys",
|
||
hint: "Mit einem Passkey (Fingerabdruck, Gesichtserkennung oder Sicherheitsschlüssel) kannst du dich künftig ohne Passwort anmelden. Passkeys gelten pro Domain – nach einem Domainwechsel müssen sie neu registriert werden.",
|
||
register: "Neuen Passkey registrieren",
|
||
empty: "Noch keine Passkeys registriert.",
|
||
createdOn: "– angelegt am {date}",
|
||
registered: "Passkey wurde erfolgreich registriert.",
|
||
registerError: "Registrierung fehlgeschlagen: {message}",
|
||
registerCancelled: "Die Passkey-Registrierung wurde abgebrochen.",
|
||
loadError: "Passkeys konnten nicht geladen werden: {message}",
|
||
deleteError: "Löschen fehlgeschlagen: {message}",
|
||
confirmDelete: "Diesen Passkey wirklich löschen?",
|
||
},
|
||
account: {
|
||
title: "Mein Konto",
|
||
personalTitle: "Persönliche Daten",
|
||
saveName: "Name speichern",
|
||
nameSaved: "Name gespeichert.",
|
||
nameRequired: "Bitte einen Namen angeben.",
|
||
emailTitle: "E-Mail-Adresse",
|
||
changeEmail: "E-Mail-Adresse ändern",
|
||
emailChanged: "E-Mail-Adresse geändert.",
|
||
passwordTitle: "Passwort ändern",
|
||
currentPassword: "Aktuelles Passwort (zur Verifizierung)",
|
||
newPassword: "Neues Passwort",
|
||
newPasswordRepeat: "Neues Passwort wiederholen",
|
||
changePassword: "Passwort ändern",
|
||
passwordChanged: "Passwort geändert.",
|
||
passwordMismatch: "Die Passwörter stimmen nicht überein.",
|
||
passwordTooShort: "Das neue Passwort muss mindestens 8 Zeichen lang sein.",
|
||
passwordAuthTitle: "Anmeldung mit Passwort",
|
||
passwordAuthHint:
|
||
"Du kannst die Anmeldung mit E-Mail und Passwort für dein Konto deaktivieren und dich künftig ausschließlich per Passkey anmelden. Dafür muss mindestens ein Passkey registriert sein.",
|
||
passwordAuthCheckbox: "Anmeldung mit E-Mail und Passwort erlaubt",
|
||
passwordAuthEnabled: "Passwort-Anmeldung aktiviert.",
|
||
passwordAuthDisabled: "Passwort-Anmeldung deaktiviert.",
|
||
passwordAuthNeedsPasskey:
|
||
"Ohne registrierten Passkey kannst du die Passwort-Anmeldung nicht deaktivieren – sonst wärst du ausgesperrt. Registriere zuerst einen Passkey weiter unten.",
|
||
confirmDisablePasswordAuth:
|
||
"Anmeldung mit E-Mail und Passwort wirklich deaktivieren? Du kannst dich danach nur noch per Passkey anmelden.",
|
||
wrongCurrentPassword: "Das aktuelle Passwort ist falsch.",
|
||
emailAlreadyUsed: "Diese E-Mail-Adresse wird bereits verwendet.",
|
||
saveError: "Speichern fehlgeschlagen: {message}",
|
||
changeError: "Ändern fehlgeschlagen: {message}",
|
||
},
|
||
suggestions: {
|
||
formTitle: "Rezept vorschlagen",
|
||
formHint:
|
||
"Fehlt dir ein Gericht auf der Speisekarte? Schlage es hier vor – das Kantinen-Team sichtet deinen Vorschlag.",
|
||
nameLabel: "Gerichtname",
|
||
descriptionLabel: "Beschreibung / Zutaten (optional)",
|
||
submit: "Vorschlag senden",
|
||
submitting: "Wird gesendet…",
|
||
success: "Danke! Dein Vorschlag wurde übermittelt.",
|
||
duplicate: "Dieses Gericht gibt es bereits auf der Speisekarte.",
|
||
genericError: "Senden fehlgeschlagen: {message}",
|
||
nameRequired: "Bitte einen Namen angeben.",
|
||
backToMenu: "← Zur Speisekarte",
|
||
reviewTitle: "Rezeptvorschläge",
|
||
reviewEmpty: "Noch keine Vorschläge.",
|
||
accept: "Als Gericht übernehmen",
|
||
reject: "Ablehnen",
|
||
confirmReject: "Vorschlag „{name}“ wirklich ablehnen und löschen?",
|
||
accepted: "Als Gericht übernommen.",
|
||
rejected: "Vorschlag abgelehnt.",
|
||
loadError: "Laden fehlgeschlagen: {message}",
|
||
actionError: "Aktion fehlgeschlagen: {message}",
|
||
submittedOn: "eingereicht am {date}",
|
||
},
|
||
};
|
||
|
||
type Dict = typeof de;
|
||
|
||
const en: Dict = {
|
||
common: {
|
||
save: "Save",
|
||
cancel: "Cancel",
|
||
delete: "Delete",
|
||
edit: "Edit",
|
||
add: "Add",
|
||
back: "Back",
|
||
login: "Log in",
|
||
logout: "Log out",
|
||
loading: "Loading…",
|
||
you: "(you)",
|
||
name: "Name",
|
||
email: "Email address",
|
||
password: "Password",
|
||
role: "Role",
|
||
roleAdmin: "Administrator",
|
||
roleStaff: "Canteen staff",
|
||
},
|
||
weekdays: {
|
||
long: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"],
|
||
short: ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
||
},
|
||
dateLocale: "en-GB",
|
||
header: {
|
||
canteen: "Canteen",
|
||
menuGroup: "Menu",
|
||
weekPlan: "Weekly plan",
|
||
sections: "Meal times",
|
||
dishes: "Dishes",
|
||
labels: "Allergens & Additives",
|
||
adminGroup: "Administration",
|
||
users: "Users",
|
||
design: "Design",
|
||
suggestions: "Suggestions",
|
||
openSuggestions: "{count} open dish suggestions",
|
||
viewMenu: "View menu",
|
||
myAccount: "My account",
|
||
},
|
||
login: {
|
||
title: "Sign in",
|
||
submit: "Log in",
|
||
or: "or",
|
||
passkeyButton: "Sign in with passkey",
|
||
backToMenu: "← Back to menu",
|
||
errorInvalidCredentials: "Email address or password is incorrect.",
|
||
errorPasskeyCancelled: "Passkey sign-in was cancelled.",
|
||
errorGeneric: "Sign-in failed: {message}",
|
||
errorPasswordDisabled:
|
||
"Password sign-in is disabled for this account. Please sign in with a passkey.",
|
||
},
|
||
publicMenu: {
|
||
prevWeek: "← Previous week",
|
||
nextWeek: "Next week →",
|
||
prevWeekShort: "← Week",
|
||
nextWeekShort: "Week →",
|
||
today: "Today",
|
||
dayTab: "Day",
|
||
weekTab: "Week",
|
||
allergens: "Allergens",
|
||
additives: "Additives",
|
||
labelingNoticeTitle: "Allergens & additives",
|
||
suggestDish: "Suggest a dish",
|
||
noEntry: "–",
|
||
rssFeed: "Subscribe to RSS feed",
|
||
},
|
||
weekEditor: {
|
||
title: "Weekly plan",
|
||
loading: "Loading weekly plan…",
|
||
changeDish: "Choose a different dish",
|
||
addMeal: "Add meal",
|
||
newDishesHint: "Add new dishes under {link}.",
|
||
newDishesLinkLabel: "Dishes",
|
||
loadError: "Loading failed: {message}",
|
||
duplicateEntry: "This dish is already assigned on this day.",
|
||
saveError: "Saving failed: {message}",
|
||
deleteError: "Deleting failed: {message}",
|
||
},
|
||
dishManager: {
|
||
title: "Dishes",
|
||
newDish: "New dish",
|
||
editDish: "Edit dish",
|
||
nameLabel: "Name",
|
||
nameEnLabel: "Name (English)",
|
||
namePlLabel: "Name (Polish)",
|
||
autoTranslate: "Auto-translate",
|
||
translating: "Translating…",
|
||
translated: "Translated.",
|
||
priceLabel: "Price in €",
|
||
pricePlaceholder: "3.50",
|
||
searchPlaceholder: "Search dishes…",
|
||
selectAll: "Select all",
|
||
selectedCount: "{count} selected",
|
||
deleteSelected: "Delete selected",
|
||
deleteSelectedCount: "Delete selected ({count})",
|
||
empty: "No dishes yet.",
|
||
noResults: "No results for “{query}”.",
|
||
confirmDelete:
|
||
"Really delete “{name}”? The dish will also be removed from all weekly plans.",
|
||
confirmDeleteSelected:
|
||
"Really delete {count} dish(es)? They will also be removed from all weekly plans.",
|
||
invalidPrice: "Please enter a valid price, e.g. 3.50",
|
||
loadError: "Loading failed: {message}",
|
||
saveError: "Saving failed: {message}",
|
||
deleteError: "Deleting failed: {message}",
|
||
exportButton: "Export",
|
||
importButton: "Import",
|
||
exportError: "Export failed: {message}",
|
||
importError: "Import failed: {message}",
|
||
importSuccess: "{created} created, {updated} updated.",
|
||
importSkipped: "{count} row(s) skipped: {reasons}",
|
||
importSkippedRow: "Row {row}: {reason}",
|
||
labelingDisabledHint:
|
||
"Allergens/additives are currently disabled (notice mode active, see \"Allergens & additives\").",
|
||
},
|
||
codeList: {
|
||
allergensTitle: "Allergens",
|
||
additivesTitle: "Additives",
|
||
allergenCodeLabel: "Code (e.g. A)",
|
||
additiveCodeLabel: "Code (e.g. 1)",
|
||
nameLabel: "Name",
|
||
empty: "No entries.",
|
||
confirmDelete: "Really delete “{code} – {name}”?",
|
||
duplicateCode: "The code “{code}” already exists.",
|
||
loadError: "Loading failed: {message}",
|
||
saveError: "Saving failed: {message}",
|
||
deleteError: "Deleting failed: {message}",
|
||
exportButton: "Export",
|
||
importButton: "Import",
|
||
exportError: "Export failed: {message}",
|
||
importError: "Import failed: {message}",
|
||
importSuccess: "{created} created, {updated} updated.",
|
||
importSkipped: "{count} row(s) skipped: {reasons}",
|
||
importSkippedRow: "Row {row}: {reason}",
|
||
},
|
||
sectionManager: {
|
||
title: "Meal times",
|
||
newSection: "New meal time",
|
||
editSection: "Edit meal time",
|
||
nameLabel: "Name",
|
||
nameEnLabel: "Name (English)",
|
||
namePlLabel: "Name (Polish)",
|
||
timeFrom: "From",
|
||
timeTo: "To",
|
||
moveUp: "Move up",
|
||
moveDown: "Move down",
|
||
empty: "No meal times yet.",
|
||
confirmDelete:
|
||
"Really delete “{name}”? Assigned dishes will also be removed from all weekly plans.",
|
||
loadError: "Loading failed: {message}",
|
||
saveError: "Saving failed: {message}",
|
||
deleteError: "Deleting failed: {message}",
|
||
},
|
||
userManager: {
|
||
title: "Users",
|
||
newUser: "New user",
|
||
editUser: "Edit user",
|
||
newPasswordLabel: "New password (optional)",
|
||
repeatPasswordLabel: "Repeat password",
|
||
passwordMismatch: "The passwords do not match.",
|
||
confirmDelete:
|
||
"Really delete user “{email}”? Access will be permanently removed.",
|
||
loadError: "Loading failed: {message}",
|
||
},
|
||
designEditor: {
|
||
title: "Design",
|
||
logoTitle: "Logo",
|
||
logoHint: "The logo is displayed centered above the menu.",
|
||
logoNone: "No logo set.",
|
||
logoUpload: "Upload logo",
|
||
logoRemove: "Remove logo",
|
||
logoUpdated: "Logo updated.",
|
||
logoRemoved: "Logo removed.",
|
||
faviconTitle: "Favicon",
|
||
faviconHint:
|
||
"Shown as the icon in the browser tab. Without a custom favicon, the application's default icon is used.",
|
||
faviconNone: "No custom favicon set.",
|
||
faviconUpload: "Upload favicon",
|
||
faviconRemove: "Remove favicon",
|
||
faviconUpdated: "Favicon updated.",
|
||
faviconRemoved: "Favicon removed.",
|
||
invalidImage: "Please choose an image file (PNG, JPG, SVG, WebP, ICO).",
|
||
colorsTitle: "Colors",
|
||
colorsSave: "Save colors",
|
||
colorsReset: "Reset to default",
|
||
colorsSaved: "Colors saved.",
|
||
colorPrimary: "Primary color (table header)",
|
||
colorPrimaryDark: "Primary color, dark (internal top bar)",
|
||
colorAccent: "Accent color",
|
||
colorHeaderText: "Table header text color",
|
||
colorRowBg: "Cell background",
|
||
colorRowBgAlt: "Cell background (alternating)",
|
||
colorAddBtn: "“Add” button",
|
||
colorDeleteBtn: "“Delete” button",
|
||
loadError: "Loading failed: {message}",
|
||
saveError: "Saving failed: {message}",
|
||
uploadError: "Upload failed: {message}",
|
||
confirmRemoveLogo: "Really remove the logo?",
|
||
confirmRemoveFavicon: "Really remove the favicon?",
|
||
},
|
||
labelingNotice: {
|
||
title: "Allergen & additive display",
|
||
hint:
|
||
"By default every guest sees a detailed allergen/additive selection per dish. Alternatively, only a notice text can be shown instead – the per-dish selection is then also hidden in the dish manager.",
|
||
modeDetailed: "Show detailed selection per dish",
|
||
modeNotice: "Show only notice text",
|
||
noticeDeLabel: "Notice text (German)",
|
||
noticeEnLabel: "Notice text (English)",
|
||
noticePlLabel: "Notice text (Polish)",
|
||
save: "Save",
|
||
saved: "Saved.",
|
||
loadError: "Loading failed: {message}",
|
||
saveError: "Saving failed: {message}",
|
||
},
|
||
passkeys: {
|
||
title: "Passkeys",
|
||
hint: "With a passkey (fingerprint, face recognition, or a security key) you can sign in without a password in the future. Passkeys are bound to a domain – after a domain change they need to be registered again.",
|
||
register: "Register new passkey",
|
||
empty: "No passkeys registered yet.",
|
||
createdOn: "– created on {date}",
|
||
registered: "Passkey registered successfully.",
|
||
registerError: "Registration failed: {message}",
|
||
registerCancelled: "Passkey registration was cancelled.",
|
||
loadError: "Could not load passkeys: {message}",
|
||
deleteError: "Deleting failed: {message}",
|
||
confirmDelete: "Really delete this passkey?",
|
||
},
|
||
account: {
|
||
title: "My account",
|
||
personalTitle: "Personal details",
|
||
saveName: "Save name",
|
||
nameSaved: "Name saved.",
|
||
nameRequired: "Please enter a name.",
|
||
emailTitle: "Email address",
|
||
changeEmail: "Change email address",
|
||
emailChanged: "Email address changed.",
|
||
passwordTitle: "Change password",
|
||
currentPassword: "Current password (for verification)",
|
||
newPassword: "New password",
|
||
newPasswordRepeat: "Repeat new password",
|
||
changePassword: "Change password",
|
||
passwordChanged: "Password changed.",
|
||
passwordMismatch: "The passwords do not match.",
|
||
passwordTooShort: "The new password must be at least 8 characters long.",
|
||
passwordAuthTitle: "Password sign-in",
|
||
passwordAuthHint:
|
||
"You can disable email and password sign-in for your account and sign in exclusively with a passkey in the future. At least one passkey must be registered for this.",
|
||
passwordAuthCheckbox: "Email and password sign-in allowed",
|
||
passwordAuthEnabled: "Password sign-in enabled.",
|
||
passwordAuthDisabled: "Password sign-in disabled.",
|
||
passwordAuthNeedsPasskey:
|
||
"You can't disable password sign-in without a registered passkey – you would lock yourself out. Register a passkey below first.",
|
||
confirmDisablePasswordAuth:
|
||
"Really disable email and password sign-in? Afterwards you can only sign in with a passkey.",
|
||
wrongCurrentPassword: "The current password is incorrect.",
|
||
emailAlreadyUsed: "This email address is already in use.",
|
||
saveError: "Saving failed: {message}",
|
||
changeError: "Change failed: {message}",
|
||
},
|
||
suggestions: {
|
||
formTitle: "Suggest a dish",
|
||
formHint:
|
||
"Missing a dish on the menu? Suggest it here – the canteen team will review your suggestion.",
|
||
nameLabel: "Dish name",
|
||
descriptionLabel: "Description / ingredients (optional)",
|
||
submit: "Submit suggestion",
|
||
submitting: "Submitting…",
|
||
success: "Thanks! Your suggestion has been submitted.",
|
||
duplicate: "This dish already exists on the menu.",
|
||
genericError: "Submission failed: {message}",
|
||
nameRequired: "Please enter a name.",
|
||
backToMenu: "← Back to menu",
|
||
reviewTitle: "Dish suggestions",
|
||
reviewEmpty: "No suggestions yet.",
|
||
accept: "Add as dish",
|
||
reject: "Reject",
|
||
confirmReject: "Really reject and delete the suggestion “{name}”?",
|
||
accepted: "Added as dish.",
|
||
rejected: "Suggestion rejected.",
|
||
loadError: "Loading failed: {message}",
|
||
actionError: "Action failed: {message}",
|
||
submittedOn: "submitted on {date}",
|
||
},
|
||
};
|
||
|
||
const pl: Dict = {
|
||
common: {
|
||
save: "Zapisz",
|
||
cancel: "Anuluj",
|
||
delete: "Usuń",
|
||
edit: "Edytuj",
|
||
add: "Dodaj",
|
||
back: "Wstecz",
|
||
login: "Zaloguj się",
|
||
logout: "Wyloguj się",
|
||
loading: "Wczytywanie…",
|
||
you: "(ty)",
|
||
name: "Nazwa",
|
||
email: "Adres e-mail",
|
||
password: "Hasło",
|
||
role: "Rola",
|
||
roleAdmin: "Administrator",
|
||
roleStaff: "Personel stołówki",
|
||
},
|
||
weekdays: {
|
||
long: ["Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek"],
|
||
short: ["Pon", "Wto", "Śro", "Czw", "Pią"],
|
||
},
|
||
dateLocale: "pl-PL",
|
||
header: {
|
||
canteen: "Stołówka",
|
||
menuGroup: "Jadłospis",
|
||
weekPlan: "Plan tygodnia",
|
||
sections: "Pory posiłków",
|
||
dishes: "Dania",
|
||
labels: "Alergeny i dodatki",
|
||
adminGroup: "Administracja",
|
||
users: "Użytkownicy",
|
||
design: "Wygląd",
|
||
suggestions: "Propozycje",
|
||
openSuggestions: "{count} otwartych propozycji dań",
|
||
viewMenu: "Zobacz jadłospis",
|
||
myAccount: "Moje konto",
|
||
},
|
||
login: {
|
||
title: "Logowanie",
|
||
submit: "Zaloguj się",
|
||
or: "lub",
|
||
passkeyButton: "Zaloguj się kluczem dostępu",
|
||
backToMenu: "← Powrót do jadłospisu",
|
||
errorInvalidCredentials: "Nieprawidłowy adres e-mail lub hasło.",
|
||
errorPasskeyCancelled: "Logowanie kluczem dostępu zostało anulowane.",
|
||
errorGeneric: "Logowanie nie powiodło się: {message}",
|
||
errorPasswordDisabled:
|
||
"Logowanie hasłem jest wyłączone dla tego konta. Zaloguj się kluczem dostępu.",
|
||
},
|
||
publicMenu: {
|
||
prevWeek: "← Poprzedni tydzień",
|
||
nextWeek: "Następny tydzień →",
|
||
prevWeekShort: "← Tydzień",
|
||
nextWeekShort: "Tydzień →",
|
||
today: "Dziś",
|
||
dayTab: "Dzień",
|
||
weekTab: "Tydzień",
|
||
allergens: "Alergeny",
|
||
additives: "Dodatki",
|
||
labelingNoticeTitle: "Alergeny i dodatki",
|
||
suggestDish: "Zaproponuj danie",
|
||
noEntry: "–",
|
||
rssFeed: "Subskrybuj kanał RSS",
|
||
},
|
||
weekEditor: {
|
||
title: "Plan tygodnia",
|
||
loading: "Wczytywanie planu tygodnia…",
|
||
changeDish: "Wybierz inne danie",
|
||
addMeal: "Dodaj posiłek",
|
||
newDishesHint: "Nowe dania możesz dodać w zakładce {link}.",
|
||
newDishesLinkLabel: "Dania",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
duplicateEntry: "To danie jest już przypisane na ten dzień.",
|
||
saveError: "Zapisywanie nie powiodło się: {message}",
|
||
deleteError: "Usuwanie nie powiodło się: {message}",
|
||
},
|
||
dishManager: {
|
||
title: "Dania",
|
||
newDish: "Nowe danie",
|
||
editDish: "Edytuj danie",
|
||
nameLabel: "Nazwa",
|
||
nameEnLabel: "Nazwa (angielski)",
|
||
namePlLabel: "Nazwa (polski)",
|
||
autoTranslate: "Przetłumacz automatycznie",
|
||
translating: "Tłumaczenie…",
|
||
translated: "Przetłumaczono.",
|
||
priceLabel: "Cena w €",
|
||
pricePlaceholder: "3,50",
|
||
searchPlaceholder: "Szukaj dania…",
|
||
selectAll: "Zaznacz wszystko",
|
||
selectedCount: "Zaznaczono: {count}",
|
||
deleteSelected: "Usuń zaznaczone",
|
||
deleteSelectedCount: "Usuń zaznaczone ({count})",
|
||
empty: "Nie dodano jeszcze żadnych dań.",
|
||
noResults: "Brak wyników dla „{query}”.",
|
||
confirmDelete:
|
||
"Czy na pewno usunąć „{name}”? Danie zostanie również usunięte ze wszystkich planów tygodniowych.",
|
||
confirmDeleteSelected:
|
||
"Czy na pewno usunąć {count} danie/dania? Zostaną również usunięte ze wszystkich planów tygodniowych.",
|
||
invalidPrice: "Podaj prawidłową cenę, np. 3,50",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
saveError: "Zapisywanie nie powiodło się: {message}",
|
||
deleteError: "Usuwanie nie powiodło się: {message}",
|
||
exportButton: "Eksportuj",
|
||
importButton: "Importuj",
|
||
exportError: "Eksport nie powiódł się: {message}",
|
||
importError: "Import nie powiódł się: {message}",
|
||
importSuccess: "Utworzono: {created}, zaktualizowano: {updated}.",
|
||
importSkipped: "Pominięto wierszy: {count}: {reasons}",
|
||
importSkippedRow: "Wiersz {row}: {reason}",
|
||
labelingDisabledHint:
|
||
"Alergeny/dodatki są obecnie wyłączone (aktywny tryb komunikatu, patrz „Alergeny i dodatki”).",
|
||
},
|
||
codeList: {
|
||
allergensTitle: "Alergeny",
|
||
additivesTitle: "Dodatki",
|
||
allergenCodeLabel: "Kod (np. A)",
|
||
additiveCodeLabel: "Kod (np. 1)",
|
||
nameLabel: "Nazwa",
|
||
empty: "Brak wpisów.",
|
||
confirmDelete: "Czy na pewno usunąć „{code} – {name}”?",
|
||
duplicateCode: "Kod „{code}” już istnieje.",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
saveError: "Zapisywanie nie powiodło się: {message}",
|
||
deleteError: "Usuwanie nie powiodło się: {message}",
|
||
exportButton: "Eksportuj",
|
||
importButton: "Importuj",
|
||
exportError: "Eksport nie powiódł się: {message}",
|
||
importError: "Import nie powiódł się: {message}",
|
||
importSuccess: "Utworzono: {created}, zaktualizowano: {updated}.",
|
||
importSkipped: "Pominięto wierszy: {count}: {reasons}",
|
||
importSkippedRow: "Wiersz {row}: {reason}",
|
||
},
|
||
sectionManager: {
|
||
title: "Pory posiłków",
|
||
newSection: "Nowa pora posiłku",
|
||
editSection: "Edytuj porę posiłku",
|
||
nameLabel: "Nazwa",
|
||
nameEnLabel: "Nazwa (angielski)",
|
||
namePlLabel: "Nazwa (polski)",
|
||
timeFrom: "Od",
|
||
timeTo: "Do",
|
||
moveUp: "Przesuń w górę",
|
||
moveDown: "Przesuń w dół",
|
||
empty: "Nie dodano jeszcze żadnych pór posiłków.",
|
||
confirmDelete:
|
||
"Czy na pewno usunąć „{name}”? Przypisane dania zostaną również usunięte ze wszystkich planów tygodniowych.",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
saveError: "Zapisywanie nie powiodło się: {message}",
|
||
deleteError: "Usuwanie nie powiodło się: {message}",
|
||
},
|
||
userManager: {
|
||
title: "Użytkownicy",
|
||
newUser: "Nowy użytkownik",
|
||
editUser: "Edytuj użytkownika",
|
||
newPasswordLabel: "Nowe hasło (opcjonalnie)",
|
||
repeatPasswordLabel: "Powtórz hasło",
|
||
passwordMismatch: "Hasła nie są zgodne.",
|
||
confirmDelete:
|
||
"Czy na pewno usunąć użytkownika „{email}”? Dostęp zostanie trwale usunięty.",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
},
|
||
designEditor: {
|
||
title: "Wygląd",
|
||
logoTitle: "Logo",
|
||
logoHint: "Logo jest wyświetlane wyśrodkowane nad jadłospisem.",
|
||
logoNone: "Nie ustawiono logo.",
|
||
logoUpload: "Prześlij logo",
|
||
logoRemove: "Usuń logo",
|
||
logoUpdated: "Logo zaktualizowane.",
|
||
logoRemoved: "Logo usunięte.",
|
||
faviconTitle: "Favicon",
|
||
faviconHint:
|
||
"Wyświetlane jako ikona na karcie przeglądarki. Bez własnego favicona używana jest domyślna ikona aplikacji.",
|
||
faviconNone: "Nie ustawiono własnego favicona.",
|
||
faviconUpload: "Prześlij favicon",
|
||
faviconRemove: "Usuń favicon",
|
||
faviconUpdated: "Favicon zaktualizowany.",
|
||
faviconRemoved: "Favicon usunięty.",
|
||
invalidImage: "Wybierz plik graficzny (PNG, JPG, SVG, WebP, ICO).",
|
||
colorsTitle: "Kolorystyka",
|
||
colorsSave: "Zapisz kolory",
|
||
colorsReset: "Przywróć domyślne",
|
||
colorsSaved: "Kolory zapisane.",
|
||
colorPrimary: "Kolor główny (nagłówek tabeli)",
|
||
colorPrimaryDark: "Kolor główny, ciemny (górny pasek wewnętrzny)",
|
||
colorAccent: "Kolor akcentu",
|
||
colorHeaderText: "Kolor tekstu w nagłówku tabeli",
|
||
colorRowBg: "Tło komórek",
|
||
colorRowBgAlt: "Tło komórek (naprzemienne)",
|
||
colorAddBtn: "Przycisk „Dodaj”",
|
||
colorDeleteBtn: "Przycisk „Usuń”",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
saveError: "Zapisywanie nie powiodło się: {message}",
|
||
uploadError: "Przesyłanie nie powiodło się: {message}",
|
||
confirmRemoveLogo: "Czy na pewno usunąć logo?",
|
||
confirmRemoveFavicon: "Czy na pewno usunąć favicon?",
|
||
},
|
||
labelingNotice: {
|
||
title: "Wyświetlanie alergenów i dodatków",
|
||
hint:
|
||
"Domyślnie każdy gość widzi szczegółowy wybór alergenów/dodatków dla każdego dania. Alternatywnie można zamiast tego wyświetlić tylko komunikat – wybór dla poszczególnych dań zostanie wtedy również ukryty w zarządzaniu daniami.",
|
||
modeDetailed: "Pokaż szczegółowy wybór dla każdego dania",
|
||
modeNotice: "Pokaż tylko komunikat",
|
||
noticeDeLabel: "Tekst komunikatu (niemiecki)",
|
||
noticeEnLabel: "Tekst komunikatu (angielski)",
|
||
noticePlLabel: "Tekst komunikatu (polski)",
|
||
save: "Zapisz",
|
||
saved: "Zapisano.",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
saveError: "Zapisywanie nie powiodło się: {message}",
|
||
},
|
||
passkeys: {
|
||
title: "Klucze dostępu",
|
||
hint: "Dzięki kluczowi dostępu (odcisk palca, rozpoznawanie twarzy lub klucz bezpieczeństwa) możesz w przyszłości logować się bez hasła. Klucze dostępu są przypisane do domeny – po zmianie domeny trzeba je zarejestrować ponownie.",
|
||
register: "Zarejestruj nowy klucz dostępu",
|
||
empty: "Nie zarejestrowano jeszcze żadnych kluczy dostępu.",
|
||
createdOn: "– utworzono {date}",
|
||
registered: "Klucz dostępu został pomyślnie zarejestrowany.",
|
||
registerError: "Rejestracja nie powiodła się: {message}",
|
||
registerCancelled: "Rejestracja klucza dostępu została anulowana.",
|
||
loadError: "Nie udało się wczytać kluczy dostępu: {message}",
|
||
deleteError: "Usuwanie nie powiodło się: {message}",
|
||
confirmDelete: "Czy na pewno usunąć ten klucz dostępu?",
|
||
},
|
||
account: {
|
||
title: "Moje konto",
|
||
personalTitle: "Dane osobowe",
|
||
saveName: "Zapisz nazwę",
|
||
nameSaved: "Nazwa zapisana.",
|
||
nameRequired: "Podaj nazwę.",
|
||
emailTitle: "Adres e-mail",
|
||
changeEmail: "Zmień adres e-mail",
|
||
emailChanged: "Adres e-mail zmieniony.",
|
||
passwordTitle: "Zmień hasło",
|
||
currentPassword: "Obecne hasło (do weryfikacji)",
|
||
newPassword: "Nowe hasło",
|
||
newPasswordRepeat: "Powtórz nowe hasło",
|
||
changePassword: "Zmień hasło",
|
||
passwordChanged: "Hasło zmienione.",
|
||
passwordMismatch: "Hasła nie są zgodne.",
|
||
passwordTooShort: "Nowe hasło musi mieć co najmniej 8 znaków.",
|
||
passwordAuthTitle: "Logowanie hasłem",
|
||
passwordAuthHint:
|
||
"Możesz wyłączyć logowanie e-mailem i hasłem dla swojego konta i logować się w przyszłości wyłącznie kluczem dostępu. Wymaga to zarejestrowania co najmniej jednego klucza dostępu.",
|
||
passwordAuthCheckbox: "Logowanie e-mailem i hasłem dozwolone",
|
||
passwordAuthEnabled: "Logowanie hasłem włączone.",
|
||
passwordAuthDisabled: "Logowanie hasłem wyłączone.",
|
||
passwordAuthNeedsPasskey:
|
||
"Bez zarejestrowanego klucza dostępu nie możesz wyłączyć logowania hasłem – stracisz dostęp do konta. Najpierw zarejestruj klucz dostępu poniżej.",
|
||
confirmDisablePasswordAuth:
|
||
"Czy na pewno wyłączyć logowanie e-mailem i hasłem? Potem będziesz mógł/mogła zalogować się tylko kluczem dostępu.",
|
||
wrongCurrentPassword: "Obecne hasło jest nieprawidłowe.",
|
||
emailAlreadyUsed: "Ten adres e-mail jest już używany.",
|
||
saveError: "Zapisywanie nie powiodło się: {message}",
|
||
changeError: "Zmiana nie powiodła się: {message}",
|
||
},
|
||
suggestions: {
|
||
formTitle: "Zaproponuj danie",
|
||
formHint:
|
||
"Brakuje dania w jadłospisie? Zaproponuj je tutaj – zespół stołówki sprawdzi Twoją propozycję.",
|
||
nameLabel: "Nazwa dania",
|
||
descriptionLabel: "Opis / składniki (opcjonalnie)",
|
||
submit: "Wyślij propozycję",
|
||
submitting: "Wysyłanie…",
|
||
success: "Dziękujemy! Twoja propozycja została przesłana.",
|
||
duplicate: "To danie już istnieje w jadłospisie.",
|
||
genericError: "Wysyłanie nie powiodło się: {message}",
|
||
nameRequired: "Podaj nazwę.",
|
||
backToMenu: "← Powrót do jadłospisu",
|
||
reviewTitle: "Propozycje dań",
|
||
reviewEmpty: "Brak propozycji.",
|
||
accept: "Dodaj jako danie",
|
||
reject: "Odrzuć",
|
||
confirmReject: "Czy na pewno odrzucić i usunąć propozycję „{name}”?",
|
||
accepted: "Dodano jako danie.",
|
||
rejected: "Propozycja odrzucona.",
|
||
loadError: "Wczytywanie nie powiodło się: {message}",
|
||
actionError: "Czynność nie powiodła się: {message}",
|
||
submittedOn: "przesłano {date}",
|
||
},
|
||
};
|
||
|
||
export type { Dict };
|
||
export const dictionaries = { de, en, pl };
|