feat: 添加关键词词云页面国际化支持

This commit is contained in:
2026-01-27 20:39:38 +08:00
parent 9164086d6e
commit e1f250d397
5 changed files with 82 additions and 15 deletions
@@ -15,12 +15,15 @@ export interface KeywordData {
word: string;
trendScore: number;
description: string;
descriptionEn?: string | null;
detailPoints: string[];
detailPointsEn?: string[] | null;
visualConfig: VisualConfig;
}
interface CloudWordProps {
data: KeywordData;
locale: string;
}
// 颜色映射
@@ -31,11 +34,15 @@ const colorMap: Record<string, string> = {
gray: 'bg-gray-100 dark:bg-gray-700',
};
export function CloudWord({ data }: CloudWordProps) {
const { word, visualConfig, description, detailPoints } = data;
export function CloudWord({ data, locale }: CloudWordProps) {
const { word, visualConfig, description, descriptionEn, detailPoints, detailPointsEn } = data;
const { color, size, border, rotation } = visualConfig;
const colorClass = colorMap[color];
// 根据语言选择内容
const displayDescription = locale === 'en' && descriptionEn ? descriptionEn : description;
const displayPoints = locale === 'en' && detailPointsEn ? detailPointsEn : detailPoints;
return (
<span
className={cn(
@@ -63,8 +70,8 @@ export function CloudWord({ data }: CloudWordProps) {
{word}
<WordPopover
title={word}
description={description}
points={detailPoints}
description={displayDescription}
points={displayPoints}
titleColor={color}
/>
</span>
@@ -6,7 +6,18 @@ import { QuarterNavigator } from './QuarterNavigator';
import { ProgressIndicator } from './ProgressIndicator';
import { useKeywordCloud } from '@/hooks/useKeywordCloudClient';
export function KeywordCloud({ initialQuarter }: { initialQuarter: string }) {
interface KeywordCloudProps {
initialQuarter: string;
locale: string;
texts: {
loading: string;
loadFailed: string;
retry: string;
hotKeyword: string;
};
}
export function KeywordCloud({ initialQuarter, locale, texts }: KeywordCloudProps) {
const [currentQuarter, setCurrentQuarter] = useState(initialQuarter);
const [quarters, setQuarters] = useState<string[]>([]);
const { data, isLoading, error } = useKeywordCloud(currentQuarter);
@@ -41,7 +52,7 @@ export function KeywordCloud({ initialQuarter }: { initialQuarter: string }) {
<div className="flex items-center justify-center min-h-[400px]">
<div className="text-center">
<div className="inline-block animate-spin rounded-full h-12 w-12 border-4 border-black border-t-primary mb-4" />
<p className="font-display font-bold text-lg">...</p>
<p className="font-display font-bold text-lg">{texts.loading}</p>
</div>
</div>
);
@@ -52,13 +63,13 @@ export function KeywordCloud({ initialQuarter }: { initialQuarter: string }) {
<div className="flex items-center justify-center min-h-[400px]">
<div className="text-center">
<p className="font-display font-bold text-lg text-red-500 mb-4">
{texts.loadFailed}
</p>
<button
onClick={() => window.location.reload()}
className="bg-primary text-black border-2 border-black px-4 py-2 font-bold hover:bg-yellow-500 transition-colors"
>
{texts.retry}
</button>
</div>
</div>
@@ -87,7 +98,7 @@ export function KeywordCloud({ initialQuarter }: { initialQuarter: string }) {
<div className="relative py-12 px-4">
<div className="word-cluster flex flex-wrap gap-3 items-center justify-center max-w-full">
{data.keywords.map((keyword) => (
<CloudWord key={keyword.id} data={keyword} />
<CloudWord key={keyword.id} data={keyword} locale={locale} />
))}
</div>
</div>
@@ -95,7 +106,7 @@ export function KeywordCloud({ initialQuarter }: { initialQuarter: string }) {
{/* 装饰元素 */}
{data.keywords.length > 0 && firstKeyword && (
<div className="absolute -top-16 -right-8 md:right-0 bg-black text-white p-5 rounded-xl text-sm md:text-base font-display w-64 shadow-hard rotate-6 hidden lg:block">
&ldquo;{firstKeyword.word}&rdquo; !
{texts.hotKeyword.replace('{word}', firstKeyword.word)}
<div className="absolute -bottom-2 left-1/2 -translate-x-1/2 w-4 h-4 bg-black transform rotate-45" />
</div>
)}
+30 -5
View File
@@ -1,4 +1,5 @@
import { KeywordCloud } from './components/KeywordCloud';
import { getTranslations } from 'next-intl/server';
interface PageProps {
params: {
@@ -9,27 +10,51 @@ interface PageProps {
};
}
export default function KeywordCloudPage({ searchParams }: PageProps) {
export async function generateMetadata({
params
}: {
params: Promise<{ locale: string }>
}) {
const { locale } = await params;
const t = await getTranslations('keywordCloud');
return {
title: t('metaTitle'),
description: t('metaDescription'),
};
}
export default async function KeywordCloudPage({ searchParams, params }: PageProps) {
const { locale } = await params;
const t = await getTranslations('keywordCloud');
// 如果 URL 中有 quarter 参数,使用它;否则使用默认季度
const quarter = searchParams.quarter || '2024-Q1';
const texts = {
loading: t('loading'),
loadFailed: t('loadFailed'),
retry: t('retry'),
hotKeyword: t('hotKeyword'),
};
return (
<main className="relative z-10 max-w-6xl mx-auto px-4 pb-32 overflow-visible">
{/* 页面标题 */}
<header className="relative z-10 pt-16 pb-8 text-center max-w-4xl mx-auto px-4">
<div className="inline-block bg-accent dark:bg-purple-700 border-2 border-black px-3 py-1 font-display font-bold text-xs mb-4 shadow-hard-sm rotate-[-2deg]">
AI
{t('badge')}
</div>
<h1 className="font-display text-5xl md:text-7xl font-bold mb-6 tracking-tighter leading-tight">
AI <span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-500 to-purple-500" style={{ WebkitTextStroke: '1.5px black' }}></span>
{t('title')} <span className="text-transparent bg-clip-text bg-gradient-to-r from-blue-500 to-purple-500" style={{ WebkitTextStroke: '1.5px black' }}>{t('titleHighlight')}</span>
</h1>
<p className="text-lg md:text-xl max-w-2xl mx-auto font-medium text-gray-700 dark:text-gray-300 mb-8">
&ldquo;&rdquo; &ldquo;Agent &rdquo; AI
{t('subtitle')}
</p>
</header>
{/* 词云组件 */}
<KeywordCloud initialQuarter={quarter} />
<KeywordCloud initialQuarter={quarter} locale={locale} texts={texts} />
</main>
);
}
+12
View File
@@ -95,5 +95,17 @@
"followUs": "Follow Us",
"copyright": "© 2025 Agent Park. All rights reserved.",
"designedFor": "DESIGNED FOR AI BUILDERS"
},
"keywordCloud": {
"metaTitle": "AI Hotspot Word Cloud - Agent Park",
"metaDescription": "Explore the evolution of quarterly AI hotspots, from Large Language Models to Agent Workflows",
"badge": "AI Trend Tracker",
"title": "Quarterly AI",
"titleHighlight": "Hotspot Word Cloud",
"subtitle": "From &ldquo;Large Language Models&rdquo; to &ldquo;Agent Workflows&rdquo;. Explore the evolution of AI discourse.",
"loading": "Loading...",
"loadFailed": "Failed to load",
"retry": "Retry",
"hotKeyword": "&ldquo;{word}&rdquo; is the hottest keyword this quarter!"
}
}
+12
View File
@@ -95,5 +95,17 @@
"followUs": "关注我们",
"copyright": "© 2025 Agent Park. 保留所有权利。",
"designedFor": "专为 AI 构建者设计"
},
"keywordCloud": {
"metaTitle": "AI 热点词云 - Agent Park",
"metaDescription": "探索季度 AI 热点词汇的演变历程,从大型语言模型到 Agent 工作流",
"badge": "AI 热点追踪",
"title": "季度 AI",
"titleHighlight": "热点词云",
"subtitle": "从 &ldquo;大型语言模型&rdquo; 到 &ldquo;Agent 工作流&rdquo;。探索 AI 话语的演变历程。",
"loading": "加载中...",
"loadFailed": "加载失败",
"retry": "重试",
"hotKeyword": "&ldquo;{word}&rdquo; 是本季度最热门词汇!"
}
}