diff --git a/src/app/[locale]/applications/[slug]/page.tsx b/src/app/[locale]/applications/[slug]/page.tsx index 3c5065c..730593d 100644 --- a/src/app/[locale]/applications/[slug]/page.tsx +++ b/src/app/[locale]/applications/[slug]/page.tsx @@ -1,5 +1,5 @@ -// Force-dynamic — see /[locale]/page.tsx for the rationale. -export const dynamic = "force-dynamic"; +// ISR: revalidate every 60s — see /[locale]/page.tsx for the full rationale. +export const revalidate = 60; import type { Metadata } from "next"; import Link from "next/link"; @@ -9,6 +9,7 @@ import { prisma } from "@/lib/prisma"; import { notFound } from "next/navigation"; import ApplicationClient from "./ApplicationClient"; +import { setRequestLocale } from "next-intl/server"; import { getLocalizedData } from "@/lib/i18nHelper"; import { buildPageMetadata, @@ -82,16 +83,15 @@ export async function generateMetadata({ } } -// generateStaticParams intentionally omitted — combined with -// `dynamic = "force-dynamic"`, this guarantees pure SSR per request. -// Having it (even returning [] in prod) made Next.js classify the -// route as SSG-eligible, which conflicted with dynamic API reads -// elsewhere in the tree and surfaced as DYNAMIC_SERVER_USAGE errors. +// generateStaticParams omitted — slug pages render on-demand and are cached +// by ISR (revalidate=60). The DYNAMIC_SERVER_USAGE issue that previously +// blocked this is now fixed via setRequestLocale. // 🔥 AHORA RECIBIMOS EL LOCALE DESDE LA URL export default async function ApplicationPage({ params }: { params: Promise<{ slug: string, locale: string }> }) { const resolvedParams = await params; const { slug, locale } = resolvedParams; + setRequestLocale(locale); // 1. Buscamos la Teoría General de la Aplicación let rawData: any = null; diff --git a/src/app/[locale]/heritage/page.tsx b/src/app/[locale]/heritage/page.tsx index 185fc58..dee83c5 100644 --- a/src/app/[locale]/heritage/page.tsx +++ b/src/app/[locale]/heritage/page.tsx @@ -1,5 +1,6 @@ -// Force-dynamic — see /[locale]/page.tsx for the rationale. -export const dynamic = "force-dynamic"; +// ISR: revalidate every 60s — see /[locale]/page.tsx for the full rationale. +// setRequestLocale caches the locale so next-intl doesn't read cookies/headers. +export const revalidate = 60; import type { Metadata } from "next"; import Link from "next/link"; @@ -11,7 +12,7 @@ import AutoPlayVideo from "@/components/AutoPlayVideo"; // 🔥 IMPORTACIONES DE IDIOMAS import { getLocalizedData } from "@/lib/i18nHelper"; -import { getTranslations } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { buildPageMetadata } from "@/lib/seo"; export async function generateMetadata({ @@ -197,7 +198,7 @@ export default async function HeritagePage({ params }: { params: Promise<{ local const resolvedParams = await params; const locale = resolvedParams.locale; - // Pass locale explicitly so getTranslations stays static-friendly under ISR. + setRequestLocale(locale); const t = await getTranslations({ locale, namespace: "HeritagePage" }); let rawSections: any[] = []; diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx index 8c0a7f2..2914a7e 100644 --- a/src/app/[locale]/layout.tsx +++ b/src/app/[locale]/layout.tsx @@ -1,4 +1,5 @@ import type { Metadata, Viewport } from "next"; +import { Suspense } from "react"; import { Inter } from "next/font/google"; import "../globals.css"; @@ -9,9 +10,15 @@ import Footer from "@/components/layout/Footer"; import CartDrawer from "@/components/layout/CartDrawer"; import { NextIntlClientProvider } from 'next-intl'; -import { getMessages } from 'next-intl/server'; +import { getMessages, setRequestLocale } from 'next-intl/server'; import { notFound } from 'next/navigation'; import { routing } from '@/i18n/routing'; + +// Pre-render all 5 locale variants at build time so Next.js knows which +// [locale] segments are valid. Required for ISR to work with next-intl. +export function generateStaticParams() { + return routing.locales.map((locale) => ({ locale })); +} import { getBranding, getSocialLinks } from '@/lib/siteSettings'; import { organizationSchema, websiteSchema } from '@/lib/seo'; import JsonLd from '@/components/seo/JsonLd'; @@ -116,6 +123,10 @@ export default async function RootLayout({ notFound(); } + // Cache the locale so next-intl resolves it from memory instead of + // reading cookies/headers — this is what allows ISR on child pages. + setRequestLocale(locale); + const [messages, branding, social] = await Promise.all([ getMessages({ locale }), getBranding(), @@ -153,7 +164,10 @@ export default async function RootLayout({ - + {/* Suspense boundary required for useSearchParams() under ISR */} + + +
{children} diff --git a/src/app/[locale]/news/[slug]/page.tsx b/src/app/[locale]/news/[slug]/page.tsx index 3b10ed5..36f9fe3 100644 --- a/src/app/[locale]/news/[slug]/page.tsx +++ b/src/app/[locale]/news/[slug]/page.tsx @@ -1,5 +1,5 @@ -// Force-dynamic — see /[locale]/page.tsx for the rationale. -export const dynamic = "force-dynamic"; +// ISR: revalidate every 60s — see /[locale]/page.tsx for the full rationale. +export const revalidate = 60; import type { Metadata } from "next"; import Link from "next/link"; @@ -8,6 +8,7 @@ import { prisma } from "@/lib/prisma"; import { ArrowLeft, Calendar, Tag, Linkedin } from "lucide-react"; import BreathingField from "@/components/visuals/BreathingField"; +import { setRequestLocale } from "next-intl/server"; import { getLocalizedData } from "@/lib/i18nHelper"; import { buildPageMetadata, @@ -47,8 +48,9 @@ export async function generateMetadata({ } } -// generateStaticParams intentionally omitted — see /[locale]/page.tsx -// for the rationale. +// generateStaticParams omitted — slug pages render on-demand and are cached +// by ISR (revalidate=60). The DYNAMIC_SERVER_USAGE issue is fixed via +// setRequestLocale. // ── SÚPER PARSER MARKDOWN (Con Tablas, Imágenes y Dark/Light Mode) ── // ... (El código del Súper Parser se queda IGUAL, no te preocupes) ... @@ -213,6 +215,7 @@ const renderMarkdown = (text: string) => { export default async function ArticlePage({ params }: { params: Promise<{ slug: string, locale: string }> }) { const resolvedParams = await params; const { slug, locale } = resolvedParams; + setRequestLocale(locale); let rawArticle: any = null; try { diff --git a/src/app/[locale]/news/page.tsx b/src/app/[locale]/news/page.tsx index 0b83614..5d14dab 100644 --- a/src/app/[locale]/news/page.tsx +++ b/src/app/[locale]/news/page.tsx @@ -6,11 +6,11 @@ import { Newspaper, ArrowRight, Calendar } from "lucide-react"; import BreathingField from "@/components/visuals/BreathingField"; import { getLocalizedData } from "@/lib/i18nHelper"; -import { getTranslations } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { buildPageMetadata } from "@/lib/seo"; -// Force-dynamic — see /[locale]/page.tsx for the rationale. -export const dynamic = "force-dynamic"; +// ISR: revalidate every 60s — see /[locale]/page.tsx for the full rationale. +export const revalidate = 60; export async function generateMetadata({ params, @@ -31,7 +31,7 @@ export default async function NewsHub({ params }: { params: Promise<{ locale: st const resolvedParams = await params; const locale = resolvedParams.locale; - // Pass locale explicitly so getTranslations stays static-friendly under ISR. + setRequestLocale(locale); const t = await getTranslations({ locale, namespace: "NewsHub" }); let rawArticles: any[] = []; diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx index 5cf7af3..6f4c9c8 100644 --- a/src/app/[locale]/page.tsx +++ b/src/app/[locale]/page.tsx @@ -15,17 +15,16 @@ import ApplicationsDeep from "@/components/sections/ApplicationsDeep"; import HeroReel from "@/components/sections/HeroReel"; import WhatWeDo from "@/components/sections/WhatWeDo"; +import { setRequestLocale } from "next-intl/server"; import { buildPageMetadata } from "@/lib/seo"; import { getBranding } from "@/lib/siteSettings"; -// Force-dynamic — there's an interaction between next-intl 4, Prisma client, -// and Next.js 16 standalone that intermittently leaks dynamic API reads -// (cookies / headers) through Server Components and trips DYNAMIC_SERVER_USAGE -// under ISR. Caching is still effective at the Nginx layer (max-age=300 on -// /_next/image and asset routes), and metadata is still recomputed per request -// via generateMetadata. We can move back to ISR per-page once we've isolated -// the offending dynamic read. -export const dynamic = "force-dynamic"; +// ISR: revalidate every 60s. The DYNAMIC_SERVER_USAGE issue was caused by +// next-intl internally reading cookies/headers to resolve the locale. +// Fixed by calling setRequestLocale(locale) which caches the locale in +// React cache, preventing the dynamic API read. Nginx also caches with +// s-maxage=60 + stale-while-revalidate=300 as a safety net. +export const revalidate = 60; const TITLES: Record = { en: "FLUX | Solid-State RF Industrial Solutions", @@ -63,6 +62,7 @@ export async function generateMetadata({ // ✅ Next.js 16: params es Promise y DEBE ser awaiteado export default async function Home({ params }: { params: Promise<{ locale: string }> }) { const { locale } = await params; + setRequestLocale(locale); // --- 1. SLIDES DEL HERO (CMS-managed via HeroSlide model, fallback to filesystem) --- let heroSlides: Array<{