Files
GerbilManager/gerbil-manager-web/src/strings/de.ts
Gulum 2e7911074f
Some checks failed
CI / Backend Tests (.NET) (push) Successful in 1m36s
CI / Frontend Tests (Node/Vite) (push) Successful in 9m35s
CI / Docker Build & Push (push) Successful in 1m28s
CI / Deploy auf TrueNAS (Custom App) (push) Failing after 3s
feat(triage): Ticket-Fixes (Daten + Code) + prod-fähige Triage
Daten-Fixes (conflict-decisions.json, re-ingest-stabil) für ~30 Tickets:
Merges (Jamie/Hiro/Mino/Jana/Blacky/Sakura/Malou/Socke→Marty), Eltern-Korrekturen
(Jacky/Idefix/Ichika/Roni/Ethan), Kruke→Kuke (+ Todesdatum), Targa-Wurf R14 + Druna,
Stacy/Merle/Domi/Eliza; Joghurt-Phantomwurf entfernt.

Code-Fixes:
- Gaida & alle Verstorbenen: Status wird aus Todesdatum/Abgabe abgeleitet
  (Program.cs Startup-Sweep heilt Altfälle; IngestResolved re-derived nach Freeze).
- CoCo: Scheckungsart wird bei jeder Schecke angezeigt (Platzhalter wenn leer).
- M-Wurf/Gale: über-gemergte Fremdtiere via neuem litterChildren-Override entfernt.
- renameTo eltern-verknüpfungssicher (Quell-Name im Index); dateOfDeath als Override.

Prod-fähige Triage (API):
- GET /feedback/{id} + GET /feedback?status= (kein 2-MB-Dump).
- POST /import/ingest-resolved/upload (multipart) → Ingest gegen Prod ohne SSH.

Tests: 280 Backend, 149 Frontend, alle Python, betroffene Playwright grün.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-21 00:41:43 +02:00

