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>
1599 lines
66 KiB
TypeScript
1599 lines
66 KiB
TypeScript
/**
|
||
* 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 (A–Z)',
|
||
nameDesc: 'Name (Z–A)',
|
||
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. 1–2 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
|