4246e0d98fc703471746c82a16b97c84052029a2
10 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
158196f67b |
Gruppen und Kategorien getrennt, EAN-Codes an der Gruppe automatisch gefuehrt
Die Umbenennung von Gruppen in "Kategorien" war falsch: Es sind zwei
verschiedene Dinge. Sie ist zurueckgenommen, Kategorien kommen als eigene Ebene
dazu.
GRUPPE zaehlt Bestaende mehrerer Marken zusammen - Mehl von Rewe, Aldi und
Migros ergeben "5 kg Mehl". Dafuer Mindestbestand mit Einheit und EAN-Codes.
KATEGORIE ordnet allein die Artikelliste ("zeig mir alle Suesswaren"), ist
verschachtelbar wie ein Lagerort und hat weder Bestand noch EAN-Codes. Ein
Artikel kann beides, eines oder keines haben.
Die Vermischung war aelter als die Umbenennung: guessGroup in offUtils.js hat
aus der Open-Food-Facts-KATEGORIE eine GRUPPE geraten. Das ist entfernt. Die
OFF-Einordnung steuert jetzt die Kategorie, wo sie hingehoert; eine Gruppe
entsteht nur ueber einen hinterlegten Gruppen-Code oder bewusste Auswahl.
EAN-Codes an der Gruppe: Das war kein Anzeigefehler. Beim Anlegen eines Artikels
wurde ausschliesslich group_id gesetzt - ein Gruppen-Code entstand nie, die
Liste war tatsaechlich leer. Die Meldung "bereits vergeben" kam daher, dass der
Code am Artikel hing. Jetzt pflegt services/group_codes.py den Code mit: beim
Zuordnen kommt er hinzu, beim Gruppenwechsel wandert er mit, beim Entfernen der
Gruppe oder Loeschen des Artikels verschwindet er. Beim Scannen aendert sich
nichts an der Reihenfolge - der Artikel wird weiterhin zuerst gefunden; der
Gruppen-Eintrag ist Beleg in der Verwaltung und Rueckfall. Traegt man denselben
Code von Hand nach, ist das kein Fehler mehr, sondern die Auskunft, dass er ueber
den Artikel bereits dort steht.
Kategorien im Backend: neue Tabelle mit parent_id (Muster von Location),
products.category_id per ADD COLUMN IF NOT EXISTS nachgezogen, deutsche
zweistufige Startliste analog zu den eingebauten Einheiten. Die Startliste wird
nur angelegt, wenn ueberhaupt noch keine Kategorie existiert - wer sie bewusst
leerraeumt, findet sie nicht wieder. Beim Setzen einer Oberkategorie wird
geprueft, dass keine Kategorie sich selbst oder einem eigenen Nachfahren
untergeordnet wird; sonst entstuende ein Ring und jede Baumdarstellung liefe
endlos. Der Produktfilter schliesst Unterkategorien ein, category_id=0 liefert
die Artikel ohne Kategorie. Export und Import fuehren die Kategorie als Pfad
("Suesswaren & Snacks > Schokolade") in einer Spalte, damit die CSV in Excel
bedienbar bleibt.
Web: neue Seite Kategorien mit Baumdarstellung, Filter ueber der Produktliste,
getrennte Auswahlfelder im Produktformular mit je einer Zeile Erklaerung, und
beim Einlagern laesst sich eine Gruppe samt Einheit und Mindestbestand direkt
anlegen, ohne den Vorgang zu verlassen.
iOS: Kategorie-Filter ueber der Produktliste, Unterkategorien eingerueckt. Die
Artikelzeile nennt jetzt das Gebinde und warnt, wenn der Mindestbestand
unterschritten ist (rot) oder weniger als ein Viertel Luft bleibt (orange).
Getrennte Auswahlfelder fuer Kategorie und Gruppe, Gruppe direkt anlegbar.
Ausserdem die Eingabefelder in der App: .textFieldStyle(.roundedBorder) zeichnet
in der dunklen Darstellung einen fast schwarzen Kasten. Ersetzt durch eine
Systemfuellung, die sich Hell und Dunkel anpasst und zurueckhaltend bleibt.
Getestet: 54 pytest-Tests gruen, 14 davon neu (Nachfahren-Sammler, OFF-Zuordnung
inklusive Vorrang der Unterkategorie, und die komplette Codepflege an der
Gruppe). Gegen die laufende API geprueft: Startliste ohne Dubletten, Filter auf
Ober- und Unterkategorie, Ringschutz, Loeschen einer Kategorie laesst Artikel
und Unterkategorien bestehen, Export/Import-Rundlauf mit Kategoriepfad, und der
Durchlauf aus der Meldung - Artikel mit Gruppe anlegen, Code steht danach in der
Gruppe. Web-Build und iOS-Geraetebuild fehler- und warnungsfrei.
Die Oberflaechen habe ich nicht selbst bedient.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
8dcc17b22f |
EAN-Codes einer Kategorie nachvollziehbar gemacht
Eine Kategorie mit Artikeln zeigte "0 EANs", und der Versuch, den Code eines eigenen Artikels einzutragen, scheiterte mit "Dieser Code ist bereits vergeben". Beides war fachlich richtig, aber nirgends erklaert. Hintergrund: Die Code-Liste einer Kategorie ist eine Vorratsliste fuer Artikel, die es noch nicht gibt. Sie greift nur, wenn beim Einlagern ein unbekannter Code gescannt wird - dann landet der neu angelegte Artikel in dieser Kategorie (routers/products.lookup). Haengt ein Code bereits an einem Artikel, findet die Suche immer zuerst den Artikel; ein gleichlautender Kategorie-Eintrag koennte nie wirken. Die Spalte zaehlte bisher ausschliesslich diese Vorratscodes, nie die Codes der enthaltenen Artikel - daher die irritierende 0. Die Kategorie liefert jetzt zusaetzlich die Codes ihrer Artikel mit (product_barcodes, rein informativ). Beide Herkuenfte stehen in einer Liste: Artikel-Codes sind als solche gekennzeichnet, nennen den Artikel und lassen sich hier nicht loeschen, weil sie am Artikel haengen. Bewusst ohne Dublette in der Datenbank - ein zweiter Datensatz koennte nie greifen und beim Loeschen des Artikels verwaisen. Die Spalte zaehlt beide Herkuenfte. Die Fehlermeldung sagt jetzt, wem ein Code gehoert: beim Artikel mit Namen und dem Hinweis, dass Artikel-Codes hier nicht eingetragen werden muessen; bei einer anderen Kategorie mit deren Namen. Signal beim Einlagern: Wird ein Code erkannt, der einer Kategorie zugeordnet ist, steht jetzt deutlich sichtbar "Wird automatisch der Kategorie X zugeordnet" samt Begruendung - sowohl im Web als auch in der App, und in beiden Faellen (Open-Food-Facts-Treffer und voellig unbekannter Code). Nach dem Anlegen meldet die Web-Oberflaeche zurueck, welche Kategorie es geworden ist. Vorher stand die Zuordnung nur als Nebensatz in grauer Kleinschrift. Getestet: Gegen die laufende API geprueft, dass eine Kategorie die Codes ihrer Artikel meldet (Haupt-Barcode und zusaetzliche Alias-Codes), dass das Eintragen eines Artikel-Codes und eines fremden Kategorie-Codes mit der jeweils richtigen Begruendung abgewiesen wird und dass ein echter Vorratscode weiterhin angelegt werden kann. iOS-Geraetebuild und Web-Build fehlerfrei, 40 pytest-Tests gruen. Dabei zwei Uebersetzungsfehler durch deutsche Anfuehrungszeichen gefunden: Das schliessende Zeichen war ein gerades ", das den String vorzeitig beendete. Korrigiert und die uebrigen Vorkommen im Projekt gleich mit vereinheitlicht. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
47ca4802aa |
Darstellung der App nachgebessert, Gruppen heissen jetzt Kategorien
Die App zeigte an mehreren Stellen Rohwerte statt lesbarer Angaben, und die
Bedienelemente sahen nicht nach Bedienelementen aus.
Deutsche Lokalisierung: Im Chargen-Abschnitt stand "10. Dec 2027" - deutsches
Format mit englischem Monatsnamen. Die Ursache lag nicht in der Formatierung,
sondern darin, dass die App als englische App gebaut wurde
(CFBundleDevelopmentRegion = $(DEVELOPMENT_LANGUAGE), also "en"). Jetzt ist
Deutsch als Sprache gesetzt; damit zeichnet iOS DatePicker und Monatsnamen von
selbst richtig. Der MonthYearPicker legt seinen Kalender zusaetzlich fest auf
de_DE, damit die Monatsnamen auch bei anderssprachigem Geraet stimmen.
Datumsformat: Die Anzeige folgt jetzt der Servereinstellung (Einstellungen ->
Darstellung), wie die Web-Oberflaeche. Neu DisplaySettings mit den fuenf
Formaten, den deutschen Beschriftungen der Basiseinheiten und der Mengenangabe
in der Leitangabe. Die doppelt ausprogrammierte MHD-Formatierung in
ListViews und CheckOutView ist damit weg.
Chargen-Abschnitt: Jede Charge steht jetzt in einem eigenen Abschnitt mit
Kopfzeile statt gestapelt in einer einzigen Formularzeile - das war der
gequetschte Eindruck. Loeschen sitzt in der Kopfzeile.
Mengenfelder haben einen sichtbaren Rahmen. Ohne ihn las sich das
rechtsbuendige Feld wie fester Text, und es war nicht erkennbar, dass sich die
Menge ueberhaupt aendern laesst.
Kamera: Der Sucher fuellte per ZStack und ignoresSafeArea den ganzen Bildschirm
und wirkte dadurch erdrueckend. Er sitzt jetzt als 4:3-Feld oben, darunter
Hinweis, Meldungen und Knoepfe in gewohnter Form. Am ScannerViewController
musste nichts geaendert werden.
Einkaufsliste: Artikel und Kategorien tragen ein Symbol, Kategoriezeilen
zusaetzlich eine Kennzeichnung. Den Artikelzeilen fehlte bisher jede Einheit
("fehlt 2 - Bestand 7 von 10"); sie nennen jetzt Packungen und Basismenge.
Produktdetails: Die Felder waren blanke TextFields - sobald ein Wert drinstand,
verschwand der Platzhalter und man las nur noch "Bratbutter" / "M-Classic" /
"450". Jetzt mit Beschriftung links, Einheit hinter der Packungsgroesse (vorher
stand dort der rohe API-Wert "gram") und einem Abschnitt "Erkennung" mit
Barcode. Dasselbe im Formular zum Anlegen.
Gruppen heissen in der Oberflaeche jetzt Kategorien - in Web und App. Tabelle,
Feld group_id und die Endpunkte behalten ihren Namen, damit bestehende Zugriffe
wie Home Assistant weiterlaufen; der Unterschied ist rein sprachlich. Die
Kategorie laesst sich nun auch in der App zuweisen, was vorher gar nicht ging.
Dabei ein Fehler gefunden und behoben: Swift laesst nil-Optionals beim Kodieren
weg, das Backend wertet nur mitgeschickte Felder aus. "Keine Kategorie" oder
eine geloeschte Marke waeren damit stumm verpufft. ProductUpdateRequest kodiert
diese Felder jetzt ausdruecklich. Der Mindestbestand steht bewusst nicht mehr
darin, weil die App ihn nicht bearbeitet und ein mitgesendetes null ihn
geloescht haette.
Getestet: iOS-Geraetebuild fehler- und warnungsfrei, Web-Build laeuft durch,
40 pytest-Tests gruen. Die Datumsformatierung wurde eigenstaendig uebersetzt
und gegen elf Faelle geprueft (alle fuenf Formate, Monatsangabe, fehlendes und
unlesbares Datum) - alle korrekt. Im gebauten Bundle ist belegt, dass
CFBundleDevelopmentRegion auf "de" steht. Gegen die laufende API geprueft:
/settings und /groups liefern die erwarteten Felder, das Leeren der Kategorie
wirkt jetzt und der Mindestbestand bleibt dabei erhalten.
Die Oberflaeche selbst habe ich nicht auf dem Geraet bedient.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
f3ee10e4d4 |
Einkaufsliste, Ablaufliste und Produktverwaltung in der App
Der Startbildschirm bekommt drei weitere Einstiege: Einkaufsliste (Artikel und
Gruppen unter Mindestbestand), Bald ablaufend (Chargen mit Restfrist, abgelaufene
rot) und Produkte. Alle Listen lassen sich durch Herunterziehen aktualisieren.
In den Produktdetails sind Name, Marke, Packungsgroesse, Gebinde-Bezeichnung und
MHD-Angabe aenderbar. Die Chargen werden mit Menge und MHD aufgelistet; Antippen
oeffnet die Korrektur von Menge und MHD (inklusive Umschalten auf Monat/Jahr),
Wischen loescht eine Charge. Mengen werden in der Leitangabe des Artikels
angezeigt und beim Speichern in Basiseinheiten zurueckgerechnet, weil die
Chargen-Schnittstelle in Basiseinheiten arbeitet.
Dabei ist ein bestehender Fehler aufgefallen und mitbehoben: Fuer das Gebinde
kennt das Backend nur das Schluesselwort "package" (services/conversion.py
akzeptiert package/packung/pkg/pack). Die App hat stattdessen die
Gebinde-Bezeichnung selbst als Einheit geschickt. Bei Produkten mit eigener
Bezeichnung - "Glas", "Dose", "Flasche", "Tuete" - schlugen Einlagern und
Auslagern damit mit "Unbekannte Einheit: Dose" fehl. Nur die Standardbezeichnung
"Packung" funktionierte zufaellig, weil sie in der Liste der Schluesselwoerter
steht. Anzeige und uebertragener Wert sind jetzt getrennt (neuer Typ
UnitOption): angezeigt wird weiterhin "Glas", geschickt wird "package".
Ausserdem die Warnung zu den Bildschirmausrichtungen behoben - das iPad verlangt
alle Ausrichtungen, solange die App nicht auf Vollbild besteht.
Getestet: iOS-Geraetebuild fehler- und warnungsfrei. Die Endpunkte hinter den
neuen Ansichten sind gegen die laufende API geprueft, ebenso das Aendern und
Loeschen von Chargen. Der Einheiten-Fehler wurde an der echten API
nachgestellt ("Unbekannte Einheit: Dose") und mit "package" als 200 bestaetigt.
Die neuen Ansichten habe ich nicht auf dem Geraet bedient.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
||
|
|
c4acc8bec7 |
MHD per Texterkennung einlesen
In der Chargenzeile beim Einlagern gibt es einen Knopf "MHD scannen". Er oeffnet die Texterkennung von VisionKit; erkannte Daten erscheinen als Vorschlag und werden erst uebernommen, wenn man sie antippt. Bewusst kein automatisches Uebernehmen: Eine Fehllesung beim MHD faellt sonst erst auf, wenn die Ware bereits falsch einsortiert ist. Der Parser deckt die Schreibweisen ab, die auf Verpackungen vorkommen - Tagesdaten (12.09.2026, 2026-09-12, 12/09/2026, 12.09.26) und Monatsangaben (09/2026, 09.2026, 2026-09, 09/26). Erkennt der Aufdruck nur Monat und Jahr, stellt sich die Eingabe sichtbar auf Monat/Jahr um. Damit aus Chargennummern und EAN-Codes keine Phantasiedaten werden, greifen mehrere Einschraenkungen: Muster mit Tag werden zuerst geprueft, ein bereits erkannter Textabschnitt wird nicht erneut ausgewertet, Monate ausserhalb 1-12 entfallen und das Jahr muss im Fenster von fuenf Jahren rueckwaerts bis dreissig vorwaerts liegen. Der Knopf erscheint nur, wenn das Geraet Texterkennung unterstuetzt (Neural Engine); sonst bleibt die Eingabe von Hand. Getestet: Der Parser wurde eigenstaendig uebersetzt und gegen 14 Faelle geprueft, alle korrekt - darunter, dass "12.09.2026" nicht als Monatsangabe gelesen wird, dass eine EAN keine Treffer erzeugt und dass unplausible Jahre und Monate verworfen werden. Der iOS-Geraetebuild laeuft fehlerfrei durch. Die Erkennung an einer echten Verpackung habe ich nicht selbst ausprobiert. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
30307d6cfb |
MHD nur mit Monat und Jahr in Web-UI und iOS-App
Setzt den Backend-Umbau in beiden Oberflaechen um. Die Genauigkeit gilt jeweils fuer den ganzen Einlager-Vorgang und nicht je Charge: Auf einer Packung steht entweder ein Tagesdatum oder nur Monat/Jahr, gemischt kommt das nicht vor. Vorbelegt wird sie aus dem Produkt, laesst sich aber im Vorgang umstellen. Web-UI: Umschalter im Kopf der Chargenliste; das Eingabefeld wechselt zwischen type="date" und type="month". Im Produktformular gibt es das neue Feld "MHD-Angabe" neben der Gebinde-Bezeichnung. Anzeige laeuft ueber den Settings-Context, damit das eingestellte Datumsformat erhalten bleibt und Monatsangaben ueberall als "09/2026" erscheinen (Auslagern, Uebersicht, Chargentabelle). Die Abgelaufen-Warnung prueft bei Monatsangaben gegen den Monatsletzten - sonst haette eine Packung schon am Monatsersten als abgelaufen gegolten. iOS: Auswahl "Tagesdatum / nur Monat/Jahr" im Einlagern-Formular und beim Anlegen eines Artikels. SwiftUI hat keinen DatePicker ohne Tag, deshalb ein eigener MonthYearPicker aus zwei Auswahlfeldern; die Jahresliste reicht zwei Jahre zurueck (bereits abgelaufene Ware) und fuenfzehn nach vorn (Konserven). Die Chargenauswahl beim Auslagern zeigt Monatsangaben ebenfalls ohne Tag. Getestet: Web-Build (vite) und iOS-Geraetebuild laufen fehlerfrei durch, die App ist auf dem iPhone installiert. Das Verhalten in der Oberflaeche ist noch nicht von Hand durchgeklickt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
d680aeff0e |
Mengenfeld beschriftet und "Angemeldet bleiben" ergaenzt
Beim Einlagern stand in der Chargenzeile eine nackte 1 ohne Beschriftung. Das las sich wie eine Nummerierung der Charge, war aber das Mengenfeld. Die Zeile hat jetzt links die Beschriftung "Menge", der Wert steht rechtsbuendig; die 1 bleibt als Vorgabe, weil meistens genau ein Stueck eingelagert wird. Beim Auslagern war dieselbe Zeile ebenso unbeschriftet und ist jetzt gleich aufgebaut. Anmeldung: Das Token wanderte bisher immer dauerhaft in den Schluesselbund. Der neue Haken "Angemeldet bleiben" laesst sich abwaehlen - dann gilt die Anmeldung nur, solange die App laeuft, und es bleibt nichts auf dem Geraet zurueck. Die Wahl wird gemerkt, damit der Haken beim naechsten Mal richtig steht. Dabei ist aufgefallen, dass der Benutzername nirgends gespeichert wurde: Nach einem Neustart stand im Menue nur noch "Angemeldet als" ohne Namen. Er wird jetzt zusammen mit dem Token abgelegt und beim Abmelden wieder entfernt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
8e94f15c84 |
App-Icon eingebunden, fehlendes Auslagern-Symbol und Barcode-Erkennung verbessert
Auslagern-Kachel: "arrow.up.from.line" existiert als SF Symbol nicht, deshalb blieb das Icon leer und man sah nur die eingefaerbte Kachelflaeche. Ersetzt durch "arrow.up.to.line", das Gegenstueck zum "arrow.down.to.line" beim Einlagern. Alle uebrigen im Projekt verwendeten Symbolnamen wurden gegen die Symbolliste des Systems geprueft und sind gueltig. App-Icon: Das mitgelieferte AppIcon.icon (Icon-Composer-Format) wird als Ressource eingebunden und ueber ASSETCATALOG_COMPILER_APPICON_NAME gesetzt. Die Icon-Eintraege landen korrekt in der selbstgepflegten Info.plist. Barcode-Erkennung, nachdem ein dunkelgruener Code auf weiss nicht gelesen wurde: - Aufloesung auf 1920x1080 statt der Voreinstellung, damit kontrastarme und kleine Codes ueberhaupt sauber aufgeloest werden. - Dauerhafter Autofokus mit Beschraenkung auf den Nahbereich; weiches Nachfuehren aus, da es hier nur verzoegert. - Antippen stellt gezielt auf eine Stelle scharf und misst dort die Belichtung. - Licht-Schalter in der Navigationsleiste beider Scan-Bildschirme; beim Verlassen wird das Licht sicher wieder ausgeschaltet. - Mehr Symbologien (ITF-14, DataMatrix, PDF417, Aztec, Code93). Es werden nur die Typen gesetzt, die die Kamera meldet - sonst wirft AVFoundation zur Laufzeit. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
3a0c130cb1 |
iOS-App kompiliert erstmals: Info.plist gesichert und zwei Build-Fehler behoben
Die App war bisher nie durch einen Compiler gelaufen. Mit Xcode 26.6 baut sie jetzt fehler- und warnungsfrei gegen das iOS-16-Deployment-Target. Info.plist: Der "info:"-Block in project.yml hat die handgepflegte Sources/Info.plist bei jedem "xcodegen generate" ueberschrieben und dabei Schluessel verloren, die nur in der Datei standen - insbesondere NSAppTransportSecurity/NSAllowsLocalNetworking. Ohne diese Ausnahme haette die App den Server im Heimnetz per http:// ueberhaupt nicht erreichen koennen. Die Datei ist jetzt die einzige Quelle: project.yml verweist nur noch per INFOPLIST_FILE darauf und nimmt sie aus den Sources heraus. Die Bundle-Keys, die vorher nur die erzeugte Fassung hatte (CFBundleExecutable, CFBundleIdentifier, CFBundlePackageType ...), stehen nun in der Datei selbst. ProductViews: onChange(of:) wurde in der zweiwertigen iOS-17-Form verwendet und war damit ein harter Fehler - auf die einwertige Form umgestellt. ProjectGoodApp: application(_:performActionFor:) als async-Fassung reicht das nicht-Sendable UIApplicationShortcutItem ueber eine Actor-Grenze. Das ist heute eine Warnung und im Swift-6-Sprachmodus ein Fehler; jetzt die Variante mit Completion-Handler. Der dritte Verdacht hat sich nicht bestaetigt: AudioServicesPlaySystemSound in ScannerView uebersetzt ohne zusaetzliches "import AudioToolbox", weil AVFoundation es bereits mitbringt. Deshalb dort keine Aenderung. Das erzeugte ProjectGood.xcodeproj wandert in .gitignore, da project.yml es vollstaendig beschreibt. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> |
||
|
|
4bb9a10366 |
iOS-App angefangen; Import-Modi; MHD-Formatierung; Gebinde in Ablauf-Ansichten
iOS (neu, ios/):
- SwiftUI-App: Login (Server + Keychain-Token), Kamera-Scanner (EAN/UPC/Code128),
Einlagern mit mehreren Chargen und eigenem MHD, Auslagern mit Chargenauswahl
oder FEFO, Artikelsuche, Anlegen mit Open-Food-Facts-Vorbefuellung.
- Home-Screen-Shortcuts: Schnellaktionen (langer Druck) und URL-Schema
projectgood://checkin | ://checkout fuer eigene Symbole via Kurzbefehle.
- project.yml (XcodeGen) + README mit Build-Anleitung. NICHT kompiliert - auf
diesem Rechner ist kein Xcode vorhanden.
Import-Modi (wie besprochen sinnvoll):
- add (Standard, nichts loeschen), replace_listed (Bestaende der in der Datei
genannten Produkte ersetzen - fuer Inventur), replace_all (alles ersetzen).
Geleerte Bestaende werden als Korrektur-Bewegung protokolliert; die Oberflaeche
fragt bei den zerstoerenden Modi nach.
Anzeige:
- "Bald ablaufend"/"Abgelaufen" zeigen jetzt das Gebinde ("1 Glas") mit der
Basiseinheit klein darunter (ExpiringItem liefert die Einheiten mit).
- MHD als Zeitspanne mit korrektem Numerus: "in 3 Tagen", "in 1 Woche",
"vor 2 Wochen", dazu heute/morgen/gestern.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|