1599 lines
66 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.',
// GEN-5: ein unbekannter Gencode-Buchstabe wurde aus einem reinerbigen
// Elternteil ergänzt (z. B. Vater ee ⇒ Kind erbt e). %s = aufgelöster Genotyp.
genotypeInferred: 'Aus den Eltern ergänzt',
genotypeInferredTitle: 'Ein unbekanntes Gen wurde aus einem reinerbigen Elternteil abgeleitet.',
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',
// WURFCHRONIK-FILTER: Wurf ist nicht in der Wurfchronik (showInChronicle=false),
// wird daher nur hier (am Elterntier) gezeigt, nicht in der Wurf-Liste.
parentLittersNotInChronicle: 'Nicht in der Wurfchronik',
offspringInBreedingTitle: 'Nachzucht in der Zucht',
offspringInBreedingEmpty: 'Keine Nachkommen dieses Tiers sind in die Zucht gegangen.',
// 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.',
// Vorfahren-Nachzucht-Zeile: statt Wurf-Karten nur ein Hinweis auf die Nachzucht.
nonResidentOffspringLabel: 'Nachzucht dieses Vorfahren:',
// Positives „Zuchttier“-Kennzeichen (Tier hatte eigene Würfe in der Zucht).
zuchttierBadge: '★ Zuchttier',
zuchttierBadgeTitle: 'Dieses Tier wurde bei dir in der Zucht eingesetzt (hatte eigene Würfe).',
// Zeile „Zuchtpartner“ in den Stammdaten (bisherige Verpaarungspartner).
zuchtpartner: 'Zuchtpartner',
},
// 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: Zuchtanwärter/in (eigenes Zuchttier) vs. reine Ahne
isResidentLabel: 'Zuchtanwärter/innen',
isResidentHint: 'Abwählen für reine Vorfahren, die nur für den Stammbaum erfasst sind und keine eigenen Zuchttiere waren.',
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 —',
notRecorded: 'noch nicht erfasst',
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)',
nameAsc: 'Alphabetisch (A-Z)',
nameDesc: 'Alphabetisch (Z-A)',
},
// Felder
fields: {
name: 'Bezeichnung',
date: 'Wurfdatum',
father: 'Vater',
mother: 'Mutter',
totalBorn: 'Wurfstärke',
deathsWithin8Weeks: 'In den ersten 8 Wochen verstorben',
stillborn: 'Totgeburten',
expectedGoHomeDate: 'Voraussichtliches Abgabedatum',
socializeDate: 'Vergesellschaftung (ab 8 Wochen)',
groupGoHomeDate: 'Abgabe als Gruppe (ab 10 Wochen)',
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.',
// Umfang: was der Import übernimmt und was (noch) nicht.
scope: {
title: 'Was wird übernommen?',
importedTitle: 'Wird übernommen',
imported: [
'Tiere (eigene + Ahnen aus fremden Zuchten) mit Stammbaum/Eltern',
'Farbschläge & Genotypen',
'Würfe (mit Eltern & Datum)',
'Kontakte (Züchter & Abnehmer)',
'Todesfälle & Todesursachen, Gewichte, Krankheiten, Fotos',
'Gehege inkl. Reinigungszyklus',
'Erwerb/Kauf, Reservierungen/Abgaben, Rücknahmen, Warteliste, Ausstellungen',
],
notImportedTitle: 'Wird (noch) nicht übernommen',
notImported: [
'Finanzen (Einnahmen, Ausgaben, Artikel, Bestand/Kasse)',
'Termine & Kalender',
'Tierarzt-Stammdaten (Adressbuch der Tierärzte)',
'Tagebuch-Einträge als eigener Bereich (werden, falls vorhanden, als Gesundheitsnotiz „Sonstiges" abgelegt)',
],
},
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',
},
},
// ── GEPRÜFTE TIERE: „vollständig korrekt"-Markierung + Schutz manueller Änderungen ──
// Ziel laienverständlich erklären: eine geprüfte Maus wird vom automatischen Import
// nicht mehr verändert; so wird der Bestand Tier für Tier sauber.
verified: {
// Karte auf der Rennmausakte
sectionTitle: 'Prüfstatus & Schutz',
explainIntro:
'Wenn bei dieser Maus alle Angaben stimmen, markiere sie als „vollständig korrekt". ' +
'Der automatische Import verändert sie dann nicht mehr — deine geprüften Angaben bleiben erhalten. ' +
'So wird dein Bestand nach und nach sauber, ohne dass der Import raten muss.',
explainProtected:
'Diese Maus enthält von dir geänderte Angaben. Diese sind vor dem Import geschützt und bleiben erhalten. ' +
'Felder, die du nicht angefasst hast, werden weiterhin automatisch aus dem Import verbessert.',
verifiedBadge: '✓ Vollständig korrekt',
verifiedBadgeTitle: 'Geprüft — der automatische Import verändert diese Maus nicht mehr.',
protectedBadge: '🔒 Geschützte Änderungen',
protectedBadgeTitle: 'Enthält von dir geänderte Angaben, die der Import nicht überschreibt.',
driftBadge: '⚠ Weicht vom Import ab',
driftBadgeTitle: 'Der automatische Import liefert für einige Felder andere Werte als dein geprüfter Stand.',
markAction: 'Als vollständig korrekt markieren',
unmarkAction: 'Markierung entfernen',
releaseAction: 'Schutz aufheben (wieder aus Import)',
marking: 'Wird gespeichert …',
markSuccess: 'Als vollständig korrekt markiert. Der Import verändert diese Maus nicht mehr.',
unmarkSuccess: 'Markierung entfernt. Beim nächsten Import wird die Maus wieder automatisch aktualisiert.',
error: 'Konnte nicht gespeichert werden.',
unmarkConfirm:
'Markierung wirklich entfernen? Die aktuellen Werte bleiben stehen; beim nächsten Import wird diese Maus wieder automatisch aktualisiert.',
releaseConfirm:
'Schutz wirklich aufheben? Beim nächsten Import wird diese Maus wieder komplett aus dem Import übernommen — deine Änderungen gehen dann verloren.',
statusUnchanged: 'Der Import stimmt mit deinem geprüften Stand überein.',
driftHeading: 'Abweichungen zum automatischen Import',
driftHint:
'So sieht es der Import gerade. Ist dein Stand richtig, kannst du das ignorieren — oder Julian passt den Import an. Deine geprüften Werte bleiben so oder so erhalten.',
colField: 'Feld',
colGolden: 'Dein geprüfter Stand',
colImport: 'Automatischer Import',
// Übersichtsseite (/hilfe/verifizierte-tiere)
pageTitle: 'Geprüfte Tiere',
pageSubtitle: 'Alle Mäuse, die du als „vollständig korrekt" markiert oder von Hand geändert hast.',
pageIntro1:
'Hier siehst du alle Mäuse, deren Angaben du geprüft und markiert hast. Diese werden vom automatischen Import nicht mehr verändert — dein Bestand wird so Tier für Tier sauber.',
pageIntro2:
'„Weicht vom Import ab" heißt: der Import liefert inzwischen andere Werte als dein geprüfter Stand — ein Hinweis, dass am Import noch etwas zu korrigieren ist. Deine Angaben bleiben trotzdem erhalten.',
empty: 'Noch keine Mäuse als vollständig korrekt markiert.',
loadError: 'Die geprüften Tiere konnten nicht geladen werden.',
sectionVerified: 'Vollständig korrekt',
sectionProtected: 'Geschützte Änderungen (von Hand bearbeitet)',
openAkte: 'Zur Akte',
protectedFieldsLabel: 'Geschützte Felder:',
warningsHeading: 'Hinweise',
statusLabels: {
unchanged: 'Unverändert',
drifted: 'Weicht vom Import ab',
missing: 'Im Import nicht mehr vorhanden',
} as Record<string, string>,
// Link auf der Hilfe-Seite
hilfeLink: 'Geprüfte Tiere (vollständig korrekt)',
// Feld-Bezeichnungen für Diff-/Schutz-Anzeige (Schlüssel = Backend-Feldnamen).
fieldLabels: {
name: 'Name',
gender: 'Geschlecht',
dateOfBirth: 'Geburtsdatum',
dateOfDeath: 'Todesdatum',
causeOfDeath: 'Todesursache',
goHomeDate: 'Abgabedatum',
genotype: 'Genotyp',
spottingType: 'Scheckung',
colorName: 'Farbschlag',
colorVarietyId: 'Farbschlag',
isResident: 'Zuchtanwärter/in',
isDeaf: 'Gehörlos',
isCastrated: 'Kastrat',
originBreeder: 'Herkunft (Zucht)',
originContact: 'Herkunft (Kontakt)',
originContactId: 'Herkunft (Kontakt)',
receiverContact: 'Abnehmer',
receiverContactId: 'Abnehmer',
notes: 'Notizen',
characterTraits: 'Charakter-Merkmale',
characterNote: 'Charakter-Notiz',
birthLitter: 'Geburtswurf',
father: 'Vater',
mother: 'Mutter',
} as Record<string, string>,
},
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.',
/** „Ähnliche bereits gelöste Tickets" im Melde-Fenster. */
similarTitle: 'Schon mal gelöst? Vielleicht hilft eines davon:',
similarOpen: 'ansehen',
/** Datei-Anhänge. */
attachLabel: 'Fotos anhängen (optional)',
attachmentError: 'Ein Anhang konnte nicht hochgeladen werden.',
/** 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',
reopenedLabel: 'Wieder geöffnet am',
markResolved: 'Als gelöst markieren',
reopen: 'Wieder öffnen',
reopenRequest:
'Du hast dieses Ticket wieder geöffnet. Bitte beschreibe kurz, was noch fehlt oder nicht stimmt — dann schaue ich es mir erneut an.',
edit: 'Bearbeiten',
save: 'Speichern',
cancel: 'Abbrechen',
saving: 'Wird gespeichert …',
delete: 'Löschen',
confirmDelete: 'Dieses Ticket in den Papierkorb verschieben? Du kannst es unter „Gelöscht" wiederherstellen.',
editTitle: 'Fehlerbericht bearbeiten',
editLabel: 'Beschreibung',
saved: 'Änderung gespeichert.',
resolvedToast: 'Ticket als gelöst markiert.',
reopenedToast: 'Ticket wieder geöffnet.',
deletedToast: 'Ticket in den Papierkorb verschoben.',
restore: 'Wiederherstellen',
restoredToast: 'Ticket wiederhergestellt.',
restoreError: 'Ticket konnte nicht wiederhergestellt werden.',
/** Countdown im Papierkorb bis zur endgültigen Löschung. {n} = verbleibende Tage. */
trashCountdownDays: 'Wird in {n} Tagen endgültig gelöscht.',
trashCountdownTomorrow: 'Wird morgen endgültig gelöscht.',
trashCountdownToday: 'Wird heute endgültig gelöscht.',
deletedLabel: 'Gelöscht am',
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',
/** Gruppe „Gelöscht": in den Papierkorb verschobene Tickets (wiederherstellbar). */
deleted: 'Gelöscht',
},
/** Leertext je gefilterter Ansicht. */
emptyDialog: 'Aktuell keine Tickets im Dialog.',
emptyOpen: 'Keine offenen Tickets.',
emptyClosed: 'Noch keine geschlossenen Tickets.',
emptyDeleted: 'Der Papierkorb ist leer.',
/** Suche + Kategorie-Filter. */
searchPlaceholder: 'Tickets durchsuchen …',
categoryFilterLabel: 'Nach Kategorie filtern',
categoryAll: 'Alle Kategorien',
emptySearch: 'Keine Tickets passen zu Suche/Filter.',
/** Daumen-Rückmeldung auf gelösten Tickets. */
helpfulQuestion: 'Hat dir das geholfen?',
helpfulYes: '👍 Ja',
helpfulNo: '👎 Nein',
helpfulThanks: 'Danke für die Rückmeldung!',
helpfulReopenNote: 'Schade — ich öffne das Ticket wieder. Bitte schreib kurz, was noch fehlt.',
/** Anhänge auf einem Ticket. */
attachmentsLabel: 'Anhänge',
addAttachment: 'Foto anhängen',
removeAttachment: 'Anhang entfernen',
attachmentAdded: 'Anhang hinzugefügt.',
attachmentRemoved: 'Anhang entfernt.',
attachmentError: 'Anhang konnte nicht verarbeitet werden.',
/** Push-Benachrichtigungen (PWA). */
pushEnable: 'Benachrichtigungen aktivieren',
pushDisable: 'Benachrichtigungen aus',
pushEnabledToast: 'Benachrichtigungen aktiviert — du wirst informiert, sobald ich antworte.',
pushDisabledToast: 'Benachrichtigungen deaktiviert.',
pushDenied: 'Benachrichtigungen wurden im Browser blockiert. Bitte in den Browser-Einstellungen erlauben.',
pushUnavailable: 'Benachrichtigungen sind auf diesem Gerät nicht verfügbar.',
/** 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