Files
sage-home/app/[locale]/line/[slug]/page.tsx
砂糖 e7a428d8f0 feat(i18n): 更新中英文翻译及国际化支持
- 在Workshop和Line模块中添加新的翻译字段
- 修复页面中硬编码的文本,改为使用翻译
- 更新产品线和车间展示的英文翻译内容
- 为卡片组件添加locale属性传递
2026-02-03 17:18:13 +08:00

147 lines
4.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { LOCALES } from "@/i18n/routing";
import { getLine, getLines } from "@/lib/lines";
import { constructMetadata } from "@/lib/metadata";
import { Line } from "@/types/line";
import { Metadata } from "next";
import { Locale } from "next-intl";
import { getTranslations } from "next-intl/server";
// 强制静态渲染
export const dynamic = "force-static";
// 固定 Params 类型为普通对象Next.js 原生传参无异步)
type Params = {
locale: string;
slug: string;
};
type MetadataProps = {
params: Params;
};
export async function generateMetadata({
params,
}: MetadataProps): Promise<Metadata> {
const { locale, slug } = await params;
const line = await getLine(locale, slug);
if (!line) {
return constructMetadata({
title: "404 - 产线不存在",
description: "请求的产线页面未找到",
noIndex: true,
locale: locale as Locale,
path: `/line/${slug}`,
canonicalUrl: `/line/${slug}`,
});
}
return constructMetadata({
title: line.title,
description: line.desc,
locale: locale as Locale,
path: `/line/${slug}`,
canonicalUrl: `/line/${slug}`,
});
}
// 页面主组件 - 仅保留字段展示+修复 Hydration 错误
export default async function ProductDetailPage({ params }: { params: Params }) {
const { locale, slug } = await params;
const line = await getLine(locale, slug);
const t = await getTranslations({ locale, namespace: "Line" });
if (!line) return <div className="p-6">404 - 线</div>;
return (
<div className="product-detail max-w-7xl mx-auto p-6 md:p-8">
{/* 标题和描述区域,分为左右布局 */}
<div className="grid grid-cols-1 md:grid-cols-2 gap-8 mb-12">
{/* 左侧:标题和描述 */}
<div>
<h1 className="text-4xl md:text-5xl font-bold text-gray-800 mb-4">
{line.title}
</h1>
<p className="text-gray-700 text-lg md:text-xl mb-8 leading-relaxed">
{line.desc}
</p>
</div>
{/* 右侧:封面图 */}
{line.cover && (
<div className="relative rounded-lg overflow-hidden shadow-lg">
<img
src={line.cover}
alt={`${line.title} - 封面`}
className="w-full h-auto object-cover transition-transform duration-300 hover:scale-105"
loading="lazy"
/>
</div>
)}
</div>
{/* 产品图片列表区域 */}
{line.images && line.images.length > 0 && (
<div className="mb-12">
<h2 className="text-2xl md:text-3xl font-semibold text-gray-800 mb-6">
{t("productImages")}
</h2>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6">
{line.images.map((imgUrl, index) => (
<div key={index} className="rounded-xl overflow-hidden shadow-md transition-all duration-300 hover:shadow-xl">
<img
src={imgUrl}
alt={`${line.title} - 图片${index + 1}`}
className="w-full h-auto object-cover"
loading="lazy"
/>
</div>
))}
</div>
</div>
)}
{/* 产品特性/参数区域 */}
{line.properties && line.properties.length > 0 && (
<div className="mb-12">
<h2 className="text-2xl md:text-3xl font-semibold text-gray-800 mb-6">
{t("productProperties")}
</h2>
<ul className="space-y-4">
{line.properties.map((prop, index) => (
<li
key={index}
className="p-6 bg-gray-50 rounded-lg shadow-sm hover:shadow-lg transition-all duration-200"
>
{/* 处理参数中的换行符 \n */}
<span
dangerouslySetInnerHTML={{
__html: prop.replace(/\n/g, "<br />"),
}}
/>
</li>
))}
</ul>
</div>
)}
</div>
);
}
export async function generateStaticParams() {
try {
const defaultLocale = LOCALES[0];
const lines: Line[] = await getLines(defaultLocale);
return LOCALES.flatMap((locale) =>
lines.map((line) => ({
locale,
slug: line.slug as string,
}))
);
} catch (error) {
console.error("生成产线静态参数失败:", error);
return [];
}
}