Files
GerbilManager/gerbil-manager-web/src/strings/de.ts
Gulum 156ede120e Merge branch 'worktree-agent-ae59040b377a324cb'
# Conflicts:
#	GerbilManagerWebAPI/ApplicationContext.cs
#	GerbilManagerWebAPI/Program.cs
#	gerbil-manager-web/e2e/mock-data.ts
#	gerbil-manager-web/src/pages/GerbilDetailPage.tsx
#	gerbil-manager-web/src/strings/de.ts
2026-06-22 23:10:18 +02:00

1424 lines
56 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Zentrale deutsche Texte der Anwendung.
* Alle für Benutzer sichtbaren Zeichenketten gehören hierher —
* niemals Texte direkt in Komponenten hartkodieren.
*/
export const de = {
app: {
title: 'Rennmaus-Manager',
tagline: 'Verwaltung für Rennmäuse, Würfe und Züchter',
},
nav: {
gerbils: 'Rennmäuse',
litters: 'Würfe',
breeders: 'Züchter',
genetics: 'Genetik',
// FEAT-2 (Oscar): Becken + Kontakte (GEHEGE-RENAME: Becken → Gehege)
enclosures: 'Gehege',
contacts: 'Kontakte',
// FEAT-7 (Kelly): Statistik
statistics: 'Statistik',
// FEAT-7 (Kevin): „Mehr“-Overflow auf dem Smartphone
more: 'Mehr',
// FEAT-12a (Kevin): Abgabe
forSale: 'Abgabe',
// ABGABE-STATUS: Reservierungs-/Abgabe-Status (verfügbar → reserviert → abgegeben)
reservations: 'Reservierungen',
// FEAT-13 (Kelly): Verträge + Einstellungen
contracts: 'Verträge',
settings: 'Einstellungen',
// INBOX-1 (Kelly): Anfragen-Posteingang
requests: 'Anfragen',
// WAITLIST: Warteliste/Nachfrage (RennmausPro nachfrage_tb)
waitingList: 'Warteliste',
// RÜCKNAHMEN: zurückgekommene/zurückgenommene Tiere
returns: 'Rücknahmen',
openMenu: 'Menü öffnen',
closeMenu: 'Menü schließen',
mainNavigation: 'Hauptnavigation',
// HELP-1
help: 'Hilfe',
// WEB-0b (Kevin): CMS-Verwaltung der öffentlichen Webseite
website: 'Webseite',
colorCatalog: 'Farbkatalog',
},
pages: {
gerbils: {
title: 'Rennmäuse',
nameless: '(ohne Namen)',
// Liste
newButton: 'Neue Rennmaus',
empty: 'Keine Rennmäuse gefunden.',
countLabel: 'Tiere',
searchPlaceholder: 'Name suchen …',
// DESIGN (Rennmaus Filter): „geb." Präfix vor dem Geburtsdatum auf der Karte.
born: 'geb.',
// Zurück-nach-oben-Button (erscheint beim Scrollen der langen Liste).
backToTop: 'Nach oben',
// BESTAND-FILTER: Kennzeichnung externer (nicht zum eigenen Bestand gehörender) Tiere
externalBadge: 'Extern',
externalTitle: 'Externes Tier — gehört nicht zum eigenen Bestand, nur für den Stammbaum erfasst.',
// Filter-Beschriftungen
filters: {
title: 'Filter',
status: 'Status',
gender: 'Geschlecht',
colorVariety: 'Farbschlag',
all: 'Alle',
reset: 'Filter zurücksetzen',
sortBy: 'Sortieren nach',
// BESTAND-FILTER: eigener Bestand (Clan) vs. externe Ahnen (nur Stammbaum)
showExternal: 'Externe Ahnen einblenden',
// DESIGN (Rennmaus Filter): kurze Variante für den Toggle-Chip.
showExternalShort: 'Externe Ahnen',
showExternalHint: 'Tiere aus fremden Zuchten, die nur für den Stammbaum erfasst sind.',
// BESTAND-FILTER: Tiere ohne Geburtsdatum ausblenden (Toggle-Chip neben „Externe Ahnen“).
hideUndatedShort: 'Mit Geburtsdatum',
hideUndatedHint: 'Tiere ohne hinterlegtes Geburtsdatum ausblenden.',
},
// Sortier-Optionen
sort: {
nameAsc: 'Name (AZ)',
nameDesc: 'Name (ZA)',
birthDesc: 'Geburtsdatum (neueste)',
birthAsc: 'Geburtsdatum (älteste)',
},
// Feld-Beschriftungen (Stammdaten)
fields: {
name: 'Name',
gender: 'Geschlecht',
status: 'Status',
dateOfBirth: 'Geburtsdatum',
dateOfDeath: 'Todesdatum',
causeOfDeath: 'Todesursache',
goHomeDate: 'Abgabedatum',
litter: 'Wurf',
enclosure: 'Gehege',
colorVariety: 'Farbschlag',
origin: 'Herkunft',
originBreeder: 'Herkunft (Freitext)',
isDeaf: 'Gehörlos',
receiver: 'Abnehmer',
genotype: 'Genotyp',
isCastrated: 'Kastrat',
notes: 'Notizen',
spottingType: 'Scheckungsart',
},
// Detailseite
detail: {
masterData: 'Stammdaten',
genetics: 'Genetik',
resolvedFarbschlag: 'Errechneter Farbschlag',
resolvedPrefix: 'Errechnet',
farbschlagMismatch: 'Weicht vom eingetragenen Farbschlag ab.',
genotypeNotSet: 'Kein Genotyp hinterlegt.',
testMating: 'Probeverpaarung',
edit: 'Bearbeiten',
back: 'Zurück zur Liste',
tabs: {
photos: 'Fotos',
health: 'Gesundheit',
weight: 'Gewicht',
exhibitions: 'Ausstellungen',
},
tabPlaceholder: 'Dieser Bereich entsteht in einem späteren Schritt.',
notFound: 'Diese Rennmaus wurde nicht gefunden.',
moreData: 'Weitere Daten',
// ANIMAL-LITTERS: Würfe als Elternteil
parentLittersTitle: 'Würfe als Elternteil',
parentLittersEmpty: 'Keine Würfe als Elternteil erfasst.',
parentLittersRoleVater: 'Vater',
parentLittersRoleMutter: 'Mutter',
// Hinweis: Eltern dieses Tiers sind Vollgeschwister (gleicher Wurf).
siblingPairing: 'Geschwisterverpaarung',
siblingPairingTitle:
'Die Eltern dieses Tiers stammen aus demselben Wurf (Vollgeschwister).',
// Externe Tiere (nur als Vorfahre erfasst): Würfe & Charakter werden
// ausgeblendet, da das Tier nie im eigenen Bestand war.
nonResidentNote:
'Externes Tier — nur als Vorfahre erfasst. Würfe und Charakter werden nicht angezeigt, da es nie im eigenen Bestand war.',
},
// Formular (anlegen/bearbeiten)
form: {
createTitle: 'Neue Rennmaus anlegen',
editTitle: 'Rennmaus bearbeiten',
none: '— keine Angabe —',
// Herkunft-Standardoption: eigene Zucht (leere Herkunft = selbst gezüchtet).
ownBreeding: 'Eigene Zucht',
genotypeHint:
'Optional. Format z. B. „Aa CC Dd EE GG Pp Spsp rere“. Unbekannte Allele als „-“.',
// BESTAND-FILTER: Zugehörigkeit zum eigenen Bestand (sonst externe Ahne)
isResidentLabel: 'Gehört zum eigenen Bestand',
isResidentHint: 'Abwählen für externe Ahnen, die nur für den Stammbaum erfasst sind.',
isDeafUnknown: 'Unbekannt',
isDeafYes: 'Ja',
isDeafNo: 'Nein',
isScheckeLabel: 'Ist eine Schecke',
colorSectionTitle: 'Farbe & Genetik',
// STATUS-MODEL: Hinweis für abgeleitete Statuswerte
statusDerivedHint: {
Deceased: 'Wird automatisch gesetzt wenn Todesdatum erfasst.',
GivenAway: 'Wird automatisch gesetzt nach Abgabe.',
},
save: 'Speichern',
cancel: 'Abbrechen',
saving: 'Speichern …',
},
// Validierungsmeldungen
validation: {
nameRequired: 'Bitte einen Namen eingeben.',
genderRequired: 'Bitte ein Geschlecht auswählen.',
genotypeInvalid: 'Der Genotyp ist ungültig.',
dateOfDeathBeforeBirth: 'Das Todesdatum darf nicht vor dem Geburtsdatum liegen.',
},
// Aufzählungen
genderLabels: {
unknown: 'Unbekannt',
male: 'Männlich',
female: 'Weiblich',
},
// STATUS-MODEL: Breeding/Pet ersetzen Active; Deceased+GivenAway = abgeleitet (Backend)
statusLabels: {
Breeding: 'Zucht',
Pet: 'Liebhaber',
Deceased: 'Verstorben',
GivenAway: 'Abgegeben',
ForSale: 'Zur Abgabe',
},
spottingTypes: {
none: '— keine Scheckungsart —',
Punktschecke: 'Punktschecke',
Kragenschecke: 'Kragenschecke',
Ansatzschecke: 'Ansatzschecke',
Starkschecke: 'Starkschecke',
Superschecke: 'Superschecke',
'DP (Dark Patch)': 'DP (Dark Patch)',
WP: 'Minimalschecke (WP)',
wp: 'WP',
},
},
// ── FEAT-3 (Kevin): Zucht — Würfe + Zuchtpaare ──
litters: {
title: 'Würfe',
tabs: {
litters: 'Würfe',
pairs: 'Zuchtpaare',
},
// Liste
newButton: 'Neuer Wurf',
empty: 'Keine Würfe gefunden.',
countLabel: 'Würfe',
searchPlaceholder: 'Wurf suchen …',
filterYear: 'Jahr',
allYears: 'Alle Jahre',
sort: {
dateDesc: 'Wurfdatum (neueste)',
dateAsc: 'Wurfdatum (älteste)',
},
// Felder
fields: {
name: 'Bezeichnung',
date: 'Wurfdatum',
father: 'Vater',
mother: 'Mutter',
totalBorn: 'Wurfstärke',
deathsWithin8Weeks: 'In den ersten 8 Wochen verstorben',
expectedGoHomeDate: 'Voraussichtliches Abgabedatum',
notes: 'Notizen',
},
// Detail / Arbeitsbereich
detail: {
parents: 'Elterntiere',
registered: 'Erfasste Jungtiere',
juveniles: 'Jungtiere',
registerJuvenile: 'Jungtier erfassen',
expectedColors: 'Erwartete Farbschläge dieser Verpaarung',
needParentsGenotype:
'Für die Farbvorhersage müssen bei Vater und Mutter Genotypen hinterlegt sein.',
noJuveniles: 'Noch keine Jungtiere erfasst.',
unknownParent: 'Unbekannt',
edit: 'Bearbeiten',
back: 'Zurück zur Liste',
notFound: 'Dieser Wurf wurde nicht gefunden.',
// LITTER-JUVENILE-DETAILS: pro-Jungtier-Felder
juvenileFields: {
colorVariety: 'Farbschlag',
goHomeDate: 'Abgegeben',
receiver: 'Abnehmer',
dateOfDeath: 'Verstorben',
causeOfDeath: 'Todesursache',
},
},
// Formular
form: {
createTitle: 'Neuen Wurf anlegen',
editTitle: 'Wurf bearbeiten',
none: '— keine Angabe —',
goHomeHint: 'Vorschlag: 35 Tage nach dem Wurfdatum. Anpassbar.',
save: 'Speichern',
cancel: 'Abbrechen',
saving: 'Speichern …',
},
validation: {
nameRequired: 'Bitte eine Bezeichnung eingeben.',
dateRequired: 'Bitte ein Wurfdatum angeben.',
invalidParentGender: 'Der Vater muss männlich und die Mutter weiblich sein.',
deathsExceedTotalBorn: 'Die Anzahl der Frühverluste darf die Wurfstärke nicht überschreiten.',
},
// Zuchtpaar-Übersicht
pairs: {
title: 'Zuchtpaare',
empty: 'Noch keine Zuchtpaare — diese ergeben sich aus den erfassten Würfen.',
litterCount: 'Würfe',
lastLitter: 'Letzter Wurf',
testMating: 'Probeverpaarung',
},
},
breeders: {
title: 'Züchter',
comingSoon: 'Die Züchter-Verwaltung entsteht gerade. Bald kannst du hier Züchter erfassen.',
},
farbkatalog: {
title: 'Farbkatalog',
subtitle: 'Übersicht aller {count} registrierten Farbschläge und deren genetischen Formeln.',
searchPlaceholder: 'Nach Name, englischem Begriff oder Genen suchen (z. B. \'Zobel\', \'dd\', \'ee\', \'pp\')...',
empty: 'Keine Farbschläge gefunden, die Ihrer Suche entsprechen.',
},
notFound: {
title: 'Seite nicht gefunden',
message: 'Die angeforderte Seite existiert nicht.',
backHome: 'Zur Startseite',
},
// ── FEAT-5 (Kevin): Genetik / Probeverpaarung ──
genetik: {
title: 'Genetik',
subtitle: 'Probeverpaarung Farbschläge der Nachkommen vorhersagen',
father: 'Vater',
mother: 'Mutter',
pickAnimal: 'Tier auswählen',
pickAnimalSearch: 'Name suchen …',
pickAnimalNone: 'Keine passenden Tiere gefunden.',
pickAnimalNoGenotype: 'Für dieses Tier ist kein Genotyp hinterlegt bitte unten eingeben.',
clearAnimal: 'Auswahl entfernen',
genotypeLabel: 'Genotyp',
genotypeHint: 'Format z. B. „Aa CC Dd EE GG Pp Spsp rere“. Unbekannte Allele als „-“.',
genotypeInvalid: 'Der Genotyp ist ungültig.',
genotypePreview: 'Farbschlag',
run: 'Probeverpaarung berechnen',
needBoth: 'Bitte für Vater und Mutter einen gültigen Genotyp angeben.',
resultsTitle: 'Mögliche Nachkommen',
byFarbschlag: 'Nach Farbschlag',
byGenotype: 'Nach Genotyp',
showGenotypes: 'Genotypen anzeigen',
hideGenotypes: 'Genotypen ausblenden',
probability: 'Wahrscheinlichkeit',
noOffspring: 'Keine lebend geborenen Nachkommen möglich.',
warningsTitle: 'Hinweise',
},
// ── FEAT-12a (Kevin): Abgabe (For-Sale / Inserate) ──
abgabe: {
title: 'Abgabe',
subtitle: 'Abgabetiere gruppieren und Inserate erstellen',
empty: 'Keine Tiere zur Abgabe. Stelle Tiere über „Zur Abgabe stellen“ ein.',
markAction: 'Zur Abgabe stellen',
markMultiAction: 'Ausgewählte zur Abgabe stellen',
grouping: {
title: 'Gruppen',
byEnclosure: 'Nach Gehege vorgeschlagen',
ungrouped: 'Ohne Gehege',
moveTo: 'Verschieben nach',
newGroup: 'Neue Gruppe',
groupLabel: 'Gruppe',
},
// Inserat-Komposer (Vorlage der Züchterin)
listing: {
headingFor: (n: number, gender: string) => `Gruppe ${n} (${gender})`,
genderMale: 'männlich',
genderFemale: 'weiblich',
genderMixed: 'gemischt',
status: 'Status',
statusFree: 'FREI',
statusLooseReserved: 'LOCKER RESERVIERT',
statusReserved: 'RESERVIERT',
reservedName: 'Name (bei Reservierung)',
tagline: 'Überschrift (emotionaler Einzeiler)',
taglinePlaceholder: 'z. B. „Großer und kleiner Bruder“ Männliches Rennmaus-Duo sucht ein Zuhause',
bornOn: 'geboren am',
personality: 'Charakter',
personalityPlaceholder: 'Ein paar Sätze zum Charakter des Tieres …',
photos: 'Fotos',
noPhotos: 'Für dieses Tier sind keine Fotos hinterlegt.',
},
// Export / Paste-Paket
export: {
copyText: 'Text kopieren',
copied: 'Text in die Zwischenablage kopiert.',
copyFailed: 'Kopieren fehlgeschlagen.',
downloadPhotos: 'Fotos herunterladen',
zipping: 'Fotos werden gepackt …',
noPhotosSelected: 'Keine Fotos ausgewählt.',
zipFailed: 'Fotos konnten nicht gepackt werden.',
finish: 'Abgabe abschließen',
finishHint: 'Vertrag erstellen (folgt in einem späteren Schritt).',
},
// KI-Assistent (Backend folgt mit API-Schlüssel)
ai: {
improve: 'Text mit KI verbessern',
generating: 'KI erstellt den Text …',
hintsLabel: 'Hinweise für die KI (optional)',
notConfigured: 'KI-Funktion: API-Schlüssel noch nicht konfiguriert.',
},
},
// ── ABGABE-STATUS: Reservierungs-/Abgabe-Status (verfügbar → reserviert → abgegeben) ──
reservierungen: {
title: 'Reservierungen',
subtitle: 'Reservierungs- und Abgabe-Status der Abgabetiere verwalten.',
loadError: 'Reservierungen konnten nicht geladen werden.',
empty: 'Noch keine Reservierungen erfasst.',
newButton: 'Neue Reservierung',
// Status-Werte (Anzeige).
status: {
verfuegbar: 'Verfügbar',
reserviert: 'Reserviert',
abgegeben: 'Abgegeben',
},
// Filter-Chips nach Status.
filters: {
all: 'Alle',
verfuegbar: 'Verfügbar',
reserviert: 'Reserviert',
abgegeben: 'Abgegeben',
},
// Spalten / Feld-Beschriftungen.
fields: {
animal: 'Tier',
status: 'Status',
reservedFor: 'Reserviert für',
appointment: 'Termin',
price: 'Preis',
note: 'Notiz',
handedOver: 'Abgegeben am',
none: '—',
},
// Formular (Anlegen / Bearbeiten).
form: {
addTitle: 'Reservierung anlegen',
editTitle: 'Reservierung bearbeiten',
animal: 'Tier',
animalPlaceholder: 'Tier auswählen …',
status: 'Status',
reservedFor: 'Reserviert für (Kontakt)',
contactNone: '— niemand —',
appointment: 'Termin',
price: 'Preis (€)',
note: 'Notiz',
handedOver: 'Abgegeben am',
save: 'Speichern',
cancel: 'Abbrechen',
saveError: 'Speichern fehlgeschlagen.',
chooseAnimal: 'Bitte ein Tier auswählen.',
},
// Aktionen pro Zeile.
actions: {
edit: 'Bearbeiten',
delete: 'Löschen',
markReserved: 'Reservieren',
markHandedOver: 'Als abgegeben markieren',
markAvailable: 'Wieder freigeben',
confirmDelete: 'Diese Reservierung wirklich löschen?',
deleteError: 'Löschen fehlgeschlagen.',
},
// Hinweis: Status ≠ Vertrag.
contractHint:
'Hinweis: Der Status ist eine Vormerkung. Die rechtliche Abgabe erfolgt weiterhin über einen Vertrag.',
},
// ── FEAT-2 (Oscar): Gehege (Enclosures) — GEHEGE-RENAME: Becken → Gehege ──
becken: {
title: 'Gehege',
newButton: 'Neues Gehege',
empty: 'Keine Gehege gefunden.',
countLabel: 'Gehege',
searchPlaceholder: 'Name suchen …',
fields: {
name: 'Name',
notes: 'Notizen',
// Reinigungszyklus (RennmausPro becken_tb).
size: 'Maße',
capacity: 'Empf. Tieranzahl',
lastCleanedDate: 'Zuletzt gereinigt',
cleaningCycleDays: 'Reinigungszyklus (Tage)',
nextCleaningDate: 'Nächste Reinigung',
},
// Reinigungszyklus: Hinweise + Aktion auf der Detailseite.
cleaning: {
title: 'Reinigung',
due: 'Reinigung fällig',
dueSince: (date: string) => `Reinigung fällig (seit ${date})`,
nextOn: (date: string) => `Nächste Reinigung am ${date}`,
noCycle: 'Kein Reinigungszyklus hinterlegt.',
neverCleaned: 'Noch nie als gereinigt vermerkt.',
markCleaned: 'Als gereinigt markieren',
marking: 'Wird gespeichert …',
marked: 'Reinigung vermerkt.',
capacityUnit: (n: number) => `${n} ${n === 1 ? 'Tier' : 'Tiere'}`,
cycleUnit: (n: number) => `alle ${n} Tage`,
},
// Bilder-Sektion auf der Gehege-Detailseite.
photosTitle: 'Bilder',
occupancy: {
title: 'Bewohner',
empty: 'Dieses Gehege ist derzeit leer.',
countOne: 'Tier',
countMany: 'Tiere',
},
detail: {
edit: 'Bearbeiten',
back: 'Zurück zur Liste',
notFound: 'Dieses Gehege wurde nicht gefunden.',
},
form: {
createTitle: 'Neues Gehege anlegen',
editTitle: 'Gehege bearbeiten',
save: 'Speichern',
cancel: 'Abbrechen',
saving: 'Speichern …',
},
validation: {
nameRequired: 'Bitte einen Namen eingeben.',
},
delete: {
action: 'Löschen',
confirmMessage: 'Soll dieses Gehege wirklich gelöscht werden?',
conflict:
'Gehege ist nicht leer — bitte zuerst alle Tiere in ein anderes Gehege umsetzen.',
},
},
// ── FEAT-4 (Kelly): Stammbaum (Ahnentafel) ──
stammbaum: {
title: 'Stammbaum',
/** Überschrift mit Tiername. */
titleFor: (name: string) => `Stammbaum von ${name}`,
/** Button auf der Tier-Detailseite (Integration durch FEAT-1). */
openButton: 'Stammbaum',
backToAnimal: 'Zur Tierakte',
notFound: 'Diese Rennmaus wurde nicht gefunden.',
unknown: 'unbekannt',
/** Auf Karten am Rand: weitere Vorfahren nachladen. */
expand: 'Vorfahren laden',
tapHint: 'Tippe auf ein Tier, um dessen Stammbaum anzuzeigen.',
/** Mini-Legende unter dem Baum (STAMMBAUM-EXPAND). */
hintName: 'Namenslink: Tierakte öffnen',
hintExpand: ': weitere Vorfahren nachladen',
hintContext: 'Rechtsklick (oder Karte lange gedrückt halten): ID kopieren / Fehler melden',
hintSiblings: '⟲: Eltern sind Geschwister — gemeinsame Vorfahren siehe Vaterlinie',
/** Verweis-Knoten bei Geschwister-Verpaarung (Vater & Mutter aus demselben Wurf). */
siblingPairing: {
refLabel: (name: string) => `Geschwister von ${name}`,
refHint: 'Eltern siehe oben',
},
/** Würfe-Panel links (STAMMBAUM-LITTERS). */
littersTitle: 'Würfe',
littersJunge: 'Junge',
zoomIn: 'Vergrößern',
zoomOut: 'Verkleinern',
zoomFit: 'Ansicht einpassen',
print: 'Drucken / PDF',
inbreeding: {
label: 'Inzuchtkoeffizient',
unavailable: 'wird berechnet …',
},
printView: {
/** Spaltenüberschriften der Ahnentafel, Index = Generation. */
generations: ['Tier', 'Eltern', 'Großeltern', 'Urgroßeltern', 'Ur-Urgroßeltern'],
createdOn: 'Erstellt am',
born: 'geb.',
},
/** FEEDBACK: Rechtsklick-Kontextmenü auf einer Stammbaum-Karte. */
contextMenu: {
copyId: 'ID kopieren',
reportError: 'Fehler melden',
},
},
// ── FEAT-7 (Kelly): Statistik & Berichte ──
statistik: {
title: 'Statistik & Berichte',
empty:
'Noch keine Daten — lege zuerst Tiere und Würfe an oder importiere deinen Bestand.',
sectionEmpty: 'Noch keine Daten für diese Auswertung.',
littersPerYear: 'Würfe pro Jahr',
avgLitterSize: 'Durchschnittliche Wurfstärke pro Jahr',
avgLitterSizeHint: 'Nur Würfe mit erfasster Wurfstärke.',
farbschlag: 'Farbschlag-Verteilung',
farbschlagHint: 'Nur aktive Tiere.',
withoutFarbschlag: 'ohne Farbschlag',
population: 'Bestandsentwicklung',
populationHint:
'Lebende, nicht abgegebene Tiere im Zeitverlauf. Tiere ohne Geburtsdatum sind nicht enthalten.',
populationUnit: 'Tiere',
losses: 'Verluste pro Jahr',
lossesHint: 'Verstorbene Tiere nach Todesjahr.',
},
// ── FEAT-13 (Kelly): Abgabeverträge ──
vertraege: {
title: 'Abgabeverträge',
newButton: 'Neuer Vertrag',
empty: 'Noch keine Verträge — erstelle den ersten über „Neuer Vertrag“ oder den Abgabe-Bereich.',
countText: (n: number) => (n === 1 ? '1 Vertrag' : `${n} Verträge`),
download: 'Word',
downloadPdf: 'PDF',
noWordFileShort: 'Keine Word-Datei',
noWordFile:
'Für importierte Verträge liegt keine Word-Datei vor — das PDF wird aus den Daten erzeugt.',
delete: 'Löschen',
confirmDelete:
'Vertrag wirklich löschen? Die Word-Datei wird mit entfernt; der Status der Tiere bleibt unverändert.',
animalsCount: (n: number) => (n === 1 ? '1 Tier' : `${n} Tiere`),
fields: {
contact: 'Abnehmer',
animals: 'Tiere',
price: 'Kaufpreis',
handoverDate: 'Übergabedatum',
contractDate: 'Vertragsdatum',
createdAt: 'Erstellt',
},
// Assistent (/vertraege/neu)
wizard: {
title: 'Abgabe abschließen',
steps: ['Abnehmer', 'Tiere', 'Preis & Datum', 'Vertrag'],
back: 'Zurück',
next: 'Weiter',
cancel: 'Abbrechen',
// Schritt 1
pickContact: 'Abnehmer auswählen',
searchContact: 'Name suchen …',
noContacts: 'Keine Kontakte gefunden.',
orCreateNew: 'Oder neuen Kontakt anlegen',
createContact: 'Kontakt anlegen und auswählen',
contactNameRequired: 'Bitte einen Namen für den Kontakt eingeben.',
// Schritt 2
pickAnimals: 'Tiere bestätigen',
pickAnimalsHint: 'Nur lebende, nicht abgegebene Tiere werden angezeigt.',
noAnimals: 'Keine abgebbaren Tiere gefunden.',
animalsRequired: 'Bitte mindestens ein Tier auswählen.',
photoLabel: 'Foto für den Vertrag',
photoNone: 'Kein Foto',
// Schritt 3
priceLabel: 'Kaufpreis (€)',
pricePlaceholder: 'z. B. 72,00',
priceInvalid: 'Bitte einen gültigen Preis eingeben (z. B. 72,00).',
handoverLabel: 'Übergabedatum',
contractDateLabel: 'Vertragsdatum (optional, Standard = Übergabedatum)',
// Schritt 4
summaryTitle: 'Zusammenfassung',
profileIncomplete:
'Das Zuchtprofil ist unvollständig — Name, Adresse und Ort erscheinen im Vertrag. Jetzt unter Einstellungen ergänzen?',
profileLink: 'Zu den Einstellungen',
generate: 'Vertrag erzeugen',
generating: 'Vertrag wird erzeugt …',
successTitle: 'Vertrag erstellt!',
successText:
'Die Tiere wurden als „Abgegeben“ markiert (Abnehmer und Abgabedatum gesetzt).',
downloadDocx: 'Vertrag herunterladen (.docx)',
toList: 'Zur Vertragsliste',
anotherOne: 'Weiteren Vertrag erstellen',
},
},
// ── FEAT-13 (Kelly): Einstellungen (Zuchtprofil) ──
einstellungen: {
title: 'Einstellungen',
zuchtprofil: {
title: 'Zuchtprofil',
intro:
'Diese Angaben erscheinen als Verkäufer-Block in jedem Abgabevertrag.',
incompleteHint:
'Noch unvollständig: Name, Adresse und Ort werden für den Vertrag benötigt.',
fields: {
zuchtName: 'Zuchtname',
nameSuffix: 'Namens-Anhängsel der Zucht',
nameSuffixHint:
'Wird wie ein „Nachname" an eigene Tiere angehängt, z. B. „von den kleinen Chaoten“ → „Danako von den kleinen Chaoten“.',
name: 'Vor- und Nachname',
nameHint: 'Mit Anrede, z. B. „Frau Erika Muster“.',
address: 'Adresse',
addressHint: 'Straße Nr, PLZ Ort.',
phone: 'Telefon',
email: 'E-Mail',
homepage: 'Homepage',
city: 'Ort (Unterschriftszeile)',
},
save: 'Speichern',
saving: 'Speichern …',
saved: 'Gespeichert.',
},
},
// ── INBOX-1 (Kelly): Anfragen-Posteingang ──
anfragen: {
title: 'Anfragen',
empty: 'Keine Anfragen — hole neue E-Mails mit „Anfragen abrufen“.',
emptyFiltered: 'Keine Anfragen mit diesem Status.',
countText: (n: number) => (n === 1 ? '1 Anfrage' : `${n} Anfragen`),
sync: 'Anfragen abrufen',
syncing: 'Abrufen …',
syncImported: (n: number) =>
n === 0 ? 'Keine neuen Anfragen.' : n === 1 ? '1 neue Anfrage abgerufen.' : `${n} neue Anfragen abgerufen.`,
mailNotConfigured:
'Gmail ist noch nicht eingerichtet — Adresse und App-Passwort folgen in den Einstellungen.',
mailAuthFailed:
'Gmail-Anmeldung fehlgeschlagen — bitte das App-Passwort neu eintragen.',
filterAll: 'Alle',
statusLabels: {
New: 'Neu',
InProgress: 'In Bearbeitung',
Assigned: 'Zugeordnet',
Answered: 'Beantwortet',
Abandoned: 'Verworfen',
},
// Detailansicht
detail: {
back: 'Zurück zur Liste',
notFound: 'Diese Anfrage wurde nicht gefunden.',
from: 'Von',
receivedAt: 'Eingegangen',
answeredAt: 'Beantwortet am',
message: 'Nachricht',
noBody: '(kein Text)',
noSubject: '(kein Betreff)',
// Triage
triage: 'Bearbeitung',
statusLabel: 'Status',
abandon: 'Verwerfen',
abandonConfirm: 'Anfrage wirklich verwerfen?',
assignContact: 'Abnehmer zuordnen',
assignNone: '— kein Abnehmer —',
assignedTo: 'Zugeordneter Abnehmer',
// Antwort
reply: 'Antwort',
replyPlaceholder: 'Antwort schreiben oder mit KI entwerfen …',
draftButton: 'Antwort entwerfen',
drafting: 'Entwurf wird erstellt …',
draftHint: 'Die KI erstellt nur einen Entwurf — gesendet wird erst nach deiner Bestätigung.',
aiKeyMissing: 'KI-Schlüssel fehlt — der Entwurfs-Assistent wird mit dem Schlüssel aktiviert.',
aiUpstreamError: 'Der KI-Dienst hat gerade ein Problem — bitte später erneut versuchen.',
send: 'Antwort senden',
sending: 'Senden …',
sendConfirm: 'Antwort jetzt per E-Mail senden?',
sendEmptyBody: 'Bitte zuerst eine Antwort schreiben.',
sent: 'Antwort gesendet — die Anfrage ist als „Beantwortet“ markiert.',
},
},
// ── FEAT-2 (Oscar): Kontakte (Contacts — Herkunft/Abnehmer) ──
kontakte: {
title: 'Kontakte',
newButton: 'Neuer Kontakt',
empty: 'Keine Kontakte gefunden.',
countLabel: 'Kontakte',
searchPlaceholder: 'Name suchen …',
// Quick-Chip-Filter nach Rolle (Züchter / Abnehmer).
filters: {
role: 'Rolle',
breeder: 'Züchter',
receiver: 'Abnehmer',
},
// FEAT-13: contactInfo (Freitext) wurde durch strukturierte Felder ersetzt
// (DATA-2-Schema: email/phone/address) — gebraucht für den Käufer-Block der Verträge.
fields: {
name: 'Name',
email: 'E-Mail',
phone: 'Telefon',
address: 'Adresse',
notes: 'Notizen',
isBreeder: 'Ist Züchter (Zucht)',
isReceiver: 'Ist Abnehmer (Käufer)',
nameSuffix: 'Namens-Anhängsel der Zucht',
nameSuffixHint:
'Wird an Tiere aus dieser Zucht angehängt, z. B. „von den Wüstenwinden“.',
},
linked: {
title: 'Verknüpfte Tiere',
empty: 'Diesem Kontakt sind keine Tiere zugeordnet.',
originRole: 'Herkunft von',
receiverRole: 'Abnehmer von',
},
detail: {
edit: 'Bearbeiten',
back: 'Zurück zur Liste',
notFound: 'Dieser Kontakt wurde nicht gefunden.',
},
form: {
createTitle: 'Neuen Kontakt anlegen',
editTitle: 'Kontakt bearbeiten',
addressHint: 'Straße Nr, PLZ Ort — so erscheint sie im Abgabevertrag.',
save: 'Speichern',
cancel: 'Abbrechen',
saving: 'Speichern …',
},
validation: {
nameRequired: 'Bitte einen Namen eingeben.',
},
delete: {
action: 'Löschen',
confirmMessage: 'Soll dieser Kontakt wirklich gelöscht werden?',
conflict:
'Kontakt ist noch mit Tieren verknüpft (Herkunft/Abnehmer) und kann nicht gelöscht werden.',
},
},
// ── FEAT-6 (Oscar): Tier-Detail-Tabs (Gesundheit / Gewicht / Fotos) ──
tierTabs: {
actions: {
save: 'Speichern',
saving: 'Speichern …',
cancel: 'Abbrechen',
edit: 'Bearbeiten',
delete: 'Löschen',
},
health: {
empty: 'Noch keine Gesundheitseinträge.',
newButton: 'Neuer Eintrag',
createTitle: 'Neuer Gesundheitseintrag',
editTitle: 'Gesundheitseintrag bearbeiten',
fields: {
date: 'Datum',
type: 'Art',
description: 'Beschreibung',
veterinarian: 'Tierarzt',
},
typeLabels: {
Examination: 'Untersuchung',
Treatment: 'Behandlung',
Injury: 'Verletzung',
Vaccination: 'Impfung',
Other: 'Sonstiges',
},
validation: {
dateRequired: 'Bitte ein Datum angeben.',
descriptionRequired: 'Bitte eine Beschreibung eingeben.',
},
deleteConfirm: 'Diesen Gesundheitseintrag wirklich löschen?',
},
weight: {
addTitle: 'Gewicht erfassen',
fields: {
date: 'Datum',
weightGrams: 'Gewicht (g)',
},
addButton: 'Hinzufügen',
adding: 'Speichern …',
historyTitle: 'Verlauf',
chartTitle: 'Gewichtsverlauf',
chartNeedsTwo: 'Für die Verlaufskurve sind mindestens zwei Einträge nötig.',
empty: 'Noch keine Gewichtseinträge.',
gramsSuffix: 'g',
validation: {
dateRequired: 'Bitte ein Datum angeben.',
weightRequired: 'Bitte ein Gewicht in Gramm eingeben.',
weightRange: 'Bitte ein plausibles Gewicht zwischen 1 und 500 g eingeben.',
},
deleteConfirm: 'Diesen Gewichtseintrag wirklich löschen?',
},
photos: {
empty: 'Noch keine Fotos.',
uploadTitle: 'Foto hochladen',
chooseFile: 'Foto auswählen',
captionLabel: 'Bildunterschrift (optional)',
uploadButton: 'Hochladen',
uploading: 'Hochladen …',
profileBadge: 'Profilfoto',
deleteConfirm: 'Dieses Foto wirklich löschen?',
validation: {
fileRequired: 'Bitte zuerst ein Foto auswählen.',
},
},
// ERWERB: Erwerb/Kauf je Tier (Kaufdatum, Preis, Notiz) — eigene Sektion in der Akte.
acquisition: {
sectionTitle: 'Erwerb',
intro: 'Wann und zu welchem Preis dieses Tier erworben wurde.',
addTitle: 'Erwerb erfassen',
editTitle: 'Erwerb bearbeiten',
fields: {
date: 'Kaufdatum',
price: 'Preis (€)',
note: 'Notiz',
},
addButton: 'Hinzufügen',
saveButton: 'Speichern',
saving: 'Speichern …',
cancel: 'Abbrechen',
edit: 'Bearbeiten',
delete: 'Löschen',
empty: 'Noch keine Erwerbsdaten erfasst.',
noDate: 'Ohne Datum',
noPrice: '—',
deleteConfirm: 'Diesen Erwerbseintrag wirklich löschen?',
validation: {
empty: 'Bitte mindestens Kaufdatum, Preis oder Notiz angeben.',
priceRange: 'Bitte einen plausiblen Preis (0 bis 9999 €) angeben.',
},
},
// ── Ausstellungen/Auszeichnungen je Tier (RennmausPro ausz_tb) ──
exhibitions: {
empty: 'Noch keine Ausstellungsergebnisse erfasst.',
newButton: 'Neues Ergebnis',
createTitle: 'Neues Ausstellungsergebnis',
editTitle: 'Ausstellungsergebnis bearbeiten',
fields: {
eventName: 'Veranstaltung',
date: 'Datum',
placement: 'Platzierung',
award: 'Auszeichnung',
note: 'Notiz',
},
placeholders: {
eventName: 'z. B. Nationale Rennmausschau 2026',
placement: 'z. B. 1. Platz',
award: 'z. B. Best in Show',
},
validation: {
eventNameRequired: 'Bitte eine Veranstaltung angeben.',
},
deleteConfirm: 'Dieses Ausstellungsergebnis wirklich löschen?',
},
},
// ── EXPORT-1 (Oscar): Datenexport (Karte auf /einstellungen) ──
datenexport: {
title: 'Datenexport',
intro:
'Sicherung deiner Daten — alle Tiere, Würfe und Kontakte als Tabellen (CSV für Excel) plus eine vollständige Datensicherung (JSON), gebündelt als Zip.',
button: 'Export herunterladen',
photoNote:
'Fotos sind nicht enthalten — sie liegen als Bilddateien im Datenordner der Anwendung und können von dort gesichert werden.',
},
// ── WEB-0b (Kevin): CMS-Verwaltung der öffentlichen Webseite ──
webseite: {
title: 'Webseite',
intro:
'Hier pflegst du die Inhalte deiner öffentlichen Webseite. Änderungen werden erst beim Veröffentlichen online sichtbar.',
empty: 'Es sind noch keine Seiten angelegt.',
statusLabel: 'Status',
statusDraft: 'Entwurf',
statusPublished: 'Veröffentlicht',
edit: 'Bearbeiten',
back: 'Zurück zur Übersicht',
// ── WEB-3 (Kelly): lokale Vorschau ──
vorschau: {
button: 'Vorschau',
title: 'Vorschau der Webseite',
intro:
'So sieht deine Webseite nach dem Veröffentlichen aus. Entwürfe erscheinen hier noch nicht.',
pageSelect: 'Seite',
reload: 'Neu laden',
viewPhone: 'Smartphone',
viewDesktop: 'Desktop',
frameTitle: 'Vorschau der öffentlichen Webseite',
empty:
'Noch keine veröffentlichte Seite — stelle eine Seite auf „Veröffentlicht“, um die Vorschau zu sehen.',
draftHint: 'Entwurf — erscheint noch nicht in der Vorschau.',
openPage: 'Ansehen',
},
// Seiten-Editor (Kopf)
editor: {
pageTitleLabel: 'Seitentitel',
seoLabel: 'Beschreibung für Suchmaschinen (SEO)',
seoHint: 'Kurzer Text (ca. 12 Sätze), der bei Google unter dem Titel erscheint.',
save: 'Seite speichern',
saved: 'Seite gespeichert.',
},
// Block-Editor
blocks: {
sectionTitle: 'Inhaltsblöcke',
empty: 'Diese Seite hat noch keine Inhaltsblöcke. Füge unten den ersten hinzu.',
addLabel: 'Block hinzufügen:',
moveUp: 'Nach oben',
moveDown: 'Nach unten',
delete: 'Block löschen',
confirmDelete: 'Diesen Block wirklich löschen?',
save: 'Block speichern',
saved: 'Gespeichert.',
// Block-Typ-Namen
types: {
Heading: 'Überschrift',
RichText: 'Textabschnitt',
Image: 'Bild',
Gallery: 'Bildergalerie',
ContactInfo: 'Kontaktangaben',
AbgabetiereList: 'Abgabetiere (automatisch)',
},
// Feld-Beschriftungen je Block-Typ
fields: {
headingText: 'Überschrift-Text',
headingLevel: 'Größe',
levelMain: 'Hauptüberschrift',
levelSub: 'Unterüberschrift',
markdown: 'Text',
markdownHint:
'Einfache Formatierung möglich: **fett**, *kursiv*, Listen mit „- “, Links als [Text](https://…).',
imageUrl: 'Bild-Adresse (URL)',
imageAlt: 'Bildbeschreibung (für Suchmaschinen & Barrierefreiheit)',
galleryImages: 'Bilder',
galleryAdd: 'Bild hinzufügen',
galleryRemove: 'Entfernen',
contactName: 'Name',
contactEmail: 'E-Mail',
contactPhone: 'Telefon',
contactAddress: 'Adresse',
abgabeIntro: 'Einleitungstext',
abgabeAutoNote:
'Die Liste der Abgabetiere wird beim Veröffentlichen automatisch aus deinen aktuellen Abgabetieren erzeugt. Du kannst nur den Einleitungstext bearbeiten.',
},
},
},
// ── RPRO3: RennmausPro-III-Backup-Import (Rubrik unter „Hilfe") ──
rpro3Import: {
title: 'RennmausPro-Import',
subtitle:
'Daten aus deiner alten RennmausPro-III-Software übernehmen — Tiere, Würfe, Stammbäume, Kontakte und Genotypen.',
intro:
'Lade hier deine RennmausPro-Sicherungsdatei hoch (die Datei endet auf „.backup"). Optional kannst du zusätzlich das zugehörige Bilder-Archiv (endet auf „_bilder.zip") hochladen. Zuerst wird die Datei nur ausgewertet — es wird noch nichts gespeichert. Du siehst dann eine Übersicht und entscheidest selbst, ob du den Import durchführst.',
step1Title: '1. Dateien auswählen',
backupLabel: 'RennmausPro-Sicherung (.backup)',
backupHint: 'Pflicht. Die Datei aus deiner RennmausPro-III-Software.',
imagesLabel: 'Bilder-Archiv (_bilder.zip)',
imagesHint: 'Optional. Wird gebraucht, um die Tierfotos zuzuordnen.',
analyzeButton: 'Auswerten',
analyzing: 'Datei wird ausgewertet …',
noBackup: 'Bitte zuerst eine RennmausPro-Sicherung (.backup) auswählen.',
step2Title: '2. Auswertung',
overviewTitle: 'Was steckt in der Datei?',
counts: {
ownAnimals: 'Eigene Tiere',
externalAfterDedup: 'Externe Ahnen (nach Bereinigung)',
externalRaw: 'Externe Ahnen (roh, vor Bereinigung)',
litters: 'Würfe',
contacts: 'Kontakte (Züchter & Abnehmer)',
genotypes: 'Hinterlegte Genotypen',
duplicatesMerged: 'Erkannte Dubletten (zusammengelegt)',
},
newVsExistingTitle: 'Abgleich mit deinem aktuellen Bestand',
newCount: (n: number) => `${n} Tiere wären neu`,
existingCount: (n: number) => `${n} Tiere sind vermutlich schon vorhanden`,
dedupExplain:
'RennmausPro hat beim Import vorhandene Tiere nicht erkannt — dadurch kommt dasselbe Tier oft mehrfach vor. Diese Dubletten werden automatisch anhand von Name, Geburtsdatum, Farbe und Herkunft zusammengelegt.',
topMergesTitle: 'Größte automatische Zusammenlegungen',
topMergesCol: { name: 'Tier', count: 'Datensätze', dob: 'Geburtsdatum', farbe: 'Farbe', origin: 'Herkunft' },
ambiguousTitle: 'Mehrdeutige Namen — bitte später prüfen',
ambiguousIntro:
'Bei diesen Namen gibt es mehrere unterschiedliche Tiere. Sie werden vorsichtshalber NICHT automatisch zusammengelegt, damit nichts falsch verknüpft wird. Du kannst sie nach dem Import in der Tierliste prüfen.',
ambiguousVariant: (count: number, dob: string, farbe: string, origin: string) =>
`${count}× · ${dob} · ${farbe} · ${origin}`,
ambiguousOwn: 'eigenes Tier',
ambiguousMore: (n: number) => `… und ${n} weitere mehrdeutige Namen.`,
photosNote: (n: number) => `Bilder-Archiv erkannt: ${n} Bilddateien werden den Tieren zugeordnet.`,
photosNoneNote: 'Kein Bilder-Archiv hochgeladen — Tiere werden ohne Fotos importiert.',
step3Title: '3. Import durchführen',
executeWarning:
'Beim Import werden die Tiere, Würfe, Kontakte und Genotypen aus RennmausPro übernommen. Ein erneuter Import aktualisiert dieselben Daten (es entstehen keine Dubletten). Deine manuell angelegten Tiere bleiben unberührt.',
executeButton: 'Import jetzt durchführen',
executing: 'Import läuft … das kann einen Moment dauern.',
successTitle: 'Import abgeschlossen',
resultCounts: {
gerbils: 'Tiere importiert',
litters: 'Würfe importiert',
contacts: 'Kontakte importiert',
health: 'Gesundheitseinträge',
weights: 'Gewichtseinträge',
photos: 'Fotos',
},
errorTitle: 'Es ist ein Fehler aufgetreten',
restart: 'Neue Datei auswählen',
},
// ── WAITLIST (RennmausPro nachfrage_tb): Warteliste/Nachfrage ──
warteliste: {
title: 'Warteliste',
subtitle: 'Interessenten warten auf bestimmte Tiere',
newButton: 'Neuer Eintrag',
empty: 'Keine Wartelisten-Einträge vorhanden.',
emptyOpen: 'Keine offenen Einträge.',
countLabel: 'Einträge',
onlyOpen: 'Nur offene',
loadError: 'Die Warteliste konnte nicht geladen werden.',
saveError: 'Der Eintrag konnte nicht gespeichert werden.',
deleteError: 'Der Eintrag konnte nicht gelöscht werden.',
deleteConfirm: 'Diesen Wartelisten-Eintrag wirklich löschen?',
// Status-Bezeichnungen (Backend-Werte: offen | erfuellt | storniert)
status: {
offen: 'Offen',
erfuellt: 'Erfüllt',
storniert: 'Storniert',
},
// Geschlechts-Wunsch
wishGender: {
any: 'Egal',
male: 'Männlich',
female: 'Weiblich',
},
fields: {
contact: 'Kontakt',
contactNone: '— kein Kontakt —',
contactName: 'Name (falls kein Kontakt)',
wishColor: 'Wunsch-Farbschlag',
wishColorAny: 'Egal',
wishGender: 'Wunsch-Geschlecht',
requestedAt: 'Angefragt am',
status: 'Status',
note: 'Notiz',
},
// Aktionen je Eintrag
edit: 'Bearbeiten',
delete: 'Löschen',
save: 'Speichern',
cancel: 'Abbrechen',
formTitleNew: 'Neuer Wartelisten-Eintrag',
formTitleEdit: 'Eintrag bearbeiten',
validationName: 'Bitte einen Kontakt wählen oder einen Namen eingeben.',
noContactLink: 'Kein Kontakt verknüpft',
},
// ── RÜCKNAHMEN: zurückgekommene/zurückgenommene Tiere (getback_tb) ──
ruecknahmen: {
title: 'Rücknahmen',
subtitle: 'Tiere, die zur Zucht zurückgekommen sind',
countText: (n: number) =>
n === 1 ? '1 Rücknahme erfasst' : `${n} Rücknahmen erfasst`,
empty: 'Noch keine Rücknahmen erfasst.',
newButton: 'Rücknahme erfassen',
// Formular
formTitle: 'Rücknahme erfassen',
editTitle: 'Rücknahme bearbeiten',
fields: {
gerbil: 'Tier',
gerbilName: 'Tiername',
gerbilNameHint: 'Falls das Tier nicht in der Liste steht, hier den Namen eintragen.',
returnDate: 'Rücknahmedatum',
returnPrice: 'Rücknahmepreis (€)',
originalPrice: 'Ursprünglicher Abgabepreis (€)',
originalSaleDate: 'Ursprüngliches Abgabedatum',
fromContact: 'Zurück von (Kontakt)',
fromContactName: 'Name (frei)',
fromContactNameHint: 'Falls der Kontakt nicht in der Liste steht, hier den Namen eintragen.',
note: 'Grund / Notiz',
notePlaceholder: 'Warum kam das Tier zurück?',
},
gerbilPlaceholder: '— Tier wählen —',
contactPlaceholder: '— Kontakt wählen —',
// Listen-Karte
returnedOn: 'zurück am',
from: 'von',
unknownAnimal: '(unbekanntes Tier)',
// Aktionen
save: 'Speichern',
saving: 'Wird gespeichert …',
edit: 'Bearbeiten',
cancel: 'Abbrechen',
delete: 'Löschen',
confirmDelete: 'Diese Rücknahme wirklich löschen?',
validationNoAnimal: 'Bitte ein Tier wählen oder einen Tiernamen eintragen.',
saveSuccess: 'Rücknahme gespeichert.',
saveError: 'Rücknahme konnte nicht gespeichert werden.',
},
},
// ── HELP-1: In-App-Anleitung ──
hilfe: {
title: 'Hilfe & Anleitung',
subtitle: 'Kurzanleitung für den Rennmaus-Manager',
sections: {
ersteSchritte: 'Erste Schritte',
tiere: 'Rennmäuse anlegen & Fotos',
becken: 'Gehege',
wuerfe: 'Würfe & Jungtiere',
genetik: 'Probeverpaarung & Genetik',
stammbaum: 'Stammbaum',
abgabe: 'Abgabe-Ablauf',
// FEAT-13-Followup (Kelly): Vertrag + Zuchtprofil
vertraege: 'Abgabevertrag erstellen',
einstellungen: 'Zuchtprofil (Einstellungen)',
statistik: 'Statistik',
datensicherung: 'Datensicherung',
rpro3Import: 'Daten aus RennmausPro übernehmen',
},
// Verweis auf die eigene RennmausPro-Import-Rubrik.
rpro3Link: {
text: 'Hast du früher mit der Software „RennmausPro III" gearbeitet? Du kannst deine alten Daten (Tiere, Würfe, Stammbäume, Kontakte) bequem übernehmen.',
button: 'Zum RennmausPro-Import',
},
},
api: {
errors: {
network: 'Verbindung zum Server fehlgeschlagen. Bitte später erneut versuchen.',
notFound: 'Der Eintrag wurde nicht gefunden.',
server: 'Auf dem Server ist ein Fehler aufgetreten.',
unknown: 'Ein unbekannter Fehler ist aufgetreten.',
},
},
// ── FEEDBACK: "Fehler melden" Dialog + "ID kopieren" Aktion ──
feedback: {
/** Button-Beschriftung (Tierakte, Wurf-Ansicht). */
button: 'Fehler melden',
dialogTitle: 'Fehler melden',
intro: 'Beschreibe kurz, was nicht stimmt. Technische Angaben werden automatisch mitgesendet.',
label: 'Beschreibung',
placeholder: 'Was funktioniert nicht oder ist falsch dargestellt?',
/** Überschrift über den automatisch erfassten Debug-Angaben. */
debugTitle: 'Automatisch erfasst',
debugFields: {
context: 'Ansicht',
entity: 'Datensatz',
url: 'Adresse',
},
contexts: {
stammbaum: 'Stammbaum',
'gerbil-detail': 'Rennmausakte',
'litter-detail': 'Wurf',
'contact-detail': 'Kontakt',
'rpro3-import': 'RennmausPro-Import',
},
submit: 'Senden',
submitting: 'Wird gesendet …',
cancel: 'Abbrechen',
close: 'Schließen',
success: 'Danke! Dein Fehlerbericht wurde gesendet.',
error: 'Fehlerbericht konnte nicht gesendet werden.',
emptyMessage: 'Bitte beschreibe den Fehler.',
/** Toast nach erfolgreichem "ID kopieren". */
idCopied: 'ID kopiert',
idCopyFailed: 'ID konnte nicht kopiert werden.',
/** "Meine Tickets" — Verwaltung der eingereichten Fehlerberichte. */
tickets: {
title: 'Meine Tickets',
subtitle: 'Deine eingereichten Fehlerberichte — bearbeite, schließe oder lösche sie hier.',
/** Link auf der Hilfe-Seite. */
link: 'Meine Tickets (Fehlerberichte)',
empty: 'Du hast noch keine Fehlerberichte gesendet.',
loadError: 'Tickets konnten nicht geladen werden.',
statusOpen: 'Offen',
statusResolved: 'Gelöst',
statusNeedsInfo: 'Rückfrage offen',
statusAnswered: 'Beantwortet',
/** Spalte/Label für die Ansicht, aus der der Bericht kam. */
contextLabel: 'Ansicht',
entityLabel: 'Datensatz',
createdLabel: 'Gesendet am',
resolvedLabel: 'Gelöst am',
markResolved: 'Als gelöst markieren',
reopen: 'Wieder öffnen',
edit: 'Bearbeiten',
save: 'Speichern',
cancel: 'Abbrechen',
saving: 'Wird gespeichert …',
delete: 'Löschen',
confirmDelete: 'Diesen Fehlerbericht wirklich löschen?',
editTitle: 'Fehlerbericht bearbeiten',
editLabel: 'Beschreibung',
saved: 'Änderung gespeichert.',
resolvedToast: 'Ticket als gelöst markiert.',
reopenedToast: 'Ticket wieder geöffnet.',
deletedToast: 'Ticket gelöscht.',
updateError: 'Ticket konnte nicht aktualisiert werden.',
deleteError: 'Ticket konnte nicht gelöscht werden.',
emptyMessage: 'Bitte beschreibe den Fehler.',
/** Rückfrage (Question) + Antwort der Züchterin (Answer). */
questionLabel: 'Rückfrage',
answerLabel: 'Deine Antwort',
answerPlaceholder: 'Antwort auf die Rückfrage eingeben …',
answerButton: 'Antworten',
/** Button auf einem beantworteten Ticket, um die eigene Antwort noch zu ändern. */
amendAnswer: 'Antwort ändern',
answering: 'Wird gesendet …',
answeredOn: 'Beantwortet am',
answeredToast: 'Antwort gesendet.',
emptyAnswer: 'Bitte gib eine Antwort ein.',
/** Gefilterte Verlinkungen (wie die Filter-Chips der Rennmaus-Liste). */
filters: {
/** Gruppe „Rückfragen": Tickets im Dialog (NeedsInfo + Answered). */
dialog: 'Rückfragen',
/** Gruppe „Offen": noch nicht bearbeitete Tickets. */
open: 'Offen',
/** Gruppe „Geschlossen": erledigte Tickets mit Changelog. */
closed: 'Geschlossen',
},
/** Leertext je gefilterter Ansicht. */
emptyDialog: 'Aktuell keine Tickets im Dialog.',
emptyOpen: 'Keine offenen Tickets.',
emptyClosed: 'Noch keine geschlossenen Tickets.',
/** Changelog (fixNote) auf geschlossenen Tickets. */
changelogLabel: 'Was wurde geändert',
/** Überschrift des Frage/Antwort-Verlaufs (frühere Runden). */
threadLabel: 'Bisheriger Verlauf',
/** Rollen-Beschriftungen im Verlauf. */
threadMaintainer: 'Rückfrage',
threadBreeder: 'Deine Antwort',
/** Tooltip am verlinkten Datensatz-Namen (Tier/Wurf/Kontakt). */
entityLinkTitle: 'Datensatz ansehen',
/** Link-Beschriftung für eine im Text referenzierte andere Ticket-Nummer. */
ticketRefLabel: 'verknüpftes Ticket ansehen',
},
},
/** NACHVERFOLGUNG: Datenherkunft eines importierten Tiers (Rennmausakte). */
provenance: {
/** Button-Beschriftung in den Akten-Aktionen. */
button: 'Datenherkunft',
dialogTitle: 'Nachverfolgungsinformationen',
intro: 'Woher stammen die Daten dieses Eintrags? Diese Angaben werden beim Import automatisch erfasst.',
/** Wie {@link intro}, aber mit Entitätsbezeichnung (z. B. „dieses Kontakts"). */
introFor: (label: string) =>
`Woher stammen die Daten ${label}? Diese Angaben werden beim Import automatisch erfasst.`,
/** Entitätsbezeichnungen für introFor (Genitiv). */
entityLabels: {
contact: 'dieses Kontakts',
litter: 'dieses Wurfs',
},
/** Überschrift des chronologischen, dateibezogenen Verlaufs (Primärinhalt). */
historyTitle: 'Verlauf',
/** Legende für die mit „⚠“ markierten Verlaufszeilen, in denen Daten aus
* einer Quelle verworfen wurden (mit Grund und verwendetem Ersatz). */
discardLegend: '⚠ markiert verworfene Quelldaten (mit Grund und verwendetem Ersatz).',
/** Überschriften / Feldbeschriftungen. */
sourceFilesTitle: 'Quelldateien',
sourceFilesCount: (n: number) => (n === 1 ? 'aus 1 Quelle' : `aus ${n} Quellen`),
mergedTitle: 'Datensätze',
mergedCount: (n: number) =>
n === 1 ? 'aus 1 Datensatz' : `zusammengeführt aus ${n} Datensätzen`,
fromWurfchronik: 'Enthält Angaben aus der Wurfchronik',
parentsTitle: 'Eltern-Herkunft',
parentMethodLabel: 'Methode',
parentConfidenceLabel: 'Konfidenz',
/** Übersetzungen für die technischen Methoden-/Konfidenz-Werte. */
methods: {
'chart-position': 'Position im Stammbaum',
decision: 'Manuelle Entscheidung',
} as Record<string, string>,
confidences: {
low: 'niedrig',
medium: 'mittel',
high: 'hoch',
} as Record<string, string>,
notesTitle: 'Hinweise',
/** Wenn ein Tier keine Importdaten hat (manuell angelegt). */
empty: 'Keine Herkunftsdaten vorhanden.',
close: 'Schließen',
},
common: {
loading: 'Lädt …',
retry: 'Erneut versuchen',
previous: 'Zurück',
next: 'Weiter',
page: 'Seite',
of: 'von',
yes: 'Ja',
no: 'Nein',
delete: 'Löschen',
confirmDelete: 'Wirklich löschen?',
pageNav: 'Seitennavigation',
// Toast-Rückmeldungen
saved: 'Gespeichert',
saveFailed: 'Speichern fehlgeschlagen',
deleted: 'Gelöscht',
},
// Genetik-Warnungen: der Engine (src/genetics) liefert nur CODES,
// die deutschen Texte stehen hier. Schlüssel = GeneticsWarningCode-Werte.
genetics: {
warnings: {
SCHECKE_LETHAL:
'Schecke × Schecke: Reinerbige Tiere (SpSp) sterben bereits im Mutterleib — etwa ein Viertel weniger Jungtiere.',
REX_SEMI_LETHAL:
'Rex × Rex: Reinerbige Tiere (ReRe) sind nur eingeschränkt lebensfähig.',
SLS_LETHAL:
'WP × WP: Reinerbige Tiere (S(l)S(l)) sterben bereits im Mutterleib (Rumpback) — weniger Jungtiere.',
SUPERSCHECKE_DEAF:
'Schecke × WP: Superschecken (sehr hoher Weißanteil) sind möglich — erhöhtes Taubheitsrisiko.',
},
unknownFarbschlag: 'Unbekannter Farbschlag',
},
// ── FEAT-14 / CHARAKTERBOGEN-2: Charakterbogen — Eigenschaften + Notiz, speist KI-Verkaufstext ──
// Traits: stabile KEYS (gespeichert, NIEMALS umbenennen) + deutsche LABELS (UI + KI-Prompt).
// Neue Traits = neuen Eintrag hinzufügen; warn:true = Warnsignal (visuell abgesetzt).
character: {
sectionTitle: 'Charakter & Eigenschaften',
noteLabel: 'Notizen zum Charakter',
notePlaceholder: 'Ein paar Sätze zum Charakter dieses Tieres …',
save: 'Charakter speichern',
saved: 'Charakter gespeichert.',
none: 'Noch keine Eigenschaften ausgewählt.',
warnLabel: '⚠ Warnsignal',
traitCategories: [
{
category: 'Sozialverhalten',
traits: [
{ key: 'dominant', label: 'dominant (Leittier)' },
{ key: 'rangniedrig', label: 'rangniedrig / unterwürfig' },
{ key: 'sozialkompetent', label: 'sozialkompetent / gut sozialisiert' },
{ key: 'schwer-vergesellschaftbar', label: 'schwer vergesellschaftbar', warn: true },
],
},
{
category: 'Eignung & Umgang',
traits: [
{ key: 'anfaengergeeignet', label: 'anfängergeeignet' },
{ key: 'erfahrene-halter', label: 'für erfahrene Halter' },
{ key: 'beobachtungstier', label: 'reines Beobachtungstier' },
{ key: 'familiengeeignet', label: 'familiengeeignet / stressresistent' },
],
},
{
category: 'Hobbys & Eigenarten',
traits: [
{ key: 'futterfreudig', label: 'futterfreudig' },
{ key: 'buddelt', label: 'buddelt gern' },
{ key: 'klettert', label: 'klettert gern' },
{ key: 'laufrad', label: 'läuft gern im Laufrad' },
{ key: 'schredder', label: 'Schredder-Meister' },
{ key: 'nestbauer', label: 'Nestbauer / Architekt' },
{ key: 'territorial', label: 'territorial', warn: true },
],
},
{
category: 'Wesen & Temperament',
traits: [
{ key: 'zutraulich', label: 'zutraulich' },
{ key: 'handzahm', label: 'handzahm' },
{ key: 'neugierig', label: 'neugierig' },
{ key: 'aufgeschlossen', label: 'aufgeschlossen' },
{ key: 'ruhig', label: 'ruhig / ausgeglichen' },
{ key: 'lebhaft', label: 'lebhaft / aktiv' },
{ key: 'verschmust', label: 'verschmust' },
{ key: 'eigenstaendig', label: 'eigenständig' },
{ key: 'vertraeglich', label: 'gut verträglich' },
{ key: 'schreckhaft', label: 'schreckhaft' },
],
},
],
},
// ── UX-MOBILE-1 (Kevin): FilterPanel — einklappbare Filter auf Mobil ──
filterPanel: {
toggleButton: 'Filter',
resetButton: 'Filter zurücksetzen',
closeButton: 'Schließen',
},
// ── DESIGN (Rennmaus Filter): Quick-Chips-Filter mit Bottom-Sheet ──
filterBar: {
title: 'Filter',
done: 'Fertig',
clearAll: 'Alle löschen',
remove: 'entfernen',
searchPlaceholder: 'Suchen …',
noMatch: 'Kein Treffer',
searchClear: 'Suche leeren',
},
// ── FEAT-NAMEGEN: Namensvorschläge (KI-gestützt, UC-1 Einzeltier) ──
namegen: {
button: 'Name vorschlagen',
panelTitle: 'Namensvorschläge',
letterLabel: 'Anfangsbuchstabe',
letterPlaceholder: 'z. B. A',
genderLabel: 'Geschlecht',
genderAny: 'Egal',
genderFemale: 'Weiblich',
genderMale: 'Männlich',
usagesLabel: 'Herkunftskultur',
loadButton: 'Vorschläge laden',
loading: 'Lade Vorschläge …',
empty: 'Keine Vorschläge — andere Einstellungen versuchen.',
keyMissing: 'Namensvorschläge benötigen einen API-Key — bitte in den Einstellungen konfigurieren.',
close: 'Schließen',
},
} as const
export type Strings = typeof de