fix: pass locale explicitly to next-intl helpers (DYNAMIC_SERVER_USAGE)
Deploy to VPS / deploy (push) Has been cancelled

Production logs were spamming "DYNAMIC_SERVER_USAGE" errors and every
ISR-cached page (home, news, heritage, applications, news/[slug]) was
500-ing. Root cause: when force-dynamic was replaced with revalidate=60
last commit batch, the implicit locale-resolution path through
next-intl's getTranslations() / getLocale() / getMessages() became a
problem. Without an explicit locale arg, next-intl reads cookies()
under the hood — which trips Next.js's "dynamic API used inside a
static / ISR render" guard and aborts with DYNAMIC_SERVER_USAGE.

Fix: pass the locale (already known from the URL via params) every
time we call next-intl on the server.

CHANGES
- src/components/layout/Footer.tsx
  - Now accepts `locale` as a prop instead of awaiting getLocale()
  - getTranslations({ locale, namespace: "Footer" })
- src/app/[locale]/layout.tsx
  - Passes locale prop to <Footer locale={locale} />
  - getMessages({ locale }) instead of getMessages()
- src/components/sections/PatrizioLegacy.tsx
  - Accepts `locale` prop, passes it to getTranslations
- src/app/[locale]/page.tsx
  - Renders <PatrizioLegacy locale={locale} />
- src/app/[locale]/news/page.tsx (body)
  - getTranslations({ locale, namespace: "NewsHub" })
- src/app/[locale]/heritage/page.tsx (body)
  - getTranslations({ locale, namespace: "HeritagePage" })

The generateMetadata / generateStaticParams paths in news/[slug] and
heritage already passed locale correctly — only the page bodies and
shared components were leaking dynamic reads.

Net effect: all five ISR pages render statically again, the error spam
in `docker compose logs app` clears, and /en/applications/digital-print
loads its server component without falling through to the error boundary.
This commit is contained in:
2026-05-04 16:53:20 -05:00
parent 3d066fa67e
commit e879016879
6 changed files with 20 additions and 16 deletions
+2 -2
View File
@@ -197,8 +197,8 @@ export default async function HeritagePage({ params }: { params: Promise<{ local
const resolvedParams = await params; const resolvedParams = await params;
const locale = resolvedParams.locale; const locale = resolvedParams.locale;
// 🔥 Cargamos el diccionario para los textos fijos // Pass locale explicitly so getTranslations stays static-friendly under ISR.
const t = await getTranslations("HeritagePage"); const t = await getTranslations({ locale, namespace: "HeritagePage" });
let rawSections: any[] = []; let rawSections: any[] = [];
try { try {
+2 -2
View File
@@ -72,7 +72,7 @@ export default async function RootLayout({
} }
const [messages, branding, social] = await Promise.all([ const [messages, branding, social] = await Promise.all([
getMessages(), getMessages({ locale }),
getBranding(), getBranding(),
getSocialLinks(), getSocialLinks(),
]); ]);
@@ -114,7 +114,7 @@ export default async function RootLayout({
{children} {children}
</div> </div>
<Footer /> <Footer locale={locale} />
<SilentObserver /> <SilentObserver />
</NextIntlClientProvider> </NextIntlClientProvider>
+2 -2
View File
@@ -31,8 +31,8 @@ export default async function NewsHub({ params }: { params: Promise<{ locale: st
const resolvedParams = await params; const resolvedParams = await params;
const locale = resolvedParams.locale; const locale = resolvedParams.locale;
// 🔥 LLAMAMOS AL DICCIONARIO // Pass locale explicitly so getTranslations stays static-friendly under ISR.
const t = await getTranslations("NewsHub"); const t = await getTranslations({ locale, namespace: "NewsHub" });
let rawArticles: any[] = []; let rawArticles: any[] = [];
try { try {
+1 -1
View File
@@ -176,7 +176,7 @@ export default async function Home({ params }: { params: Promise<{ locale: strin
<ApplicationsDashboard dbApps={dbApps} /> <ApplicationsDashboard dbApps={dbApps} />
<GlobalOperations dbNodes={mapNodes} dbApps={dbApps} /> <GlobalOperations dbNodes={mapNodes} dbApps={dbApps} />
<OurStory dbTimeline={dbTimeline} /> <OurStory dbTimeline={dbTimeline} />
<PatrizioLegacy /> <PatrizioLegacy locale={locale} />
<div className="h-64 w-full"></div> <div className="h-64 w-full"></div>
</div> </div>
</main> </main>
+6 -4
View File
@@ -2,14 +2,16 @@ import { Link } from "@/i18n/routing";
import { Linkedin, Instagram, Youtube, Mail, Phone } from "lucide-react"; import { Linkedin, Instagram, Youtube, Mail, Phone } from "lucide-react";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
import { getLocalizedData } from "@/lib/i18nHelper"; import { getLocalizedData } from "@/lib/i18nHelper";
import { getTranslations, getLocale } from "next-intl/server"; import { getTranslations } from "next-intl/server";
import { getFooterSettings, getSocialLinks } from "@/lib/siteSettings"; import { getFooterSettings, getSocialLinks } from "@/lib/siteSettings";
import { AiContactButton, AiFooterLink } from "@/components/ui/AiTriggerButton"; import { AiContactButton, AiFooterLink } from "@/components/ui/AiTriggerButton";
export default async function Footer() { // `locale` comes from the parent layout. Reading it via getLocale() here
const locale = await getLocale(); // would call cookies()/headers() under the hood, breaking ISR with
const t = await getTranslations("Footer"); // DYNAMIC_SERVER_USAGE — passing it explicitly keeps everything static.
export default async function Footer({ locale }: { locale: string }) {
const t = await getTranslations({ locale, namespace: "Footer" });
const [footer, social] = await Promise.all([ const [footer, social] = await Promise.all([
getFooterSettings(locale), getFooterSettings(locale),
+5 -3
View File
@@ -1,10 +1,12 @@
import { ArrowRight } from "lucide-react"; import { ArrowRight } from "lucide-react";
import { Link } from "@/i18n/routing"; import { Link } from "@/i18n/routing";
// 🔥 IMPORTAMOS LA VERSIÓN DE SERVIDOR
import { getTranslations } from "next-intl/server"; import { getTranslations } from "next-intl/server";
export default async function PatrizioLegacy() { // `locale` is passed in from the parent server component (the page).
const t = await getTranslations("PatrizioLegacy"); // Calling getTranslations without an explicit locale forces next-intl to
// read cookies/headers, which trips DYNAMIC_SERVER_USAGE under ISR.
export default async function PatrizioLegacy({ locale }: { locale: string }) {
const t = await getTranslations({ locale, namespace: "PatrizioLegacy" });
return ( return (
<section id="legacy" className="relative w-full max-w-7xl mx-auto px-6 py-32 md:py-48 z-10"> <section id="legacy" className="relative w-full max-w-7xl mx-auto px-6 py-32 md:py-48 z-10">