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:
AI Directory Platform
2026-09-09 16:59:52 +00:00
parent f4f48f7293
commit 5cc4195d68
50 changed files with 4141 additions and 235 deletions
+16 -13
View File
@@ -1,6 +1,7 @@
// 自动生成:站点首页组件(源自底座 editorial 形态,品牌来自 @/site/brand)
import { siteConfig } from "@/site/brand";
import { BookOpen, PenTool, ArrowRight, Star } from "lucide-react";
import { getTranslations } from "next-intl/server";
import { LocaleLink } from "@/components/locale-link";
import { SectionHeader } from "@/kit/section";
import { getHomeDataSafe } from "@/kit/home-data";
@@ -45,6 +46,8 @@ const footerGroups = [
];
async function SiteHome({ locale }: { locale: string }) {
const t = await getTranslations("siteHome");
const th = await getTranslations("hero");
const data = await getHomeDataSafe(6);
const featured = data.articles[0];
const editorPicks = data.editorsChoice.slice(0, 4);
@@ -55,13 +58,13 @@ async function SiteHome({ locale }: { locale: string }) {
<section className="border-b border-border">
<div className="mx-auto max-w-4xl px-4 py-16 text-center sm:px-6 md:py-20">
<p className="text-xs font-medium uppercase tracking-[0.3em] text-muted-foreground">
Independent AI Coverage
{t("mastheadLabel")}
</p>
<h1 className="mt-4 text-4xl font-bold tracking-tight text-foreground md:text-5xl">
{siteConfig.brand.headline}
{th("title")}
</h1>
<p className="mx-auto mt-4 max-w-xl text-base leading-relaxed text-muted-foreground">
{siteConfig.brand.subheadline}
{th("description")}
</p>
</div>
</section>
@@ -72,7 +75,7 @@ async function SiteHome({ locale }: { locale: string }) {
<section>
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
<BookOpen className="h-3.5 w-3.5" />
Featured story
{t("featuredLabel")}
</div>
<LocaleLink href={`/blog/${featured.slug}`} className="group block">
<h2 className="text-2xl font-bold leading-snug text-foreground group-hover:underline md:text-3xl">
@@ -84,7 +87,7 @@ async function SiteHome({ locale }: { locale: string }) {
</p>
)}
<span className="mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary">
Read the story
{t("featuredRead")}
<ArrowRight className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" />
</span>
</LocaleLink>
@@ -96,7 +99,7 @@ async function SiteHome({ locale }: { locale: string }) {
<section>
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
<PenTool className="h-3.5 w-3.5" />
Editor's picks
{t("picksEditorialLabel")}
</div>
<div className="divide-y divide-border border-y border-border">
{editorPicks.map((tool, i) => (
@@ -132,10 +135,10 @@ async function SiteHome({ locale }: { locale: string }) {
{data.collections.length > 0 && (
<section>
<SectionHeader
title="Buying guides"
subtitle="Deep dives that help you choose"
title={t("guidesTitle")}
subtitle={t("guidesSubtitle")}
viewAllHref="/best"
viewAllLabel="All guides"
viewAllLabel={t("guidesViewAll")}
/>
<div className="grid gap-6 sm:grid-cols-2">
{data.collections.slice(0, 4).map((col) => (
@@ -151,7 +154,7 @@ async function SiteHome({ locale }: { locale: string }) {
{locale === "zh" && col.introZh ? col.introZh : col.introEn}
</p>
<p className="mt-2 text-xs uppercase tracking-wide text-muted-foreground">
{col.toolCount} tools compared
{col.toolCount} {t("toolsCompared")}
</p>
</LocaleLink>
))}
@@ -162,7 +165,7 @@ async function SiteHome({ locale }: { locale: string }) {
{/* Latest articles */}
{data.articles.length > 1 && (
<section>
<SectionHeader title="Latest stories" viewAllHref="/blog" />
<SectionHeader title={t("storiesTitle")} viewAllHref="/blog" />
<div className="grid gap-6 sm:grid-cols-2">
{data.articles.slice(1).map((article) => (
<LocaleLink key={article.slug} href={`/blog/${article.slug}`} className="group">
@@ -184,9 +187,9 @@ async function SiteHome({ locale }: { locale: string }) {
{data.latestReviews.length > 0 && (
<section>
<SectionHeader
title="From the community"
title={t("communityTitle")}
viewAllHref="/tools"
viewAllLabel="Browse directory"
viewAllLabel={t("communityViewAll")}
/>
<div className="grid gap-6 sm:grid-cols-2">
{data.latestReviews.slice(0, 4).map((review, i) => (