91 lines
3.2 KiB
TypeScript
91 lines
3.2 KiB
TypeScript
|
|
import fs from 'fs';
|
||
|
|
import path from 'path';
|
||
|
|
import matter from 'gray-matter';
|
||
|
|
import { remark } from 'remark';
|
||
|
|
import html from 'remark-html';
|
||
|
|
import { notFound } from 'next/navigation';
|
||
|
|
import { useTranslation } from '../../../lib/i18n/useTranslation';
|
||
|
|
import { languages } from '../../../lib/i18n/config';
|
||
|
|
|
||
|
|
const NEWS_DIR = path.join(process.cwd(), 'content/news');
|
||
|
|
|
||
|
|
export async function generateStaticParams() {
|
||
|
|
const files = fs.readdirSync(NEWS_DIR);
|
||
|
|
return files.map((file) => ({ id: file.replace(/\.md$/, '') }));
|
||
|
|
}
|
||
|
|
|
||
|
|
async function getNewsData(id: string) {
|
||
|
|
const filePath = path.join(NEWS_DIR, `${id}.md`);
|
||
|
|
if (!fs.existsSync(filePath)) return null;
|
||
|
|
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
||
|
|
const { data, content } = matter(fileContent);
|
||
|
|
|
||
|
|
// 提取多语言正文
|
||
|
|
const langSections: Record<string, string> = {};
|
||
|
|
let currentLang = '';
|
||
|
|
let buffer: string[] = [];
|
||
|
|
for (const line of content.split('\n')) {
|
||
|
|
const langMatch = line.match(/^##\s*(\w[\w-]*)/);
|
||
|
|
if (langMatch) {
|
||
|
|
if (currentLang && buffer.length) {
|
||
|
|
langSections[currentLang] = buffer.join('\n').trim();
|
||
|
|
}
|
||
|
|
currentLang = langMatch[1];
|
||
|
|
buffer = [];
|
||
|
|
} else if (currentLang) {
|
||
|
|
buffer.push(line);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if (currentLang && buffer.length) {
|
||
|
|
langSections[currentLang] = buffer.join('\n').trim();
|
||
|
|
}
|
||
|
|
|
||
|
|
return { frontmatter: data, langSections };
|
||
|
|
}
|
||
|
|
|
||
|
|
export default async function NewsDetailPage({ params }: { params: { id: string } }) {
|
||
|
|
const { id } = params;
|
||
|
|
const news = await getNewsData(id);
|
||
|
|
if (!news) return notFound();
|
||
|
|
|
||
|
|
// 默认语言优先级
|
||
|
|
const langOrder = ['en', 'zh-CN', 'zh-TW'];
|
||
|
|
// 这里假设 SSR 时用 Accept-Language 或默认 en
|
||
|
|
let lang = langOrder.find((l) => news.langSections[l]);
|
||
|
|
let htmlContent = '';
|
||
|
|
if (lang) {
|
||
|
|
htmlContent = (await remark().use(html).process(news.langSections[lang])).toString();
|
||
|
|
}
|
||
|
|
|
||
|
|
// 渲染页面
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
className="min-h-screen bg-gradient-to-br from-blue-50 via-indigo-50 to-purple-50"
|
||
|
|
data-oid="7k5q43s"
|
||
|
|
>
|
||
|
|
<div className="max-w-4xl mx-auto py-16 px-4" data-oid="7y520yg">
|
||
|
|
<h1 className="text-4xl font-bold mb-4" data-oid="pj.he2s">
|
||
|
|
{news.frontmatter[`title_${lang}`] || news.frontmatter.title}
|
||
|
|
</h1>
|
||
|
|
<div className="text-gray-500 mb-2" data-oid="rgvpuvi">
|
||
|
|
{news.frontmatter.date} · {news.frontmatter.readTime} ·{' '}
|
||
|
|
{news.frontmatter.category}
|
||
|
|
</div>
|
||
|
|
<div className="mb-6" data-oid="dwkw1qu">
|
||
|
|
<img
|
||
|
|
src={news.frontmatter.image}
|
||
|
|
alt={news.frontmatter.title}
|
||
|
|
className="rounded-xl w-full h-80 object-cover"
|
||
|
|
data-oid="qdo4b98"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
<div
|
||
|
|
className="prose prose-lg max-w-none"
|
||
|
|
dangerouslySetInnerHTML={{ __html: htmlContent }}
|
||
|
|
data-oid="by0i9t7"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|