fix: 语言切换全面修复 —— 品牌层/主题首页/详情区块/404 全量 i18n(zh 矩阵 13/13)
- 站点品牌双语:每站 brandZh(品牌名/标语/hero/导航/页脚/搜索占位)由生成器写入 站点 messages 的 zh 覆盖;SiteChrome 改为 async getTranslations 按语言渲染 - 五套主题首页接线 siteHome/hero 命名空间(新增 wire-theme-i18n.py 一次性接线脚本, 仅处理组件函数体、hook 自动插入、hero 用 th 命名空间) - 详情页 Use cases/Good for/FAQ/reviewCta、用例与合集索引与详情、提交页、 对比页、Alternatives 表头与 FAQ 全部走 next-intl - 404 双语言:locale 内走 next-intl,根级按 Accept-Language - 修复 zh.json 中 84 处 zhXxx 旁挂键归位 + en.json 残留清理(i18n 694 键一致) - 回归:/zh 下 13 页全中文无英文残留、无横向溢出;五站 /zh lang=zh 全部正确
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
// 自动生成:站点首页组件(源自底座 classic 形态,品牌来自 @/site/brand)
|
||||
import { siteConfig } from "@/site/brand";
|
||||
import { Search, TrendingUp, Sparkles, Clock, Award, LayoutGrid, MessageSquareQuote } from "lucide-react";
|
||||
import { getTranslations } from "next-intl/server";
|
||||
import { ToolCard, ToolCardGrid } from "@/components/tool-card";
|
||||
import { LocaleLink } from "@/components/locale-link";
|
||||
import { SectionHeader } from "@/kit/section";
|
||||
@@ -50,6 +51,8 @@ const footerGroups = [
|
||||
];
|
||||
|
||||
async function SiteHome({ locale }: { locale: string }) {
|
||||
const t = await getTranslations("siteHome");
|
||||
const th = await getTranslations("hero");
|
||||
const data = await getHomeDataSafe(8);
|
||||
|
||||
return (
|
||||
@@ -58,17 +61,17 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
<section className="border-b border-border bg-gradient-to-b from-secondary/40 to-background">
|
||||
<div className="mx-auto max-w-7xl px-4 py-16 text-center sm:px-6 md:py-24">
|
||||
<h1 className="mx-auto max-w-3xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
|
||||
{siteConfig.brand.headline}
|
||||
{th("title")}
|
||||
</h1>
|
||||
<p className="mx-auto mt-4 max-w-2xl text-sm text-muted-foreground sm:text-base">
|
||||
{siteConfig.brand.subheadline}
|
||||
{th("description")}
|
||||
</p>
|
||||
<form action={`/${locale}/tools`} className="mx-auto mt-8 max-w-xl">
|
||||
<div className="relative">
|
||||
<Search className="absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
||||
<input
|
||||
name="search"
|
||||
placeholder="Search 1,000+ AI tools..."
|
||||
placeholder={t("searchPlaceholder")}
|
||||
className="h-12 w-full rounded-full border border-border bg-background pl-11 pr-28 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/30"
|
||||
aria-label="Search AI tools"
|
||||
/>
|
||||
@@ -76,13 +79,13 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
type="submit"
|
||||
className="absolute right-1.5 top-1.5 h-9 rounded-full bg-primary px-5 text-xs font-semibold text-primary-foreground transition-opacity hover:opacity-90"
|
||||
>
|
||||
Search
|
||||
{t("searchButton")}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground">
|
||||
<span>Popular:</span>
|
||||
{["writing", "video", "coding", "image"].map((q) => (
|
||||
<span>{t("popularLabel")}</span>
|
||||
{t.raw("popularSearches").map((q: string) => (
|
||||
<LocaleLink
|
||||
key={q}
|
||||
href={`/tools?search=${q}`}
|
||||
@@ -100,10 +103,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
{data.trending.length > 0 && (
|
||||
<section>
|
||||
<SectionHeader
|
||||
title="Trending this week"
|
||||
subtitle="Ranked by votes, reviews and engagement over the last 7 days"
|
||||
title={t("trendingTitle")}
|
||||
subtitle={t("trendingSubtitle")}
|
||||
viewAllHref="/rankings?board=trending"
|
||||
viewAllLabel="All rankings"
|
||||
viewAllLabel={t("allRankings")}
|
||||
/>
|
||||
<ToolCardGrid tools={data.trending} locale={locale} ranked />
|
||||
</section>
|
||||
@@ -113,9 +116,9 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
{data.categories.length > 0 && (
|
||||
<section>
|
||||
<SectionHeader
|
||||
title="Browse by category"
|
||||
title={t("categoriesTitle")}
|
||||
viewAllHref="/tools"
|
||||
viewAllLabel="All tools"
|
||||
viewAllLabel={t("categoriesViewAll")}
|
||||
/>
|
||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
|
||||
{data.categories.slice(0, 10).map((category) => (
|
||||
@@ -144,7 +147,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
{data.newest.length > 0 && (
|
||||
<section>
|
||||
<SectionHeader
|
||||
title="New AI tools"
|
||||
title={t("newTitle")}
|
||||
viewAllHref="/rankings?board=new"
|
||||
/>
|
||||
<ToolCardGrid tools={data.newest.slice(0, 4)} locale={locale} />
|
||||
@@ -153,7 +156,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
{data.editorsChoice.length > 0 && (
|
||||
<section>
|
||||
<SectionHeader
|
||||
title="Editor's Choice"
|
||||
title={t("editorsTitle")}
|
||||
viewAllHref="/rankings?board=editors-choice"
|
||||
/>
|
||||
<ToolCardGrid tools={data.editorsChoice.slice(0, 4)} locale={locale} />
|
||||
@@ -165,10 +168,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
{data.useCases.length > 0 && (
|
||||
<section>
|
||||
<SectionHeader
|
||||
title="Tools by use case"
|
||||
subtitle="What do you want to get done?"
|
||||
title={t("useCasesTitle")}
|
||||
subtitle={t("useCasesSubtitle")}
|
||||
viewAllHref="/ai-tools-for"
|
||||
viewAllLabel="All use cases"
|
||||
viewAllLabel={t("useCasesViewAll")}
|
||||
/>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{data.useCases.slice(0, 12).map((uc) => (
|
||||
@@ -191,10 +194,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
{data.collections.length > 0 && (
|
||||
<section>
|
||||
<SectionHeader
|
||||
title="Best AI tool lists"
|
||||
subtitle="Curated rankings by our editors"
|
||||
title={t("bestListsTitle")}
|
||||
subtitle={t("bestListsSubtitle")}
|
||||
viewAllHref="/best"
|
||||
viewAllLabel="All lists"
|
||||
viewAllLabel={t("bestListsViewAll")}
|
||||
/>
|
||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{data.collections.slice(0, 3).map((col) => (
|
||||
@@ -222,7 +225,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
||||
{/* Latest Reviews */}
|
||||
{data.latestReviews.length > 0 && (
|
||||
<section>
|
||||
<SectionHeader title="Latest community reviews" />
|
||||
<SectionHeader title={t("reviewsTitle")} />
|
||||
<div className="grid gap-3 md:grid-cols-2">
|
||||
{data.latestReviews.map((review, i) => (
|
||||
<LocaleLink
|
||||
|
||||
Reference in New Issue
Block a user