* Fix ActivityFeed: Remove dynamic import that was causing it to disappear in production * Fix ActivityFeed hydration error: Move localStorage read to useEffect to prevent server/client mismatch * Update Node.js version to 25 in Gitea workflows - Fix EBADENGINE error for camera-controls@3.1.2 which requires Node.js >=22 - Update production-deploy.yml, dev-deploy.yml, and ci-cd-with-gitea-vars.yml.disabled - Node.js v25 matches local development environment * Update Dockerfile to use Node.js 25 - Update base image from node:20 to node:25 - Matches Gitea workflow configuration and camera-controls@3.1.2 requirements * Fix production deployment: Start database dependencies - Remove --no-deps flag which prevented postgres and redis from starting - Remove --build flag as image is already built in previous step - This fixes 'Can't reach database server at postgres:5432' error * Fix postgres health check in production - Remove init-db.sql volume mount (not available in CI/CD environment) - Init script not needed as Prisma handles schema migrations - Postgres will initialize empty database automatically * Fix cache permission error in Docker container - Create cache directories AFTER copying standalone files - Create both fetch-cache and images subdirectories - Set proper ownership for nextjs user - Fixes EACCES permission denied errors for prerender cache * Fix German jogging fallback text * Use Directus content in production * fix: Security vulnerability - block malicious file requests * fix: Switch projects to Directus, add security fixes and example projects
58 lines
1.8 KiB
TypeScript
58 lines
1.8 KiB
TypeScript
import { NextIntlClientProvider } from "next-intl";
|
|
import { setRequestLocale } from "next-intl/server";
|
|
import React from "react";
|
|
import { notFound } from "next/navigation";
|
|
import ConsentBanner from "../components/ConsentBanner";
|
|
import { getLocalizedMessage } from "@/lib/i18n-loader";
|
|
|
|
// Supported locales - must match middleware.ts
|
|
const SUPPORTED_LOCALES = ["en", "de"] as const;
|
|
type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
|
|
|
|
function isValidLocale(locale: string): locale is SupportedLocale {
|
|
return SUPPORTED_LOCALES.includes(locale as SupportedLocale);
|
|
}
|
|
|
|
async function loadEnhancedMessages(locale: SupportedLocale) {
|
|
// Lade basis JSON Messages
|
|
const baseMessages = (await import(`../../messages/${locale}.json`)).default;
|
|
|
|
// Erweitere mit Directus (wenn verfügbar)
|
|
// Für jetzt: return base messages, Directus wird per Server Component geladen
|
|
return baseMessages;
|
|
}
|
|
|
|
// Define valid static params to prevent malicious path traversal
|
|
export function generateStaticParams() {
|
|
return SUPPORTED_LOCALES.map((locale) => ({ locale }));
|
|
}
|
|
|
|
export default async function LocaleLayout({
|
|
children,
|
|
params,
|
|
}: {
|
|
children: React.ReactNode;
|
|
params: Promise<{ locale: string }>;
|
|
}) {
|
|
const { locale } = await params;
|
|
|
|
// Security: Validate locale to prevent malicious imports
|
|
if (!isValidLocale(locale)) {
|
|
notFound();
|
|
}
|
|
|
|
// Ensure next-intl actually uses the route segment locale for this request.
|
|
setRequestLocale(locale);
|
|
// Load messages explicitly by route locale to avoid falling back to the wrong
|
|
// language when request-level locale detection is unavailable/misconfigured.
|
|
const messages = await loadEnhancedMessages(locale);
|
|
|
|
return (
|
|
<NextIntlClientProvider locale={locale} messages={messages}>
|
|
{children}
|
|
<ConsentBanner />
|
|
</NextIntlClientProvider>
|
|
);
|
|
}
|
|
|