fix: 修复 AI 搜索跳转后 async/await 客户端组件错误

将 ProjectCard 和 SubmitProjectCard 从 async 组件重构为普通组件,
通过 props 接收翻译文本,解决在客户端组件中使用 async 组件导致的错误。

- 移除 ProjectCard 和 SubmitProjectCard 的 async 关键字
- 添加 translations prop 接收翻译文本
- 更新所有调用点传递翻译文本

Co-Authored-By: Claude (glm-4.7) <noreply@anthropic.com>
This commit is contained in:
2026-01-27 17:22:21 +08:00
co-authored by Claude
parent b03085292a
commit 6c13fc54d6
5 changed files with 69 additions and 16 deletions
@@ -24,6 +24,12 @@ interface ProjectsPageClientProps {
searching: string
aiHint: string
traditionalHint: string
translations: {
viewDetails: string
submitProjectTitle: string
submitProjectDescription: string
submitNow: string
}
}
export function ProjectsPageClient({
@@ -38,6 +44,7 @@ export function ProjectsPageClient({
searching,
aiHint,
traditionalHint,
translations,
}: ProjectsPageClientProps) {
const searchParams = useSearchParams()
const [aiResults, setAiResults] = useState<AISearchResult[]>([])
@@ -150,7 +157,7 @@ export function ProjectsPageClient({
<p className="text-red-700 dark:text-red-400 font-display text-sm">{error}</p>
</div>
)}
<AISearchResults results={aiResults} locale={locale} />
<AISearchResults results={aiResults} locale={locale} translations={translations} />
</>
) : (
children
+10
View File
@@ -16,6 +16,7 @@ export default async function ProjectsPage({
}: ProjectsPageProps) {
const t = await getTranslations('home')
const tCommon = await getTranslations('common')
const tProject = await getTranslations('project')
const [resolvedParams, resolvedSearchParams] = await Promise.all([params, searchParams])
const { locale } = resolvedParams
@@ -29,6 +30,14 @@ export default async function ProjectsPage({
getAllTags(), // 获取所有标签(用于展开)
])
// 准备翻译文本传递给客户端组件
const translations = {
viewDetails: tCommon('viewDetails'),
submitProjectTitle: tProject('submitProjectTitle'),
submitProjectDescription: tProject('submitProjectDescription'),
submitNow: tProject('submitNow'),
}
return (
<main className="container mx-auto px-4 py-12 md:py-16 max-w-7xl">
{/* Search and Filter Section */}
@@ -45,6 +54,7 @@ export default async function ProjectsPage({
searching={tCommon('searching')}
aiHint={tCommon('aiHint')}
traditionalHint={tCommon('traditionalHint')}
translations={translations}
>
{/* Tag Cloud - rendered inside client component for non-AI mode */}
<div className="border-t-2 border-gray-100 dark:border-gray-800 pt-6 mt-8">
+25 -9
View File
@@ -1,6 +1,5 @@
import Link from 'next/link'
import Image from 'next/image'
import { getTranslations } from 'next-intl/server'
import { GitHubStatsCompact } from './GitHubBadges'
import { getGitHubBadgesFromLinks } from '@/lib/github/badges'
@@ -27,6 +26,10 @@ interface ProjectCardProps {
}
locale: string
featured?: boolean
// 新增:通过 props 接收翻译文本,支持客户端组件使用
translations?: {
viewDetails: string
}
}
// Icon mapping for projects based on tags
@@ -42,8 +45,9 @@ function getProjectIcon(tags: Array<{ name: string | null }>): string {
return '✨'
}
export async function ProjectCard({ project, locale, featured = false }: ProjectCardProps) {
const t = await getTranslations('common')
export function ProjectCard({ project, locale, featured = false, translations }: ProjectCardProps) {
// 使用传入的翻译文本,如果没有提供则使用默认值
const viewDetailsText = translations?.viewDetails || 'View Details'
const icon = getProjectIcon(project.tags)
const displayName = locale === 'en' && project.nameEn ? project.nameEn : project.name
const displayDescription = locale === 'en' && project.descriptionEn ? project.descriptionEn : project.description
@@ -94,7 +98,7 @@ export async function ProjectCard({ project, locale, featured = false }: Project
href={`/${locale}/projects/${project.slug}`}
className="inline-flex items-center font-display font-bold text-sm uppercase hover:text-secondary dark:hover:text-primary group"
>
{t('viewDetails')}{' '}
{viewDetailsText}{' '}
<span className="ml-1 transform group-hover:translate-x-1 transition-transform"></span>
</Link>
@@ -121,22 +125,34 @@ export async function ProjectCard({ project, locale, featured = false }: Project
}
// Special card for "Submit Your Project" CTA
export async function SubmitProjectCard({ locale }: { locale: string }) {
const t = await getTranslations('project')
interface SubmitProjectCardProps {
locale: string
translations?: {
submitProjectTitle: string
submitProjectDescription: string
submitNow: string
}
}
export function SubmitProjectCard({ locale, translations }: SubmitProjectCardProps) {
const submitProjectTitle = translations?.submitProjectTitle || 'Submit Your Project'
const submitProjectDescription = translations?.submitProjectDescription || 'Help us grow the AI ecosystem'
const submitNow = translations?.submitNow || 'Submit Now'
return (
<article className="bg-primary border-2 border-black dark:border-gray-600 p-6 shadow-neo hover:shadow-neo-hover hover:-translate-y-1 transition-all duration-200 flex flex-col h-full justify-center items-center text-center group">
<div className="bg-white dark:bg-black p-4 rounded-full border-2 border-black mb-4 group-hover:scale-110 transition-transform">
<span className="text-3xl dark:text-primary">+</span>
</div>
<h3 className="font-display text-xl md:text-2xl font-bold text-black mb-2">{t('submitProjectTitle')}</h3>
<h3 className="font-display text-xl md:text-2xl font-bold text-black mb-2">{submitProjectTitle}</h3>
<p className="text-black mb-6 font-sans text-sm px-4">
{t('submitProjectDescription')}
{submitProjectDescription}
</p>
<Link
href="#"
className="bg-black text-white dark:bg-black dark:text-primary border-2 border-black dark:border-black px-6 py-2 font-display text-sm font-bold uppercase hover:bg-white hover:text-black dark:hover:bg-white dark:hover:text-black transition-colors"
>
{t('submitNow')}
{submitNow}
</Link>
</article>
)
+18 -4
View File
@@ -21,12 +21,13 @@ interface ProjectListProps {
}
export async function ProjectList({ projects, locale, featured = false }: ProjectListProps) {
const t = await getTranslations('common')
const tCommon = await getTranslations('common')
const tProject = await getTranslations('project')
if (projects.length === 0) {
return (
<div className="text-center py-12">
<p className="text-gray-500 dark:text-gray-400 font-display">{t('noProjects')}</p>
<p className="text-gray-500 dark:text-gray-400 font-display">{tCommon('noProjects')}</p>
</div>
)
}
@@ -34,12 +35,25 @@ export async function ProjectList({ projects, locale, featured = false }: Projec
return (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{projects.map((project) => (
<ProjectCard key={project.id} project={project} locale={locale} featured={featured} />
<ProjectCard
key={project.id}
project={project}
locale={locale}
featured={featured}
translations={{ viewDetails: tCommon('viewDetails') }}
/>
))}
{/* Add "Submit Your Project" CTA card for featured section */}
{featured && (
<SubmitProjectCard locale={locale} />
<SubmitProjectCard
locale={locale}
translations={{
submitProjectTitle: tProject('submitProjectTitle'),
submitProjectDescription: tProject('submitProjectDescription'),
submitNow: tProject('submitNow'),
}}
/>
)}
</div>
)
+8 -2
View File
@@ -12,9 +12,15 @@ interface AISearchResult {
interface AISearchResultsProps {
results: AISearchResult[]
locale: string
translations: {
viewDetails: string
submitProjectTitle: string
submitProjectDescription: string
submitNow: string
}
}
export function AISearchResults({ results, locale }: AISearchResultsProps) {
export function AISearchResults({ results, locale, translations }: AISearchResultsProps) {
if (results.length === 0) {
return (
<div className="text-center py-12 px-4 bg-surface-light dark:bg-surface-dark border-2 border-dashed border-gray-300 dark:border-gray-700 rounded-lg">
@@ -51,7 +57,7 @@ export function AISearchResults({ results, locale }: AISearchResultsProps) {
{/* 项目卡片 */}
<div className="ml-3">
<ProjectCard project={project} locale={locale} />
<ProjectCard project={project} locale={locale} translations={translations} />
{/* AI 匹配信息 */}
<div className="mt-3 px-4 py-3 bg-yellow-50 dark:bg-yellow-900/20 border-l-4 border-yellow-400 dark:border-yellow-500 rounded-r">