import Footer from '@/components/Footer'; import Header from '@/components/Header'; import JsonLd from '@/components/JsonLd'; import SkipLink from '@/components/SkipLink'; import CMSConnectivityNotice from '@/components/CMSConnectivityNotice'; import { RecordModeProvider } from '@/components/record-mode/RecordModeContext'; import { RecordModeVisuals } from '@/components/record-mode/RecordModeVisuals'; import { ToolCoordinator } from '@/components/record-mode/ToolCoordinator'; import AnalyticsShell from '@/components/analytics/AnalyticsShell'; import { Metadata, Viewport } from 'next'; import { NextIntlClientProvider } from 'next-intl'; import { getMessages } from 'next-intl/server'; import dynamic from 'next/dynamic'; import { Suspense } from 'react'; import '../../styles/globals.css'; import { SITE_URL } from '@/lib/schema'; import { config } from '@/lib/config'; import { setRequestLocale } from 'next-intl/server'; import { Inter } from 'next/font/google'; const inter = Inter({ subsets: ['latin'], display: 'swap', variable: '--font-inter', }); export async function generateMetadata(props: { params: Promise<{ locale: string }>; }): Promise { const params = await props.params; const { locale } = params; return { metadataBase: new URL(SITE_URL), manifest: '/manifest.webmanifest', alternates: { canonical: locale === 'en' ? '/' : `/${locale}`, languages: { de: '/de', en: '/en', }, }, icons: { icon: [ { url: '/favicon.ico', sizes: 'any' }, { url: '/logo-blue.svg', type: 'image/svg+xml' }, ], apple: [{ url: '/apple-touch-icon.png', sizes: '180x180', type: 'image/png' }], }, }; } export const viewport: Viewport = { width: 'device-width', initialScale: 1, maximumScale: 5, userScalable: true, viewportFit: 'cover', themeColor: '#001a4d', }; export default async function Layout(props: { children: React.ReactNode; params: Promise<{ locale: string }>; }) { const params = await props.params; const { locale } = params; const { children } = props; const supportedLocales = ['en', 'de']; const localeStr = (typeof locale === 'string' ? locale : '').trim(); const safeLocale = supportedLocales.includes(localeStr) ? localeStr : 'en'; setRequestLocale(safeLocale); let messages = {}; try { messages = await getMessages(); } catch (error) { console.error(`Failed to load messages for locale '${safeLocale}':`, error); messages = {}; } const { getServerAppServices } = await import('@/lib/services/create-services.server'); const serverServices = getServerAppServices(); try { const { headers } = await import('next/headers'); const requestHeaders = await headers(); if ('setServerContext' in serverServices.analytics) { (serverServices.analytics as any).setServerContext({ userAgent: requestHeaders.get('user-agent') || undefined, language: requestHeaders.get('accept-language')?.split(',')[0] || undefined, referrer: requestHeaders.get('referer') || undefined, ip: requestHeaders.get('x-forwarded-for')?.split(',')[0] || undefined, }); } const { after } = await import('next/server'); after(() => { serverServices.analytics.trackPageview(); }); } catch { if (process.env.NODE_ENV !== 'production' || !process.env.CI) { console.warn( '[Layout] Static generation detected or headers unavailable, skipping server-side analytics context', ); } } // Read directly from process.env — bypasses all abstraction to guarantee correctness const recordModeEnabled = process.env.NEXT_PUBLIC_RECORD_MODE_ENABLED === 'true'; const feedbackEnabled = process.env.NEXT_PUBLIC_FEEDBACK_ENABLED === 'true'; return (
{children}