import type { Metadata } from "next"; import { NextIntlClientProvider } from "next-intl"; import { getMessages, getTranslations, setRequestLocale, } from "next-intl/server"; import { notFound } from "next/navigation"; import { routing } from "@/i18n/routing"; import { SiteHeader } from "@/components/layout/site-header"; import { SiteFooter } from "@/components/layout/site-footer"; import { siteConfig } from "@/lib/site-config"; /** * 语言段布局。 * * 文档骨架( / )由根布局 app/layout.tsx 提供, * 这里只负责:校验 locale、注入 i18n Provider、渲染站点壳(页头 / 页脚)。 * * 注意:因为根布局固定了 ,实际请求语言通过 * `app/[locale]/layout.tsx` 无法直接改写 ;如需精确的 lang 属性, * 参见 README 的「已知限制」一节。 */ /** 预生成所有语言的路由 */ export function generateStaticParams() { return routing.locales.map((locale) => ({ locale })); } type Locale = (typeof routing.locales)[number]; type LocaleLayoutProps = { children: React.ReactNode; params: Promise<{ locale: string }>; }; /** 校验 locale 合法性,非法则交给 404 */ function assertLocale(locale: string): asserts locale is Locale { if (!routing.locales.includes(locale as Locale)) { notFound(); } } export async function generateMetadata({ params, }: { params: Promise<{ locale: string }>; }): Promise { const { locale } = await params; assertLocale(locale); const t = await getTranslations({ locale, namespace: "Site" }); const title = `${siteConfig.name} · ${t("tagline")}`; return { title: { default: title, template: `%s · ${siteConfig.name}`, }, description: siteConfig.description, alternates: { canonical: `/${locale}`, languages: Object.fromEntries( routing.locales.map((item) => [item, `/${item}`]), ), }, openGraph: { type: "website", siteName: siteConfig.name, locale, url: `${siteConfig.url}/${locale}`, title, description: siteConfig.description, images: [{ url: siteConfig.ogImage }], }, twitter: { card: "summary_large_image", title, description: siteConfig.description, images: [siteConfig.ogImage], }, }; } export default async function LocaleLayout({ children, params, }: LocaleLayoutProps) { const { locale } = await params; assertLocale(locale); // 启用静态渲染(next-intl 要求显式声明当前请求的 locale) setRequestLocale(locale); const messages = await getMessages(); const t = await getTranslations({ locale, namespace: "Nav" }); return ( {t("skipToContent")}
{children}
); }