fix: Preis-/Datumsformat an Kunden-Locale anpassen, Produktgalerie-LCP verbessern

- format.ts: formatPrice/formatDate/formatDateTime/formatMonthYear nehmen
  jetzt ein optionales Locale-Argument (Default "de" fuer unveraenderte
  Aufrufer wie Rechnungen/Admin) und formatieren fuer "en" als en-GB statt
  hart codiert als de-DE -- englischsprachige Kundschaft sah bisher trotz
  gewaehlter Sprache "9,90 €" und "10. Mai 2026" statt "€9.90"/"10 May 2026".
  Alle kundenseitigen Aufrufer (Produktseite, Warenkorb, Checkout, Bestell-
  verfolgung, Konto-Bestellungen, Ernten-/Chargenseiten, Live-Suchvorschlaege,
  Bestell-/Versand-E-Mails) reichen jetzt die aktive Locale durch.
- en.ts: openCart/shippingWithCount/shippingLabel pluralisieren "item(s)"
  jetzt korrekt (vorher z.B. "Open cart, 1 items").
- product-gallery.tsx: Haupt- und Vorschaubilder nutzen jetzt next/image
  statt <img> (hochgeladene Produktfotos sind immer same-origin unter
  /uploads/..., brauchen also keine remotePatterns-Konfiguration wie der
  entfernte Kommentar behauptete) -- Hauptbild mit priority/responsivem
  sizes, da es auf der Produktseite das wahrscheinlichste LCP-Element ist.
- content-image.tsx: neue optionale priority-Prop; hero.tsx setzt sie fuer
  das Startseiten-Hero-Bild (ebenfalls LCP-Kandidat).
- Sticky-Mobile-CTA-Leiste und useCartStock-Polling gegengeprueft: bereits
  korrekt (pb-28-Platzreservierung bzw. Fetch nur bei Warenkorb-Aenderung
  ohne Intervall) -- keine Aenderung noetig.

Verifiziert: tsc --noEmit clean, pnpm test (142/142 gruen), pnpm build erfolgreich.
This commit is contained in:
Nick Szaunig committed 2026-09-06 02:57:57 +02:00
1 parent ac432e261b
commit de0f6ee249
20 files changed
+137 -84

No files matched your search

+12 -6
View File
@@ -45,7 +45,8 @@ export async function generateMetadata(
export default async function ProductDetailPage(
props: PageProps<"/honig/[slug]">
) {
const t = getDictionary(await getLocale());
const locale = await getLocale();
const t = getDictionary(locale);
const { slug } = await props.params;
const { error, message, notifyError, notifyMessage } = await props.searchParams;
const product = await getProductBySlug(slug);
@@ -167,18 +168,20 @@ export default async function ProductDetailPage(
<div className="mt-6 flex items-baseline gap-3">
<span className="text-2xl text-forest">
{formatPrice(product.priceCents, product.currency)}
{formatPrice(product.priceCents, product.currency, locale)}
</span>
<span className="text-sm text-ink/65">{product.weightGrams} g</span>
</div>
<p className="text-xs text-ink/65">
{formatPricePerKg(product.pricePerKgCents, product.currency)}
{formatPricePerKg(product.pricePerKgCents, product.currency, locale)}
</p>
<Link
href="/versand-zahlung"
className="mt-2 inline-block text-xs text-ink/65 underline decoration-ink/30 hover:text-forest hover:decoration-forest"
>
{t.productPage.shippingHint(baseShippingCents === 0 ? t.cartPage.free : formatPrice(baseShippingCents))}
{t.productPage.shippingHint(
baseShippingCents === 0 ? t.cartPage.free : formatPrice(baseShippingCents, "EUR", locale)
)}
</Link>
{isHoney ? (
@@ -270,7 +273,10 @@ export default async function ProductDetailPage(
label={t.productPage.detailLabels.origin}
value={`${product.harvest.location} — ${product.harvest.type} ${product.harvest.year}`}
/>
<DetailRow label={t.productPage.detailLabels.harvest} value={formatDate(product.harvest.harvestDate)} />
<DetailRow
label={t.productPage.detailLabels.harvest}
value={formatDate(product.harvest.harvestDate, locale)}
/>
<DetailRow label={t.productPage.detailLabels.batch} value={product.batch.code} />
<DetailRow label={t.productPage.detailLabels.storage} value={t.productPage.storageText} />
<DetailRow label={t.productPage.detailLabels.note} value={t.productPage.infantWarningText} />
@@ -311,7 +317,7 @@ export default async function ProductDetailPage(
<span className="sr-only">{t.productPage.starsOutOf5(review.rating)}</span>
{review.comment ? <p className="mt-2 text-sm text-ink/80">{review.comment}</p> : null}
<p className="mt-2 text-xs text-ink/65">
{review.customer.firstName} · {formatDate(review.createdAt)}
{review.customer.firstName} · {formatDate(review.createdAt, locale)}
</p>
</li>
))}