NebulaCloud/app/[locale]/layout.tsx
2025-09-15 17:28:58 +08:00

110 lines
3.3 KiB
TypeScript

import type { Metadata } from 'next';
import '../globals.css';
import { locales, Locale, defaultLocale } from '../../lib/i18n';
import { getTranslations } from '../../lib/translations';
import {
generateAlternateLinks,
generateCanonicalUrl,
generateStructuredData,
} from '../../lib/seo-utils';
import { notFound } from 'next/navigation';
export async function generateStaticParams() {
return locales.map((locale) => ({ locale }));
}
export async function generateMetadata({
params,
}: {
params: { locale: Locale };
}): Promise<Metadata> {
const translations = getTranslations(params.locale);
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'https://your-domain.com';
const alternateLinks = generateAlternateLinks('', baseUrl);
const canonicalUrl = generateCanonicalUrl('', params.locale, baseUrl);
return {
title: {
default: translations.meta.title,
template: `%s | ${translations.meta.title}`,
},
description: translations.meta.description,
keywords: translations.meta.keywords,
authors: [{ name: translations.meta.author }],
creator: translations.meta.author,
publisher: translations.meta.author,
formatDetection: {
email: false,
address: false,
telephone: false,
},
metadataBase: new URL(baseUrl),
alternates: {
canonical: canonicalUrl,
languages: Object.fromEntries(alternateLinks.map((link) => [link.hrefLang, link.href])),
},
openGraph: {
title: translations.meta.title,
description: translations.meta.description,
url: canonicalUrl,
siteName: translations.meta.title,
locale: params.locale,
alternateLocale: locales.filter((loc) => loc !== params.locale),
type: 'website',
images: [
{
url: `${baseUrl}/og-image.jpg`,
width: 1200,
height: 630,
alt: translations.meta.title,
},
],
},
twitter: {
card: 'summary_large_image',
title: translations.meta.title,
description: translations.meta.description,
images: [`${baseUrl}/og-image.jpg`],
creator: '@yourtwitterhandle',
},
robots: {
index: true,
follow: true,
googleBot: {
index: true,
follow: true,
'max-video-preview': -1,
'max-image-preview': 'large',
'max-snippet': -1,
},
},
verification: {
google: 'your-google-verification-code',
// Add other search engine verification codes as needed
},
};
}
export default function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: { locale: Locale };
}) {
// Validate that the incoming `locale` parameter is valid
if (!locales.includes(params.locale)) {
notFound();
}
return (
<html lang={params.locale} data-oid="9-vbv6i">
<body className="" data-oid="2snbkeg">
{children}
</body>
</html>
);
}