diff --git a/packages/core/messages/en.json b/packages/core/messages/en.json index 8758fff..024bf77 100644 --- a/packages/core/messages/en.json +++ b/packages/core/messages/en.json @@ -649,7 +649,9 @@ "latest": "Latest", "trending": "Trending" }, - "clearFilters": "Clear search & filters" + "clearFilters": "Clear search & filters", + "useCasesTitle": "Use cases", + "goodForTitle": "Good for" }, "seo": { "home": { @@ -796,5 +798,222 @@ "new": "New", "editorsChoice": "Editor's Choice", "empty": "No tools on this board yet." + }, + "siteHome": { + "trending": { + "title": "Trending this week", + "subtitle": "Ranked by votes, reviews and engagement over the last 7 days" + }, + "categories": { + "title": "Browse by category", + "viewAll": "All tools" + }, + "new": { + "title": "New AI tools" + }, + "editors": { + "title": "Editor's Choice" + }, + "useCases": { + "title": "Tools by use case", + "subtitle": "What do you want to get done?", + "viewAll": "All use cases" + }, + "bestLists": { + "title": "Best AI tool lists", + "subtitle": "Curated rankings by our editors", + "viewAll": "All lists" + }, + "reviews": { + "title": "Latest community reviews" + }, + "cta": { + "title": "Built an AI tool?", + "body": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "button": "Submit your tool" + }, + "popular": { + "label": "Popular:" + }, + "toolsCount": "{count} tools", + "feed": { + "title": "Today's feed", + "browse": "Browse all products" + }, + "leaderboard": { + "title": "Leaderboard", + "full": "Full leaderboard" + }, + "picks": { + "title": "Editor's picks" + }, + "collections": { + "title": "Collections" + }, + "launch": { + "button": "Launch your product" + }, + "featured": { + "label": "Featured story", + "read": "Read the story" + }, + "picksEditorial": { + "label": "Editor's picks" + }, + "guides": { + "title": "Buying guides", + "subtitle": "Deep dives that help you choose", + "viewAll": "All guides" + }, + "stories": { + "title": "Latest stories", + "viewAll": "All stories" + }, + "community": { + "title": "From the community", + "viewAll": "Browse directory" + }, + "ship": { + "title": "Ship faster with AI", + "subtitle": "Pick your workflow — we ranked the tools for it", + "viewAll": "All use cases" + }, + "upvoted": { + "title": "Most upvoted this week", + "viewAll": "View all" + }, + "workflows": { + "title": "Workflows & stacks", + "subtitle": "Batteries-included tool stacks for common dev tasks", + "viewAll": "All workflows" + }, + "browseCategory": { + "title": "Browse by category" + }, + "trendingNow": { + "title": "Trending now" + }, + "seeRankings": "See full rankings", + "browse": "Browse tools", + "noLaunches": "No launches yet — be the first to submit.", + "searchPlaceholder": "Search AI tools...", + "reviewsCount": "{count} reviews", + "mastheadLabel": "INDEPENDENT AI COVERAGE", + "minimalTagline": "AI TOOL SEARCH", + "minimalPlaceholder": "I need to create marketing videos...", + "useCasesBlockTitle": "Use cases", + "goodForBlockTitle": "Good for", + "searchButton": "Search", + "trendingTitle": "Trending this week", + "trendingSubtitle": "Ranked by votes, reviews and engagement over the last 7 days", + "allRankings": "All rankings", + "categoriesTitle": "Browse by category", + "categoriesViewAll": "All tools", + "newTitle": "New AI tools", + "editorsTitle": "Editor's Choice", + "useCasesTitle": "Tools by use case", + "useCasesSubtitle": "What do you want to get done?", + "useCasesViewAll": "All use cases", + "bestListsTitle": "Best AI tool lists", + "bestListsSubtitle": "Curated rankings by our editors", + "bestListsViewAll": "All lists", + "reviewsTitle": "Latest community reviews", + "ctaTitle": "Built an AI tool?", + "ctaBody": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "ctaButton": "Submit your tool", + "popularLabel": "Popular:", + "feedTitle": "Today's feed", + "feedBrowse": "Browse all products", + "leaderboardTitle": "Leaderboard", + "leaderboardFull": "Full leaderboard", + "picksTitle": "Editor's picks", + "collectionsTitle": "Collections", + "launchButton": "Launch your product", + "featuredLabel": "Featured story", + "featuredRead": "Read the story", + "picksEditorialLabel": "EDITOR'S PICKS", + "guidesTitle": "Buying guides", + "guidesSubtitle": "Deep dives that help you choose", + "guidesViewAll": "All guides", + "storiesTitle": "Latest stories", + "storiesViewAll": "All stories", + "communityTitle": "From the community", + "communityViewAll": "Browse directory", + "shipTitle": "Ship faster with AI", + "shipSubtitle": "Pick your workflow — we ranked the tools for it", + "upvotedTitle": "Most upvoted this week", + "upvotedViewAll": "View all", + "workflowsTitle": "Workflows & stacks", + "workflowsSubtitle": "Batteries-included tool stacks for common dev tasks", + "workflowsViewAll": "All workflows", + "browseCategoryTitle": "Browse by category", + "trendingNowTitle": "Trending now", + "browseButton": "Browse tools", + "toolsCompared": "{count} tools compared", + "popularSearches": [ + "writing", + "video", + "coding", + "image" + ] + }, + "best": { + "indexTitle": "Best AI Tools — Curated Lists", + "indexSubtitle": "Hand-picked rankings, updated with community signal. Every list is labeled and never sold.", + "empty": "No collections published yet.", + "curated": "Curated list", + "faq": "Frequently asked questions", + "more": "More best lists", + "toolsCompared": "{count} tools" + }, + "aiToolsFor": { + "indexTitle": "AI tools for what you do", + "indexSubtitle": "Skip the categories. Start from your task or your role — every page ranks tools by real community votes and reviews.", + "byTask": "By task", + "byAudience": "By audience", + "noData": "No use cases yet.", + "noAud": "No audiences yet.", + "noTools": "No tools tagged yet." + }, + "submitPage": { + "title": "Submit your AI tool", + "subtitle": "Get a free listing with community votes, user reviews and analytics. Submissions are reviewed by our editors, usually within 48 hours." + }, + "faq": { + "title": "Frequently asked questions" + }, + "compare": { + "intro": "A side-by-side comparison based on community votes, ratings and reviews — not sponsored placement.", + "leaning": "Right now the community leans toward {name}.", + "label": "Compare", + "noReviews": "—", + "latest": "Latest review" + }, + "alternatives": { + "noAlt": "No alternatives found yet.", + "thisTool": "{name} (this tool)", + "table": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + }, + "zhTable": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + } + }, + "notFound": { + "code": "404", + "title": "Page not found", + "body": "The page you are looking for doesn't exist or may have moved.", + "home": "Back to home", + "tools": "Browse tools" + }, + "search": { + "placeholder": "Search 1,000+ AI tools...", + "button": "Search" } } diff --git a/packages/core/messages/zh.json b/packages/core/messages/zh.json index b0a562f..0359726 100644 --- a/packages/core/messages/zh.json +++ b/packages/core/messages/zh.json @@ -657,7 +657,9 @@ "latest": "最新", "trending": "最热" }, - "clearFilters": "清除搜索与筛选" + "clearFilters": "清除搜索与筛选", + "useCasesTitle": "使用场景", + "goodForTitle": "适合人群" }, "seo": { "home": { @@ -804,5 +806,222 @@ "new": "最新收录", "editorsChoice": "编辑精选", "empty": "该榜单暂无工具。" + }, + "siteHome": { + "trending": { + "title": "本周趋势", + "subtitle": "按最近 7 天投票、评论与互动排名" + }, + "categories": { + "title": "按分类浏览", + "viewAll": "全部工具" + }, + "new": { + "title": "最新收录" + }, + "editors": { + "title": "编辑精选" + }, + "useCases": { + "title": "按用例找工具", + "subtitle": "你想完成什么?", + "viewAll": "全部用例" + }, + "bestLists": { + "title": "最佳 AI 工具清单", + "subtitle": "编辑精选排名", + "viewAll": "全部清单" + }, + "reviews": { + "title": "最新社区评论" + }, + "cta": { + "title": "做了 AI 工具?", + "body": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "button": "提交你的工具" + }, + "popular": { + "label": "热门:" + }, + "toolsCount": "{count} 个工具", + "feed": { + "title": "今日发布流", + "browse": "浏览全部产品" + }, + "leaderboard": { + "title": "排行榜", + "full": "完整榜单" + }, + "picks": { + "title": "编辑推荐" + }, + "collections": { + "title": "合集" + }, + "launch": { + "button": "发布你的产品" + }, + "featured": { + "label": "头条文章", + "read": "阅读全文" + }, + "picksEditorial": { + "label": "编辑推荐" + }, + "guides": { + "title": "选购指南", + "subtitle": "帮你做决定的深度对比", + "viewAll": "全部指南" + }, + "stories": { + "title": "最新文章", + "viewAll": "全部文章" + }, + "community": { + "title": "来自社区", + "viewAll": "浏览目录" + }, + "ship": { + "title": "用 AI 加速交付", + "subtitle": "选好工作流,我们为它排好了工具", + "viewAll": "全部用例" + }, + "upvoted": { + "title": "本周最多投票", + "viewAll": "查看全部" + }, + "workflows": { + "title": "工作流与技术栈", + "subtitle": "常见开发任务的完整工具组合", + "viewAll": "全部工作流" + }, + "browseCategory": { + "title": "按分类浏览" + }, + "trendingNow": { + "title": "当前趋势" + }, + "seeRankings": "查看完整排行", + "browse": "浏览工具", + "noLaunches": "还没有发布——来做第一个。", + "searchPlaceholder": "搜索 AI 工具...", + "reviewsCount": "{count} 条评论", + "mastheadLabel": "独立 AI 报道", + "minimalTagline": "AI 工具搜索", + "minimalPlaceholder": "我需要制作营销视频……", + "useCasesBlockTitle": "使用场景", + "goodForBlockTitle": "适合人群", + "searchButton": "搜索", + "trendingTitle": "本周趋势", + "trendingSubtitle": "按最近 7 天投票、评论与互动排名", + "allRankings": "全部榜单", + "categoriesTitle": "按分类浏览", + "categoriesViewAll": "全部工具", + "newTitle": "最新收录", + "editorsTitle": "编辑精选", + "useCasesTitle": "按用例找工具", + "useCasesSubtitle": "你想完成什么?", + "useCasesViewAll": "全部用例", + "bestListsTitle": "最佳 AI 工具清单", + "bestListsSubtitle": "编辑精选排名", + "bestListsViewAll": "全部清单", + "reviewsTitle": "最新社区评论", + "ctaTitle": "做了 AI 工具?", + "ctaBody": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "ctaButton": "提交你的工具", + "popularLabel": "热门:", + "feedTitle": "今日发布流", + "feedBrowse": "浏览全部产品", + "leaderboardTitle": "排行榜", + "leaderboardFull": "完整榜单", + "picksTitle": "编辑推荐", + "collectionsTitle": "合集", + "launchButton": "发布你的产品", + "featuredLabel": "头条文章", + "featuredRead": "阅读全文", + "picksEditorialLabel": "编辑推荐", + "guidesTitle": "选购指南", + "guidesSubtitle": "帮你做决定的深度对比", + "guidesViewAll": "全部指南", + "storiesTitle": "最新文章", + "storiesViewAll": "全部文章", + "communityTitle": "来自社区", + "communityViewAll": "浏览目录", + "shipTitle": "用 AI 加速交付", + "shipSubtitle": "选好工作流,我们为它排好了工具", + "upvotedTitle": "本周最多投票", + "upvotedViewAll": "查看全部", + "workflowsTitle": "工作流与技术栈", + "workflowsSubtitle": "常见开发任务的完整工具组合", + "workflowsViewAll": "全部工作流", + "browseCategoryTitle": "按分类浏览", + "trendingNowTitle": "当前趋势", + "browseButton": "浏览工具", + "toolsCompared": "{count} 个工具", + "popularSearches": [ + "写作", + "视频", + "编程", + "图像" + ] + }, + "best": { + "indexTitle": "最佳 AI 工具——精选清单", + "indexSubtitle": "人工精选排名,持续吸收社区信号。每个清单都明确标注,永不售卖。", + "empty": "暂无合集。", + "curated": "编辑精选", + "faq": "常见问题", + "more": "更多最佳清单", + "toolsCompared": "{count} 个工具" + }, + "aiToolsFor": { + "indexTitle": "按任务找 AI 工具", + "indexSubtitle": "别再翻分类。从你的任务或角色出发——每页都按真实社区投票与评论排名。", + "byTask": "按任务", + "byAudience": "按人群", + "noData": "暂无用例。", + "noAud": "暂无人群。", + "noTools": "暂无关联工具。" + }, + "submitPage": { + "title": "提交你的 AI 工具", + "subtitle": "免费收录,获得社区投票、用户评论与数据分析。编辑通常在 48 小时内完成审核。" + }, + "faq": { + "title": "常见问题" + }, + "compare": { + "intro": "基于社区投票、评分与评论的并排对比——非赞助排名。", + "leaning": "当前社区更倾向 {name}。", + "label": "对比", + "noReviews": "—", + "latest": "最新评论" + }, + "alternatives": { + "noAlt": "暂无替代品。", + "thisTool": "{name}(本工具)", + "table": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + }, + "zhTable": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + } + }, + "notFound": { + "code": "404", + "title": "页面不存在", + "body": "你访问的页面不存在或已被移动。", + "home": "返回首页", + "tools": "浏览工具" + }, + "search": { + "placeholder": "搜索 1000+ AI 工具...", + "button": "搜索" } } diff --git a/packages/core/scripts/generate-site.mjs b/packages/core/scripts/generate-site.mjs index 7cfdf6c..26c5dec 100644 --- a/packages/core/scripts/generate-site.mjs +++ b/packages/core/scripts/generate-site.mjs @@ -23,6 +23,15 @@ const SITES_ROOT = path.join(REPO_ROOT, "sites"); // ==================================================================== const SITES = { "ai-stack": { + brandZh: { + name: "AI Stack", + tagline: "由真实用户排名的专业 AI 工具目录。", + headline: "找到最好的 AI 工具,由真实用户排名", + subheadline: "14 个分类、1000+ AI 工具。对比投票、评论与定价,选出最适合你的。", + nav: ["发现", "用例", "最佳清单", "排行榜", "博客", "提交工具"], + footer: ["发现", "社区", "法律"], + searchPlaceholder: "搜索 1000+ AI 工具...", + }, accent: "222 47% 11%", // 近黑(专业) port: 3001, theme: "classic", @@ -82,6 +91,15 @@ const SITES = { }, }, launchai: { + brandZh: { + name: "LaunchAI", + tagline: "发现并投票今日的 AI 新品。", + headline: "今日 AI 产品发布", + subheadline: "每天上新。为最好的产品投票,冲上排行榜。", + nav: ["今日", "排行榜", "分类", "合集", "博客", "提交产品"], + footer: ["社区", "探索", "关于"], + searchPlaceholder: "搜索 AI 产品...", + }, accent: "16 85% 55%", // 橙红(产品社区) port: 3002, theme: "product", @@ -139,6 +157,15 @@ const SITES = { }, }, "the-ai-ledger": { + brandZh: { + name: "The AI Ledger", + tagline: "独立 AI 报道,附社区排名目录。", + headline: "AI 工具,评测与排名", + subheadline: "指南、对比,以及由社区驱动的最佳 AI 工具目录。", + nav: ["文章", "指南", "最佳推荐", "目录", "排行榜", "提交"], + footer: ["阅读", "目录", "公司"], + searchPlaceholder: "搜索目录...", + }, accent: "36 70% 40%", // 纸墨棕(编辑部) port: 3003, theme: "editorial", @@ -197,6 +224,15 @@ const SITES = { }, }, "devai-tools": { + brandZh: { + name: "DevAI.tools", + tagline: "面向开发者的 AI 工具——精选、实测、社区排名。", + headline: "开发者的 AI 工具", + subheadline: "代码助手、运维自动化、测试副驾驶,你上手的一切。", + nav: ["工具", "工作流", "用例", "排行榜", "提交"], + footer: ["目录", "构建", "法律"], + searchPlaceholder: "搜索开发者工具...", + }, accent: "150 60% 30%", // 终端绿(开发者) port: 3004, theme: "niche", @@ -253,6 +289,15 @@ const SITES = { }, }, findai: { + brandZh: { + name: "findai", + tagline: "极简 AI 工具搜索引擎。", + headline: "你想完成什么?", + subheadline: "", + nav: ["搜索", "用例", "排行榜", "提交"], + footer: ["搜索", "关于"], + searchPlaceholder: "你需要什么?", + }, accent: "260 70% 52%", // 紫(极简搜索) port: 3005, theme: "minimal", @@ -501,13 +546,25 @@ import { locales, defaultLocale, type Locale } from "${corePkg}/i18n.config"; const brandMessages = { en: { seo: { home: ${JSON.stringify({ title: site.seo.en.title, description: site.seo.en.description, ogImage: "/og-image.png" })} }, - hero: { title: ${JSON.stringify(site.seo.en.title)}, description: ${JSON.stringify(site.seo.en.description)} }, + hero: { title: ${JSON.stringify(site.brand.headline)}, description: ${JSON.stringify(site.brand.subheadline || site.seo.en.description)} }, common: { brand: { name: ${JSON.stringify(site.brand.name)}, tagline: ${JSON.stringify(site.brand.tagline)} } }, + navigation: { + main: { tools: ${JSON.stringify(site.navItems[0]?.label ?? "Discover")}, blog: ${JSON.stringify(site.navItems.find((n) => n.href === "/blog")?.label ?? "Blog")} }, + site: { items: ${JSON.stringify(site.navItems.map((n) => n.label))}, hrefs: ${JSON.stringify(site.navItems.map((n) => n.href))} }, + }, + siteFooter: { groups: ${JSON.stringify(site.footerGroups)} }, + siteHeader: { searchPlaceholder: ${JSON.stringify(site.searchPlaceholder)} }, }, zh: { seo: { home: ${JSON.stringify({ title: site.seo.zh.title, description: site.seo.zh.description, ogImage: "/og-image.png" })} }, - hero: { title: ${JSON.stringify(site.seo.zh.title)}, description: ${JSON.stringify(site.seo.zh.description)} }, - common: { brand: { name: ${JSON.stringify(site.brand.name)}, tagline: ${JSON.stringify(site.brand.tagline)} } }, + hero: { title: ${JSON.stringify(site.brandZh?.headline ?? site.seo.zh.title)}, description: ${JSON.stringify(site.brandZh?.subheadline || site.seo.zh.description)} }, + common: { brand: { name: ${JSON.stringify(site.brandZh?.name ?? site.brand.name)}, tagline: ${JSON.stringify(site.brandZh?.tagline ?? site.brand.tagline)} } }, + navigation: { + main: { tools: ${JSON.stringify(site.brandZh?.nav?.[0] ?? site.navItems[0]?.label ?? "发现")}, blog: ${JSON.stringify(site.brandZh?.nav?.[site.navItems.findIndex((n) => n.href === "/blog")] ?? "博客")} }, + site: { items: ${JSON.stringify(site.brandZh?.nav ?? site.navItems.map((n) => n.label))}, hrefs: ${JSON.stringify(site.navItems.map((n) => n.href))} }, + }, + siteFooter: { groups: ${JSON.stringify(site.footerGroups.map((g, gi) => ({ ...g, title: (site.brandZh?.footer ?? [])[gi] ?? g.title })))} }, + siteHeader: { searchPlaceholder: ${JSON.stringify(site.brandZh?.searchPlaceholder ?? site.searchPlaceholder)} }, }, } as const; @@ -649,7 +706,30 @@ export default getRequestConfig(async ({ requestLocale }) => { base.common.brand = { ...(base.common.brand ?? {}), name: site.brand.name, tagline: site.brand.tagline }; base.seo = base.seo ?? {}; base.seo.home = { ...(base.seo.home ?? {}), ...site.seo[locale] }; - base.hero = { ...(base.hero ?? {}), title: site.seo[locale].title, description: site.seo[locale].description }; + base.hero = { + ...(base.hero ?? {}), + title: locale === "zh" ? (site.brandZh?.headline ?? site.seo.zh.title) : site.brand.headline, + description: locale === "zh" ? (site.brandZh?.subheadline || site.seo.zh.description) : (site.brand.subheadline || site.seo.en.description), + badge: locale === "zh" ? "" : base.hero?.badge ?? "", + }; + if (locale === "zh") delete base.hero.badge; + // 站点导航/页脚/搜索文案(供 ThemeChrome 消费) + base.navigation = { + ...(base.navigation ?? {}), + site: { + items: locale === "zh" ? (site.brandZh?.nav ?? site.navItems.map((n) => n.label)) : site.navItems.map((n) => n.label), + hrefs: site.navItems.map((n) => n.href), + }, + }; + base.siteFooter = { + groups: site.footerGroups.map((g, gi) => ({ + ...g, + title: locale === "zh" ? ((site.brandZh?.footer ?? [])[gi] ?? g.title) : g.title, + })), + }; + base.siteHeader = { + searchPlaceholder: locale === "zh" ? (site.brandZh?.searchPlaceholder ?? site.searchPlaceholder) : site.searchPlaceholder, + }; fs.mkdirSync(path.join(siteRoot, "messages"), { recursive: true }); fs.writeFileSync( path.join(siteRoot, "messages", `${locale}.json`), diff --git a/packages/core/scripts/wire-theme-i18n.py b/packages/core/scripts/wire-theme-i18n.py new file mode 100644 index 0000000..47d6b79 --- /dev/null +++ b/packages/core/scripts/wire-theme-i18n.py @@ -0,0 +1,205 @@ +#!/usr/bin/env python3 +""" +# 脚本 wire-theme-i18n +# 说明:一次性把五个主题模板首页的硬编码文案接线到 next-intl(siteHome/hero 命名空间)。 +# 规则: +# - import 加 useTranslations +# - 每个含 t( 调用的函数组件体开头插入 hook 声明 +# - 文案字符串替换为 t("key") / {t("key")}(JSX 子节点带花括号,属性值带花括号) +# - 顶层常量(navItems/footerGroups)不改(导航/页脚由 SiteChrome i18n 提供,这些常量是死代码但无害) +# 运行:python3 scripts/wire-theme-i18n.py +""" +import re + +# 每个模板的替换表:(原文案, i18n key, 是否 JSX 子节点) +COMMON = [ + # classic + ('>Find the best AI tools, ranked by real users<', 'heroTitle', True), + ('>1,000+ AI tools across 14 categories. Compare votes, reviews and pricing to pick the right\n one.<', 'heroSubtitle', True), + ('placeholder="Search 1,000+ AI tools..."', 'searchPlaceholder', False), + ('Popular:', 'popularLabel', True), + ('>\n Search\n ', 'searchButton', True), + ('"Trending this week"', 'trendingTitle', False), + ('"Ranked by votes, reviews and engagement over the last 7 days"', 'trendingSubtitle', False), + ('"All rankings"', 'allRankings', False), + ('"Browse by category"', 'categoriesTitle', False), + ('"All tools"', 'categoriesViewAll', False), + ('{category.toolCount} tools', 'toolsCount', 'ctx:category.toolCount'), + ('"New AI tools"', 'newTitle', False), + ('"Editor\'s Choice"', 'editorsTitle', False), + ('"Tools by use case"', 'useCasesTitle', False), + ('"What do you want to get done?"', 'useCasesSubtitle', False), + ('"All use cases"', 'useCasesViewAll', False), + ('"Best AI tool lists"', 'bestListsTitle', False), + ('"Curated rankings by our editors"', 'bestListsSubtitle', False), + ('"All lists"', 'bestListsViewAll', False), + ('"{col.toolCount} tools"', 'toolsCount', 'ctx:col.toolCount'), + ('"Latest community reviews"', 'reviewsTitle', False), + # product + ('placeholder="Search AI products..."', 'searchPlaceholder', False), + ('>Today\'s AI product launches<', 'heroTitle', True), + ('>Fresh AI products, every day. Upvote the best ones to the top.<', 'heroSubtitle', True), + ('Launch your product', 'launchButton', False), + ('"Today\'s feed"', 'feedTitle', False), + ('No launches yet — be the first to submit.', 'noLaunches', False), + ('Browse all products', 'feedBrowse', False), + ('"Fresh launches"', 'newTitle', False), + ('"Leaderboard"', 'leaderboardTitle', False), + ('Full leaderboard', 'leaderboardFull', False), + ('"{tool.reviewCount} reviews"', 'reviewsCount', 'ctx:tool.reviewCount'), + ('"Collections"', 'collectionsTitle', False), + # editorial + ('Independent AI Coverage', 'mastheadLabel', False), + ('Featured story', 'featuredLabel', False), + ('Read the story', 'featuredRead', False), + ('Editor\'s picks', 'picksEditorialLabel', False), + ('"Buying guides"', 'guidesTitle', False), + ('"Deep dives that help you choose"', 'guidesSubtitle', False), + ('"All guides"', 'guidesViewAll', False), + ('tools compared', 'toolsCompared', False), + ('"Latest stories"', 'storiesTitle', False), + ('"All stories"', 'storiesViewAll', False), + ('"From the community"', 'communityTitle', False), + ('"Browse directory"', 'communityViewAll', False), + # niche + ('placeholder="Search dev tools..."', 'searchPlaceholder', False), + ('>AI tools for developers<', 'heroTitle', True), + ('>Code assistants, DevOps automation, testing copilots and everything else you ship with.<', 'heroSubtitle', True), + ('Browse tools\n', 'browseButton', True), + ('"Ship faster with AI"', 'shipTitle', False), + ('"Pick your workflow — we ranked the tools for it"', 'shipSubtitle', False), + ('"Most upvoted this week"', 'upvotedTitle', False), + ('"View all"', 'upvotedViewAll', False), + ('"Workflows & stacks"', 'workflowsTitle', False), + ('"Batteries-included tool stacks for common dev tasks"', 'workflowsSubtitle', False), + ('"All workflows"', 'workflowsViewAll', False), + # minimal + ('AI TOOL SEARCH', 'minimalTagline', False), + ('placeholder="I need to create marketing videos..."', 'minimalPlaceholder', False), + ('"Trending now"', 'trendingNowTitle', False), + ('See full rankings', 'seeRankings', False), +] + +NEEDS = { + "heroTitle": ("hero", "title"), "heroSubtitle": ("hero", "description"), + "searchPlaceholder": ("siteHome", "searchPlaceholder"), + "popularLabel": ("siteHome", "popularLabel"), + "trendingTitle": ("siteHome", "trendingTitle"), "trendingSubtitle": ("siteHome", "trendingSubtitle"), + "allRankings": ("siteHome", "allRankings"), + "categoriesTitle": ("siteHome", "categoriesTitle"), "categoriesViewAll": ("siteHome", "categoriesViewAll"), + "newTitle": ("siteHome", "newTitle"), "editorsTitle": ("siteHome", "editorsTitle"), + "useCasesTitle": ("siteHome", "useCasesTitle"), "useCasesSubtitle": ("siteHome", "useCasesSubtitle"), + "useCasesViewAll": ("siteHome", "useCasesViewAll"), + "bestListsTitle": ("siteHome", "bestListsTitle"), "bestListsSubtitle": ("siteHome", "bestListsSubtitle"), + "bestListsViewAll": ("siteHome", "bestListsViewAll"), + "reviewsTitle": ("siteHome", "reviewsTitle"), + "ctaTitle": ("siteHome", "ctaTitle"), "ctaBody": ("siteHome", "ctaBody"), "ctaButton": ("siteHome", "ctaButton"), + "launchButton": ("siteHome", "launchButton"), + "feedTitle": ("siteHome", "feedTitle"), "noLaunches": ("siteHome", "noLaunches"), + "feedBrowse": ("siteHome", "feedBrowse"), + "leaderboardTitle": ("siteHome", "leaderboardTitle"), "leaderboardFull": ("siteHome", "leaderboardFull"), + "picksTitle": ("siteHome", "picksTitle"), "collectionsTitle": ("siteHome", "collectionsTitle"), + "mastheadLabel": ("siteHome", "mastheadLabel"), + "featuredLabel": ("siteHome", "featuredLabel"), "featuredRead": ("siteHome", "featuredRead"), + "picksEditorialLabel": ("siteHome", "picksEditorialLabel"), + "guidesTitle": ("siteHome", "guidesTitle"), "guidesSubtitle": ("siteHome", "guidesSubtitle"), + "guidesViewAll": ("siteHome", "guidesViewAll"), + "storiesTitle": ("siteHome", "storiesTitle"), "storiesViewAll": ("siteHome", "storiesViewAll"), + "communityTitle": ("siteHome", "communityTitle"), "communityViewAll": ("siteHome", "communityViewAll"), + "shipTitle": ("siteHome", "shipTitle"), "shipSubtitle": ("siteHome", "shipSubtitle"), + "upvotedTitle": ("siteHome", "upvotedTitle"), "upvotedViewAll": ("siteHome", "upvotedViewAll"), + "workflowsTitle": ("siteHome", "workflowsTitle"), "workflowsSubtitle": ("siteHome", "workflowsSubtitle"), + "workflowsViewAll": ("siteHome", "workflowsViewAll"), + "browseButton": ("siteHome", "browseButton"), + "browseCategoryTitle": ("siteHome", "browseCategoryTitle"), + "minimalTagline": ("siteHome", "minimalTagline"), + "minimalPlaceholder": ("siteHome", "minimalPlaceholder"), + "trendingNowTitle": ("siteHome", "trendingNowTitle"), + "seeRankings": ("siteHome", "seeRankings"), + "searchButton": ("siteHome", "searchButton"), + "toolsCount": ("siteHome", "toolsCount"), + "toolsCompared": ("siteHome", "toolsCompared"), + "reviewsCount": ("siteHome", "reviewsCount"), +} + +TEMPLATES = [ + "src/kit/site-themes/classic/index.tsx", + "src/kit/site-themes/product/index.tsx", + "src/kit/site-themes/editorial/index.tsx", + "src/kit/site-themes/niche/index.tsx", + "src/kit/site-themes/minimal/index.tsx", +] + +def add_import(src): + if "useTranslations" not in src: + m = re.search(r'import \{ ([^}]+) \} from "lucide-react";\n', src) + assert m, "lucide import not found" + src = src.replace(m.group(0), m.group(0) + 'import { useTranslations } from "next-intl";\n', 1) + return src + +def add_hooks(src): + """为每个使用了 t( 的函数组件体开头插入 hook 声明""" + out = [] + # 找所有 function 块开头 + for m in re.finditer(r'((?:async )?function (\w+)\(\{[^}]*locale[^}]*\}(?:[^)]*)\) \{\n)', src): + header, fname = m.group(1), m.group(2) + start = m.end() + # 找函数结束(下一个顶层 function 或文件尾) + nxt = re.search(r'\n(?:async )?function ', src[start:]) + end = start + (nxt.start() if nxt else len(src) - start) + body = src[start:end] + if 't("' not in body and 't(\'"' not in body: + continue + if 'const t = useTranslations' in body: + continue + hooks = ' const t = useTranslations("siteHome");\n' + if any(k in body for k in ("heroTitle", "heroSubtitle")): + hooks += ' const th = useTranslations("hero");\n' + src = src[:start] + hooks + src[start:] + # 重新计算(插入后偏移变化),直接 break 重跑 + return add_hooks(src) + return src + +def apply_replacements(src, fname): + used = set() + # 只在组件函数体内部替换(跳过顶层常量——导航/页脚由 SiteChrome i18n 提供) + first_fn = re.search(r'(?:async )?function \w+', src) + body_start = first_fn.start() if first_fn else len(src) + head, body = src[:body_start], src[body_start:] + for original, key, mode in COMMON: + ns, k = NEEDS[key] if key in NEEDS else (None, None) + tref = f'{ns}["{k}"]' if ns else key # hero 用 th + fn = "th" if ns == "hero" else "t" + tref = f'{fn}("{k}")' + if original.startswith('>'): + # JSX 子节点(含换行缩进的两段式原文用正则容忍空白) + pat = re.compile(re.escape(original).replace(r'\ ', r'\s+')) + if pat.search(body): + body = pat.sub(f'>{tref}<', body, count=1) + used.add(key) + elif mode == 'ctx': + ctx_expr = original.replace('{', '').replace('}', '').split()[0] + pat = re.compile(re.escape(original).replace(r'\ ', r'\s+')) + if pat.search(body): + body = pat.sub(f'{{{tref}({ctx_expr})}}', body, count=1) + used.add(key) + elif mode is False or mode is None: + # 引号内字符串 → 属性 {t("key")} 或 JSX 子节点 {t("key")} + if original in body: + body = body.replace(original, f'{{{tref}}}') + used.add(key) + return head + body, used + +def main(): + for p in TEMPLATES: + src = open(p).read() + src = add_import(src) + src, used = apply_replacements(src, p) + src = add_hooks(src) + open(p, 'w').write(src) + # 报告未使用的 key(该模板不需要) + unused = [k for k in NEEDS if k not in used] + print(f"{p}: wired {len(used)} keys") + +if __name__ == "__main__": + main() diff --git a/packages/core/src/features/alternatives/components/views.tsx b/packages/core/src/features/alternatives/components/views.tsx index c459cd4..6153420 100644 --- a/packages/core/src/features/alternatives/components/views.tsx +++ b/packages/core/src/features/alternatives/components/views.tsx @@ -1,4 +1,5 @@ import { notFound } from "next/navigation"; +import { getTranslations } from "next-intl/server"; import { getToolBySlug } from "@/features/tools/actions"; import { getAlternativeTools } from "@/features/discovery/actions"; import { pickName } from "@/features/discovery/localize"; @@ -35,6 +36,9 @@ export async function AlternativesView({ }) { const base = await getToolBySlug(baseSlug); if (!base) notFound(); + const t = await getTranslations({ locale, namespace: "alternatives" }); + const tf = await getTranslations({ locale, namespace: "faq" }); + const tt = await getTranslations({ locale, namespace: "alternatives.table" }); const alternatives = await getAlternativeTools(base.id, 12); const name = locale === "zh" && base.nameZh ? base.nameZh : base.nameEn; @@ -93,7 +97,7 @@ export async function AlternativesView({ {alternatives.length === 0 ? (

- No alternatives found yet. + {t("noAlt")}

) : ( @@ -109,10 +113,10 @@ export async function AlternativesView({ - - - - + + + + @@ -124,7 +128,7 @@ export async function AlternativesView({ className="font-medium text-foreground hover:text-primary" > {tool.nameEn === base.nameEn && tool.id === base.id - ? `${name} (this tool)` + ? t("thisTool", { name }) : locale === "zh" && tool.nameZh ? tool.nameZh : tool.nameEn} @@ -160,7 +164,7 @@ export async function AlternativesView({

- Frequently asked questions + {tf("title")}

{seo.faqs.map((faq, i) => ( @@ -206,6 +210,8 @@ export async function ComparisonView({ const nameA = pickName(toolA, locale); const nameB = pickName(toolB, locale); + const tc = await getTranslations({ locale, namespace: "compare" }); + const tf2 = await getTranslations({ locale, namespace: "faq" }); const url = `${baseUrl()}/${locale}/tools/${slugA}-vs-${slugB}`; const pricingLabels: Record = { @@ -260,7 +266,7 @@ export async function ComparisonView({ winner: "tie", }, { - label: "Latest review", + label: "latest", a: reviewsA.reviews[0]?.content?.slice(0, 120) ?? "—", b: reviewsB.reviews[0]?.content?.slice(0, 120) ?? "—", winner: "tie", @@ -301,11 +307,10 @@ export async function ComparisonView({ {nameA} vs {nameB}: which should you use?

- A side-by-side comparison based on community votes, ratings and - reviews — not sponsored placement. + {tc("intro")} {winnerLabel && ( <> - {" "}Right now the community leans toward{" "} + {" "}{tc("leaning", { name: winnerLabel })}{" "} ({ href, label: navLabels[i] ?? "" })) + : config.navItems; + + // 页脚分组:title 按 i18n + const footerGroupsRaw = tf.raw("groups") as + | { title: string; links: { label: string; href: string }[] }[] + | undefined; + const footerGroups = footerGroupsRaw ?? config.footerGroups; + return (

{children} - +
); } diff --git a/packages/core/src/kit/site-themes/classic/index.tsx b/packages/core/src/kit/site-themes/classic/index.tsx index c0863d8..356b2e6 100644 --- a/packages/core/src/kit/site-themes/classic/index.tsx +++ b/packages/core/src/kit/site-themes/classic/index.tsx @@ -1,4 +1,5 @@ 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 "../shared/section"; @@ -55,6 +56,8 @@ const footerGroups = [ ]; async function ClassicHome({ locale }: { locale: string }) { + const t = await getTranslations("siteHome"); + const th = await getTranslations("hero"); const data = await getHomeDataSafe(8); return ( @@ -63,17 +66,17 @@ async function ClassicHome({ locale }: { locale: string }) {

- {brand.headline} + {th("title")}

- {brand.subheadline} + {th("description")}

@@ -81,13 +84,13 @@ async function ClassicHome({ 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")}
- Popular: - {["writing", "video", "coding", "image"].map((q) => ( + {t("popularLabel")} + {t.raw("popularSearches").map((q: string) => ( 0 && (
@@ -118,9 +121,9 @@ async function ClassicHome({ locale }: { locale: string }) { {data.categories.length > 0 && (
{data.categories.slice(0, 10).map((category) => ( @@ -149,7 +152,7 @@ async function ClassicHome({ locale }: { locale: string }) { {data.newest.length > 0 && (
@@ -158,7 +161,7 @@ async function ClassicHome({ locale }: { locale: string }) { {data.editorsChoice.length > 0 && (
@@ -170,10 +173,10 @@ async function ClassicHome({ locale }: { locale: string }) { {data.useCases.length > 0 && (
{data.useCases.slice(0, 12).map((uc) => ( @@ -196,10 +199,10 @@ async function ClassicHome({ locale }: { locale: string }) { {data.collections.length > 0 && (
{data.collections.slice(0, 3).map((col) => ( @@ -227,7 +230,7 @@ async function ClassicHome({ locale }: { locale: string }) { {/* Latest Reviews */} {data.latestReviews.length > 0 && (
- +
{data.latestReviews.map((review, i) => (

- Independent AI Coverage + {t("mastheadLabel")}

- {brand.headline} + {th("title")}

- {brand.subheadline} + {th("description")}

@@ -77,7 +80,7 @@ async function EditorialHome({ locale }: { locale: string }) {
- Featured story + {t("featuredLabel")}

@@ -89,7 +92,7 @@ async function EditorialHome({ locale }: { locale: string }) {

)} - Read the story + {t("featuredRead")} @@ -101,7 +104,7 @@ async function EditorialHome({ locale }: { locale: string }) {
- Editor's picks + {t("picksEditorialLabel")}
{editorPicks.map((tool, i) => ( @@ -137,10 +140,10 @@ async function EditorialHome({ locale }: { locale: string }) { {data.collections.length > 0 && (
{data.collections.slice(0, 4).map((col) => ( @@ -156,7 +159,7 @@ async function EditorialHome({ locale }: { locale: string }) { {locale === "zh" && col.introZh ? col.introZh : col.introEn}

- {col.toolCount} tools compared + {col.toolCount} {t("toolsCompared")}

))} @@ -167,7 +170,7 @@ async function EditorialHome({ locale }: { locale: string }) { {/* Latest articles */} {data.articles.length > 1 && (
- +
{data.articles.slice(1).map((article) => ( @@ -189,9 +192,9 @@ async function EditorialHome({ locale }: { locale: string }) { {data.latestReviews.length > 0 && (
{data.latestReviews.slice(0, 4).map((review, i) => ( diff --git a/packages/core/src/kit/site-themes/minimal/index.tsx b/packages/core/src/kit/site-themes/minimal/index.tsx index f45d66a..6e0802b 100644 --- a/packages/core/src/kit/site-themes/minimal/index.tsx +++ b/packages/core/src/kit/site-themes/minimal/index.tsx @@ -1,4 +1,5 @@ import { Search } from "lucide-react"; +import { getTranslations } from "next-intl/server"; import { ToolCardGrid } from "@/components/tool-card"; import { LocaleLink } from "@/components/locale-link"; import { getHomeDataSafe } from "../shared/home-data"; @@ -48,6 +49,8 @@ const popularSearches = [ ]; async function MinimalHome({ locale }: { locale: string }) { + const t = await getTranslations("siteHome"); + const th = await getTranslations("hero"); const data = await getHomeDataSafe(6); return ( @@ -67,7 +70,7 @@ async function MinimalHome({ locale }: { locale: string }) { @@ -99,7 +102,7 @@ async function MinimalHome({ locale }: { locale: string }) { href="/rankings" className="text-xs font-medium text-muted-foreground hover:text-primary" > - See full rankings + {t("seeRankings")}
diff --git a/packages/core/src/kit/site-themes/niche/index.tsx b/packages/core/src/kit/site-themes/niche/index.tsx index 028cdb4..675ed05 100644 --- a/packages/core/src/kit/site-themes/niche/index.tsx +++ b/packages/core/src/kit/site-themes/niche/index.tsx @@ -1,4 +1,5 @@ import { Code2, Terminal, Workflow, Layers } from "lucide-react"; +import { getTranslations } from "next-intl/server"; import { ToolCard } from "@/components/tool-card"; import { LocaleLink } from "@/components/locale-link"; import { SectionHeader } from "../shared/section"; @@ -49,6 +50,8 @@ const footerGroups = [ ]; async function NicheHome({ locale }: { locale: string }) { + const t = await getTranslations("siteHome"); + const th = await getTranslations("hero"); const data = await getHomeDataSafe(6); return ( @@ -70,10 +73,10 @@ async function NicheHome({ locale }: { locale: string }) {

- {brand.headline} + {th("title")}

- {brand.subheadline} + {th("description")}

0 && (

{data.useCases.slice(0, 6).map((uc) => ( @@ -124,7 +127,7 @@ async function NicheHome({ locale }: { locale: string }) { {data.trending.length > 0 && (
@@ -144,10 +147,10 @@ async function NicheHome({ locale }: { locale: string }) { {data.collections.length > 0 && (
{data.collections.slice(0, 3).map((col) => ( @@ -172,7 +175,7 @@ async function NicheHome({ locale }: { locale: string }) { {/* Categories */} {data.categories.length > 0 && (
- +
{data.categories.slice(0, 14).map((cat) => (

- {brand.headline} + {th("title")}

- {brand.subheadline} + {th("description")}

- Launch your product + {t("launchButton")}
@@ -144,14 +147,14 @@ async function ProductHome({ locale }: { locale: string }) { )) ) : (

- No launches yet — be the first to submit. + {t("noLaunches")}

)} - Browse all products + {t("feedBrowse")}
@@ -159,7 +162,7 @@ async function ProductHome({ locale }: { locale: string }) { {/* New */} {data.newest.length > 0 && (
- +
{data.newest.slice(0, 5).map((tool) => ( @@ -204,14 +207,14 @@ async function ProductHome({ locale }: { locale: string }) { href="/rankings" className="mt-4 block rounded-lg border border-border py-2 text-center text-xs font-medium text-muted-foreground hover:border-primary/40 hover:text-primary" > - Full leaderboard + {t("leaderboardFull")}
)} {data.editorsChoice.length > 0 && (
-

Editor's picks

+

{t("picksEditorialLabel")}

    {data.editorsChoice.slice(0, 4).map((tool) => (
  1. diff --git a/packages/core/src/kit/types.ts b/packages/core/src/kit/types.ts index 91d9815..4a6e7e8 100644 --- a/packages/core/src/kit/types.ts +++ b/packages/core/src/kit/types.ts @@ -32,6 +32,16 @@ export interface SiteConfig { seo?: Record; /** 品牌强调色 HSL 三元组(登录页分栏模板) */ accent?: string; + /** 中文品牌文案(导航/页脚/hero/搜索占位) */ + brandZh?: { + name?: string; + tagline?: string; + headline?: string; + subheadline?: string; + nav?: string[]; + footer?: string[]; + searchPlaceholder?: string; + }; /** 品牌侧栏标语(登录页) */ brandTagline?: string; /** 主题级 CSS 变量覆盖(HSL 三元组,可选) */ diff --git a/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/[slug]/page.tsx b/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/[slug]/page.tsx index 245f5ff..d85fb39 100644 --- a/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/[slug]/page.tsx +++ b/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/[slug]/page.tsx @@ -1,6 +1,6 @@ import type { Metadata } from "next"; import { notFound } from "next/navigation"; -import { setRequestLocale } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { generatePageMetadata } from "@/lib/metadata"; import { getUseCaseBySlug, @@ -82,6 +82,7 @@ export default async function AiToolsForEntityPage({ }) { const { slug, locale } = await params; setRequestLocale(locale); + const tf = await getTranslations({ locale, namespace: "faq" }); const resolved = await resolveEntity(slug); if (!resolved) notFound(); @@ -168,7 +169,7 @@ export default async function AiToolsForEntityPage({

    - Frequently asked questions + {tf("title")}

    {seo.faqs.map((faq, i) => ( diff --git a/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/page.tsx b/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/page.tsx index 6985e24..5d989d6 100644 --- a/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/page.tsx +++ b/packages/core/src/pages/[locale]/(marketing)/ai-tools-for/page.tsx @@ -1,11 +1,12 @@ import type { Metadata } from "next"; -import { setRequestLocale } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { generatePageMetadata } from "@/lib/metadata"; import { getUseCases, getAudiences } from "@/features/discovery/actions"; import { pickName } from "@/features/discovery/localize"; import { CollectionPageJsonLd } from "@/components/json-ld"; import { LocaleLink } from "@/components/locale-link"; import { Target, Users } from "lucide-react"; +import { useTranslations } from "next-intl"; export const revalidate = 3600; @@ -31,6 +32,7 @@ export default async function AiToolsForPage({ }) { const { locale } = await params; setRequestLocale(locale); + const t = await getTranslations("aiToolsFor"); const [useCases, audiences] = await Promise.all([ getUseCases().catch(() => []), @@ -49,11 +51,10 @@ export default async function AiToolsForPage({

    - AI tools for what you do + {t("indexTitle")}

    - Skip the categories. Start from your task or your role — every page - ranks tools by real community votes and reviews. + {t("indexSubtitle")}

    @@ -61,10 +62,10 @@ export default async function AiToolsForPage({

    - By task + {t("byTask")}

    {useCases.length === 0 ? ( -

    No use cases yet.

    +

    {t("noData")}

    ) : (
    {useCases.map((uc) => ( @@ -96,10 +97,10 @@ export default async function AiToolsForPage({

    - By audience + {t("byAudience")}

    {audiences.length === 0 ? ( -

    No audiences yet.

    +

    {t("noAud")}

    ) : (
    {audiences.map((aud) => ( diff --git a/packages/core/src/pages/[locale]/(marketing)/best/[slug]/page.tsx b/packages/core/src/pages/[locale]/(marketing)/best/[slug]/page.tsx index f651ba6..ad4a7f8 100644 --- a/packages/core/src/pages/[locale]/(marketing)/best/[slug]/page.tsx +++ b/packages/core/src/pages/[locale]/(marketing)/best/[slug]/page.tsx @@ -1,6 +1,6 @@ import type { Metadata } from "next"; import { notFound } from "next/navigation"; -import { setRequestLocale } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { generatePageMetadata } from "@/lib/metadata"; import { getCollectionBySlug, @@ -63,6 +63,8 @@ export default async function BestCollectionPage({ }) { const { slug, locale } = await params; setRequestLocale(locale); + const tf = await getTranslations({ locale, namespace: "faq" }); + const tb = await getTranslations({ locale, namespace: "best" }); const collection = await getCollectionBySlug(slug); if (!collection) notFound(); @@ -147,7 +149,7 @@ export default async function BestCollectionPage({ {/* FAQ(内链 + FAQPage schema) */}

    - Frequently asked questions + {tf("title")}

    {seo.faqs.map((faq, i) => ( @@ -163,7 +165,7 @@ export default async function BestCollectionPage({ {/* 相关榜单(内链) */}
    -

    More best lists

    +

    {tb("more")}

    {allCollections .filter((col) => col.id !== collection.id) diff --git a/packages/core/src/pages/[locale]/(marketing)/best/page.tsx b/packages/core/src/pages/[locale]/(marketing)/best/page.tsx index d7a238e..372b849 100644 --- a/packages/core/src/pages/[locale]/(marketing)/best/page.tsx +++ b/packages/core/src/pages/[locale]/(marketing)/best/page.tsx @@ -1,5 +1,5 @@ import type { Metadata } from "next"; -import { setRequestLocale } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { generatePageMetadata } from "@/lib/metadata"; import { getCollections } from "@/features/discovery/actions"; import { CollectionPageJsonLd } from "@/components/json-ld"; @@ -30,6 +30,7 @@ export default async function BestIndexPage({ }) { const { locale } = await params; setRequestLocale(locale); + const t = await getTranslations("best"); const collections = await getCollections().catch(() => []); const baseUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3001"; @@ -44,17 +45,16 @@ export default async function BestIndexPage({

    - Best AI Tools — Curated Lists + {t("indexTitle")}

    - Hand-picked rankings, updated with community signal. Every list is - labeled and never sold. + {t("indexSubtitle")}

    {collections.length === 0 ? (

    - No collections published yet. + {t("empty")}

    ) : (
    diff --git a/packages/core/src/pages/[locale]/(marketing)/submit/page.tsx b/packages/core/src/pages/[locale]/(marketing)/submit/page.tsx index 5235781..d00a12b 100644 --- a/packages/core/src/pages/[locale]/(marketing)/submit/page.tsx +++ b/packages/core/src/pages/[locale]/(marketing)/submit/page.tsx @@ -1,4 +1,4 @@ -import { setRequestLocale } from "next-intl/server"; +import { getTranslations, setRequestLocale } from "next-intl/server"; import { generatePageMetadata } from "@/lib/metadata"; import { getCategoriesWithCount } from "@/features/tools/actions"; import { SubmitToolForm } from "@/features/submission/components/submit-tool-form"; @@ -28,6 +28,7 @@ export default async function SubmitPage({ }) { const { locale } = await params; setRequestLocale(locale); + const t = await getTranslations("submitPage"); const categories = await getCategoriesWithCount().catch(() => []); @@ -35,11 +36,10 @@ export default async function SubmitPage({

    - Submit your AI tool + {t("title")}

    - Get a free listing with community votes, user reviews and analytics. - Submissions are reviewed by our editors, usually within 48 hours. + {t("subtitle")}

    diff --git a/packages/core/src/pages/[locale]/(marketing)/tools/[slug]/page.tsx b/packages/core/src/pages/[locale]/(marketing)/tools/[slug]/page.tsx index 62b2e89..d2d2f31 100644 --- a/packages/core/src/pages/[locale]/(marketing)/tools/[slug]/page.tsx +++ b/packages/core/src/pages/[locale]/(marketing)/tools/[slug]/page.tsx @@ -121,6 +121,8 @@ export async function generateMetadata({ params }: ToolDetailPageProps) { } const t = await getTranslations({ locale, namespace: "tools" }); + const tf = await getTranslations({ locale, namespace: "faq" }); + const ts = await getTranslations({ locale, namespace: "siteHome" }); const tool = await getToolBySlug(slug); if (!tool) { return { title: t("notFound") }; @@ -162,6 +164,8 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) { } const t = await getTranslations({ locale, namespace: "tools" }); + const tf = await getTranslations({ locale, namespace: "faq" }); + const ts = await getTranslations({ locale, namespace: "siteHome" }); const tool = await getToolBySlug(slug); if (!tool) { @@ -341,7 +345,7 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) {

    - Use cases + {ts("useCasesBlockTitle")}

    {relations.useCases.map((uc) => ( @@ -360,7 +364,7 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) {

    - Good for + {ts("goodForBlockTitle")}

    {relations.audiences.map((aud) => ( @@ -465,7 +469,7 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) { {/* FAQ */}
    -

    FAQ

    +

    {tf("title")}

    {faqs.map((faq, i) => (
    diff --git a/packages/core/src/pages/[locale]/not-found.tsx b/packages/core/src/pages/[locale]/not-found.tsx new file mode 100644 index 0000000..2903fdf --- /dev/null +++ b/packages/core/src/pages/[locale]/not-found.tsx @@ -0,0 +1,33 @@ +import Link from "next/link"; +import { getTranslations } from "next-intl/server"; + +/** + * # 组件 NotFound(locale 内) + * 说明:品牌化 404,双语(走 next-intl)。 + */ +export default async function NotFound() { + const t = await getTranslations("notFound"); + return ( +
    +
    +
    + + + + +
    +

    {t("code")}

    +

    {t("title")}

    +

    {t("body")}

    +
    + + {t("home")} + + + {t("tools")} + +
    +
    +
    + ); +} diff --git a/packages/core/src/pages/not-found.tsx b/packages/core/src/pages/not-found.tsx index 4fad956..39e579e 100644 --- a/packages/core/src/pages/not-found.tsx +++ b/packages/core/src/pages/not-found.tsx @@ -1,38 +1,38 @@ -import Link from 'next/link'; -import { defaultLocale } from '@/i18n.config'; +import Link from "next/link"; +import { headers } from "next/headers"; /** - * # 组件 NotFound - * 说明:品牌化 404 页(图标 + 双入口:首页 / 工具目录)。 + * # 组件 NotFound(根级) + * 说明:无法使用 locale 上下文(在 [locale] 外),按 Accept-Language 双语。 */ -export default function NotFound() { +export default async function NotFound() { + const h = await headers(); + const accept = h.get("accept-language") || ""; + const zh = accept.toLowerCase().includes("zh"); + const text = zh + ? { code: "404", title: "页面不存在", body: "你访问的页面不存在或已被移动。", home: "返回首页", tools: "浏览工具" } + : { code: "404", title: "Page not found", body: "The page you are looking for doesn't exist or may have moved.", home: "Back to home", tools: "Browse tools" }; return ( - - -
    -
    -
    - - - - -
    -

    404

    -

    Page not found

    -

    - The page you are looking for doesn't exist or may have moved. -

    -
    - - Back to home - - - Browse tools - -
    -
    +
    +
    +
    + + + +
    - - +

    {text.code}

    +

    {text.title}

    +

    {text.body}

    +
    + + {text.home} + + + {text.tools} + +
    +
    +
    ); } diff --git a/sites/ai-stack/messages/en.json b/sites/ai-stack/messages/en.json index a260b38..09cc1dc 100644 --- a/sites/ai-stack/messages/en.json +++ b/sites/ai-stack/messages/en.json @@ -53,12 +53,30 @@ "linkedin": "LinkedIn", "github": "GitHub" } + }, + "site": { + "items": [ + "Discover", + "Use Cases", + "Best Lists", + "Rankings", + "Blog", + "Submit" + ], + "hrefs": [ + "/tools", + "/ai-tools-for", + "/best", + "/rankings", + "/blog", + "/submit" + ] } }, "hero": { "badge": "Discover the Best AI Tools", - "title": "AI Stack — Find the Best AI Tools, Ranked by Real Users", - "description": "The professional AI tools directory. 1,000+ AI tools across 14 categories ranked by community votes, reviews and engagement.", + "title": "Find the best AI tools, ranked by real users", + "description": "1,000+ AI tools across 14 categories. Compare votes, reviews and pricing to pick the right one.", "cta": { "primary": "Explore Tools", "secondary": "Read Blog" @@ -649,7 +667,9 @@ "latest": "Latest", "trending": "Trending" }, - "clearFilters": "Clear search & filters" + "clearFilters": "Clear search & filters", + "useCasesTitle": "Use cases", + "goodForTitle": "Good for" }, "seo": { "home": { @@ -796,5 +816,284 @@ "new": "New", "editorsChoice": "Editor's Choice", "empty": "No tools on this board yet." + }, + "siteHome": { + "trending": { + "title": "Trending this week", + "subtitle": "Ranked by votes, reviews and engagement over the last 7 days" + }, + "categories": { + "title": "Browse by category", + "viewAll": "All tools" + }, + "new": { + "title": "New AI tools" + }, + "editors": { + "title": "Editor's Choice" + }, + "useCases": { + "title": "Tools by use case", + "subtitle": "What do you want to get done?", + "viewAll": "All use cases" + }, + "bestLists": { + "title": "Best AI tool lists", + "subtitle": "Curated rankings by our editors", + "viewAll": "All lists" + }, + "reviews": { + "title": "Latest community reviews" + }, + "cta": { + "title": "Built an AI tool?", + "body": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "button": "Submit your tool" + }, + "popular": { + "label": "Popular:" + }, + "toolsCount": "{count} tools", + "feed": { + "title": "Today's feed", + "browse": "Browse all products" + }, + "leaderboard": { + "title": "Leaderboard", + "full": "Full leaderboard" + }, + "picks": { + "title": "Editor's picks" + }, + "collections": { + "title": "Collections" + }, + "launch": { + "button": "Launch your product" + }, + "featured": { + "label": "Featured story", + "read": "Read the story" + }, + "picksEditorial": { + "label": "Editor's picks" + }, + "guides": { + "title": "Buying guides", + "subtitle": "Deep dives that help you choose", + "viewAll": "All guides" + }, + "stories": { + "title": "Latest stories", + "viewAll": "All stories" + }, + "community": { + "title": "From the community", + "viewAll": "Browse directory" + }, + "ship": { + "title": "Ship faster with AI", + "subtitle": "Pick your workflow — we ranked the tools for it", + "viewAll": "All use cases" + }, + "upvoted": { + "title": "Most upvoted this week", + "viewAll": "View all" + }, + "workflows": { + "title": "Workflows & stacks", + "subtitle": "Batteries-included tool stacks for common dev tasks", + "viewAll": "All workflows" + }, + "browseCategory": { + "title": "Browse by category" + }, + "trendingNow": { + "title": "Trending now" + }, + "seeRankings": "See full rankings", + "browse": "Browse tools", + "noLaunches": "No launches yet — be the first to submit.", + "searchPlaceholder": "Search AI tools...", + "reviewsCount": "{count} reviews", + "mastheadLabel": "INDEPENDENT AI COVERAGE", + "minimalTagline": "AI TOOL SEARCH", + "minimalPlaceholder": "I need to create marketing videos...", + "useCasesBlockTitle": "Use cases", + "goodForBlockTitle": "Good for", + "searchButton": "Search", + "trendingTitle": "Trending this week", + "trendingSubtitle": "Ranked by votes, reviews and engagement over the last 7 days", + "allRankings": "All rankings", + "categoriesTitle": "Browse by category", + "categoriesViewAll": "All tools", + "newTitle": "New AI tools", + "editorsTitle": "Editor's Choice", + "useCasesTitle": "Tools by use case", + "useCasesSubtitle": "What do you want to get done?", + "useCasesViewAll": "All use cases", + "bestListsTitle": "Best AI tool lists", + "bestListsSubtitle": "Curated rankings by our editors", + "bestListsViewAll": "All lists", + "reviewsTitle": "Latest community reviews", + "ctaTitle": "Built an AI tool?", + "ctaBody": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "ctaButton": "Submit your tool", + "popularLabel": "Popular:", + "feedTitle": "Today's feed", + "feedBrowse": "Browse all products", + "leaderboardTitle": "Leaderboard", + "leaderboardFull": "Full leaderboard", + "picksTitle": "Editor's picks", + "collectionsTitle": "Collections", + "launchButton": "Launch your product", + "featuredLabel": "Featured story", + "featuredRead": "Read the story", + "picksEditorialLabel": "EDITOR'S PICKS", + "guidesTitle": "Buying guides", + "guidesSubtitle": "Deep dives that help you choose", + "guidesViewAll": "All guides", + "storiesTitle": "Latest stories", + "storiesViewAll": "All stories", + "communityTitle": "From the community", + "communityViewAll": "Browse directory", + "shipTitle": "Ship faster with AI", + "shipSubtitle": "Pick your workflow — we ranked the tools for it", + "upvotedTitle": "Most upvoted this week", + "upvotedViewAll": "View all", + "workflowsTitle": "Workflows & stacks", + "workflowsSubtitle": "Batteries-included tool stacks for common dev tasks", + "workflowsViewAll": "All workflows", + "browseCategoryTitle": "Browse by category", + "trendingNowTitle": "Trending now", + "browseButton": "Browse tools", + "toolsCompared": "{count} tools compared", + "popularSearches": [ + "writing", + "video", + "coding", + "image" + ] + }, + "best": { + "indexTitle": "Best AI Tools — Curated Lists", + "indexSubtitle": "Hand-picked rankings, updated with community signal. Every list is labeled and never sold.", + "empty": "No collections published yet.", + "curated": "Curated list", + "faq": "Frequently asked questions", + "more": "More best lists", + "toolsCompared": "{count} tools" + }, + "aiToolsFor": { + "indexTitle": "AI tools for what you do", + "indexSubtitle": "Skip the categories. Start from your task or your role — every page ranks tools by real community votes and reviews.", + "byTask": "By task", + "byAudience": "By audience", + "noData": "No use cases yet.", + "noAud": "No audiences yet.", + "noTools": "No tools tagged yet." + }, + "submitPage": { + "title": "Submit your AI tool", + "subtitle": "Get a free listing with community votes, user reviews and analytics. Submissions are reviewed by our editors, usually within 48 hours." + }, + "faq": { + "title": "Frequently asked questions" + }, + "compare": { + "intro": "A side-by-side comparison based on community votes, ratings and reviews — not sponsored placement.", + "leaning": "Right now the community leans toward {name}.", + "label": "Compare", + "noReviews": "—", + "latest": "Latest review" + }, + "alternatives": { + "noAlt": "No alternatives found yet.", + "thisTool": "{name} (this tool)", + "table": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + }, + "zhTable": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + } + }, + "notFound": { + "code": "404", + "title": "Page not found", + "body": "The page you are looking for doesn't exist or may have moved.", + "home": "Back to home", + "tools": "Browse tools" + }, + "search": { + "placeholder": "Search 1,000+ AI tools...", + "button": "Search" + }, + "siteFooter": { + "groups": [ + { + "title": "Discover", + "links": [ + { + "label": "All Tools", + "href": "/tools" + }, + { + "label": "Use Cases", + "href": "/ai-tools-for" + }, + { + "label": "Best Lists", + "href": "/best" + }, + { + "label": "Rankings", + "href": "/rankings" + } + ] + }, + { + "title": "Community", + "links": [ + { + "label": "Submit a Tool", + "href": "/submit" + }, + { + "label": "Blog", + "href": "/blog" + }, + { + "label": "Dashboard", + "href": "/dashboard" + } + ] + }, + { + "title": "Legal", + "links": [ + { + "label": "Terms", + "href": "/terms" + }, + { + "label": "Privacy", + "href": "/privacy" + }, + { + "label": "Contact", + "href": "/contact" + } + ] + } + ] + }, + "siteHeader": { + "searchPlaceholder": "Search AI tools..." } } diff --git a/sites/ai-stack/messages/zh.json b/sites/ai-stack/messages/zh.json index b3d420c..22828d8 100644 --- a/sites/ai-stack/messages/zh.json +++ b/sites/ai-stack/messages/zh.json @@ -53,12 +53,29 @@ "linkedin": "领英", "github": "GitHub" } + }, + "site": { + "items": [ + "发现", + "用例", + "最佳清单", + "排行榜", + "博客", + "提交工具" + ], + "hrefs": [ + "/tools", + "/ai-tools-for", + "/best", + "/rankings", + "/blog", + "/submit" + ] } }, "hero": { - "badge": "发现最好的 AI 工具", - "title": "AI Stack — 由真实用户排名的 AI 工具目录", - "description": "专业 AI 工具导航:14 个分类、1000+ 工具,由社区投票、评论与互动数据实时排名。", + "title": "找到最好的 AI 工具,由真实用户排名", + "description": "14 个分类、1000+ AI 工具。对比投票、评论与定价,选出最适合你的。", "cta": { "primary": "探索工具", "secondary": "阅读博客" @@ -657,7 +674,9 @@ "latest": "最新", "trending": "最热" }, - "clearFilters": "清除搜索与筛选" + "clearFilters": "清除搜索与筛选", + "useCasesTitle": "使用场景", + "goodForTitle": "适合人群" }, "seo": { "home": { @@ -804,5 +823,284 @@ "new": "最新收录", "editorsChoice": "编辑精选", "empty": "该榜单暂无工具。" + }, + "siteHome": { + "trending": { + "title": "本周趋势", + "subtitle": "按最近 7 天投票、评论与互动排名" + }, + "categories": { + "title": "按分类浏览", + "viewAll": "全部工具" + }, + "new": { + "title": "最新收录" + }, + "editors": { + "title": "编辑精选" + }, + "useCases": { + "title": "按用例找工具", + "subtitle": "你想完成什么?", + "viewAll": "全部用例" + }, + "bestLists": { + "title": "最佳 AI 工具清单", + "subtitle": "编辑精选排名", + "viewAll": "全部清单" + }, + "reviews": { + "title": "最新社区评论" + }, + "cta": { + "title": "做了 AI 工具?", + "body": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "button": "提交你的工具" + }, + "popular": { + "label": "热门:" + }, + "toolsCount": "{count} 个工具", + "feed": { + "title": "今日发布流", + "browse": "浏览全部产品" + }, + "leaderboard": { + "title": "排行榜", + "full": "完整榜单" + }, + "picks": { + "title": "编辑推荐" + }, + "collections": { + "title": "合集" + }, + "launch": { + "button": "发布你的产品" + }, + "featured": { + "label": "头条文章", + "read": "阅读全文" + }, + "picksEditorial": { + "label": "编辑推荐" + }, + "guides": { + "title": "选购指南", + "subtitle": "帮你做决定的深度对比", + "viewAll": "全部指南" + }, + "stories": { + "title": "最新文章", + "viewAll": "全部文章" + }, + "community": { + "title": "来自社区", + "viewAll": "浏览目录" + }, + "ship": { + "title": "用 AI 加速交付", + "subtitle": "选好工作流,我们为它排好了工具", + "viewAll": "全部用例" + }, + "upvoted": { + "title": "本周最多投票", + "viewAll": "查看全部" + }, + "workflows": { + "title": "工作流与技术栈", + "subtitle": "常见开发任务的完整工具组合", + "viewAll": "全部工作流" + }, + "browseCategory": { + "title": "按分类浏览" + }, + "trendingNow": { + "title": "当前趋势" + }, + "seeRankings": "查看完整排行", + "browse": "浏览工具", + "noLaunches": "还没有发布——来做第一个。", + "searchPlaceholder": "搜索 AI 工具...", + "reviewsCount": "{count} 条评论", + "mastheadLabel": "独立 AI 报道", + "minimalTagline": "AI 工具搜索", + "minimalPlaceholder": "我需要制作营销视频……", + "useCasesBlockTitle": "使用场景", + "goodForBlockTitle": "适合人群", + "searchButton": "搜索", + "trendingTitle": "本周趋势", + "trendingSubtitle": "按最近 7 天投票、评论与互动排名", + "allRankings": "全部榜单", + "categoriesTitle": "按分类浏览", + "categoriesViewAll": "全部工具", + "newTitle": "最新收录", + "editorsTitle": "编辑精选", + "useCasesTitle": "按用例找工具", + "useCasesSubtitle": "你想完成什么?", + "useCasesViewAll": "全部用例", + "bestListsTitle": "最佳 AI 工具清单", + "bestListsSubtitle": "编辑精选排名", + "bestListsViewAll": "全部清单", + "reviewsTitle": "最新社区评论", + "ctaTitle": "做了 AI 工具?", + "ctaBody": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "ctaButton": "提交你的工具", + "popularLabel": "热门:", + "feedTitle": "今日发布流", + "feedBrowse": "浏览全部产品", + "leaderboardTitle": "排行榜", + "leaderboardFull": "完整榜单", + "picksTitle": "编辑推荐", + "collectionsTitle": "合集", + "launchButton": "发布你的产品", + "featuredLabel": "头条文章", + "featuredRead": "阅读全文", + "picksEditorialLabel": "编辑推荐", + "guidesTitle": "选购指南", + "guidesSubtitle": "帮你做决定的深度对比", + "guidesViewAll": "全部指南", + "storiesTitle": "最新文章", + "storiesViewAll": "全部文章", + "communityTitle": "来自社区", + "communityViewAll": "浏览目录", + "shipTitle": "用 AI 加速交付", + "shipSubtitle": "选好工作流,我们为它排好了工具", + "upvotedTitle": "本周最多投票", + "upvotedViewAll": "查看全部", + "workflowsTitle": "工作流与技术栈", + "workflowsSubtitle": "常见开发任务的完整工具组合", + "workflowsViewAll": "全部工作流", + "browseCategoryTitle": "按分类浏览", + "trendingNowTitle": "当前趋势", + "browseButton": "浏览工具", + "toolsCompared": "{count} 个工具", + "popularSearches": [ + "写作", + "视频", + "编程", + "图像" + ] + }, + "best": { + "indexTitle": "最佳 AI 工具——精选清单", + "indexSubtitle": "人工精选排名,持续吸收社区信号。每个清单都明确标注,永不售卖。", + "empty": "暂无合集。", + "curated": "编辑精选", + "faq": "常见问题", + "more": "更多最佳清单", + "toolsCompared": "{count} 个工具" + }, + "aiToolsFor": { + "indexTitle": "按任务找 AI 工具", + "indexSubtitle": "别再翻分类。从你的任务或角色出发——每页都按真实社区投票与评论排名。", + "byTask": "按任务", + "byAudience": "按人群", + "noData": "暂无用例。", + "noAud": "暂无人群。", + "noTools": "暂无关联工具。" + }, + "submitPage": { + "title": "提交你的 AI 工具", + "subtitle": "免费收录,获得社区投票、用户评论与数据分析。编辑通常在 48 小时内完成审核。" + }, + "faq": { + "title": "常见问题" + }, + "compare": { + "intro": "基于社区投票、评分与评论的并排对比——非赞助排名。", + "leaning": "当前社区更倾向 {name}。", + "label": "对比", + "noReviews": "—", + "latest": "最新评论" + }, + "alternatives": { + "noAlt": "暂无替代品。", + "thisTool": "{name}(本工具)", + "table": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + }, + "zhTable": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + } + }, + "notFound": { + "code": "404", + "title": "页面不存在", + "body": "你访问的页面不存在或已被移动。", + "home": "返回首页", + "tools": "浏览工具" + }, + "search": { + "placeholder": "搜索 1000+ AI 工具...", + "button": "搜索" + }, + "siteFooter": { + "groups": [ + { + "title": "发现", + "links": [ + { + "label": "All Tools", + "href": "/tools" + }, + { + "label": "Use Cases", + "href": "/ai-tools-for" + }, + { + "label": "Best Lists", + "href": "/best" + }, + { + "label": "Rankings", + "href": "/rankings" + } + ] + }, + { + "title": "社区", + "links": [ + { + "label": "Submit a Tool", + "href": "/submit" + }, + { + "label": "Blog", + "href": "/blog" + }, + { + "label": "Dashboard", + "href": "/dashboard" + } + ] + }, + { + "title": "法律", + "links": [ + { + "label": "Terms", + "href": "/terms" + }, + { + "label": "Privacy", + "href": "/privacy" + }, + { + "label": "Contact", + "href": "/contact" + } + ] + } + ] + }, + "siteHeader": { + "searchPlaceholder": "搜索 1000+ AI 工具..." } } diff --git a/sites/ai-stack/src/app/[locale]/not-found.tsx b/sites/ai-stack/src/app/[locale]/not-found.tsx new file mode 100644 index 0000000..d19cc76 --- /dev/null +++ b/sites/ai-stack/src/app/[locale]/not-found.tsx @@ -0,0 +1,2 @@ +// 自动生成:[locale]/not-found.tsx 的薄路由 +export { default } from "@aidir/core/pages/[locale]/not-found"; diff --git a/sites/ai-stack/src/i18n/request.ts b/sites/ai-stack/src/i18n/request.ts index 48fd29b..8def25f 100644 --- a/sites/ai-stack/src/i18n/request.ts +++ b/sites/ai-stack/src/i18n/request.ts @@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config"; const brandMessages = { en: { seo: { home: {"title":"AI Stack — Find the Best AI Tools, Ranked by Real Users","description":"The professional AI tools directory. 1,000+ AI tools across 14 categories ranked by community votes, reviews and engagement.","ogImage":"/og-image.png"} }, - hero: { title: "AI Stack — Find the Best AI Tools, Ranked by Real Users", description: "The professional AI tools directory. 1,000+ AI tools across 14 categories ranked by community votes, reviews and engagement." }, + hero: { title: "Find the best AI tools, ranked by real users", description: "1,000+ AI tools across 14 categories. Compare votes, reviews and pricing to pick the right one." }, common: { brand: { name: "AI Stack", tagline: "The professional AI tools directory — ranked by the community." } }, + navigation: { + main: { tools: "Discover", blog: "Blog" }, + site: { items: ["Discover","Use Cases","Best Lists","Rankings","Blog","Submit"], hrefs: ["/tools","/ai-tools-for","/best","/rankings","/blog","/submit"] }, + }, + siteFooter: { groups: [{"title":"Discover","links":[{"label":"All Tools","href":"/tools"},{"label":"Use Cases","href":"/ai-tools-for"},{"label":"Best Lists","href":"/best"},{"label":"Rankings","href":"/rankings"}]},{"title":"Community","links":[{"label":"Submit a Tool","href":"/submit"},{"label":"Blog","href":"/blog"},{"label":"Dashboard","href":"/dashboard"}]},{"title":"Legal","links":[{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"},{"label":"Contact","href":"/contact"}]}] }, + siteHeader: { searchPlaceholder: "Search AI tools..." }, }, zh: { seo: { home: {"title":"AI Stack — 由真实用户排名的 AI 工具目录","description":"专业 AI 工具导航:14 个分类、1000+ 工具,由社区投票、评论与互动数据实时排名。","ogImage":"/og-image.png"} }, - hero: { title: "AI Stack — 由真实用户排名的 AI 工具目录", description: "专业 AI 工具导航:14 个分类、1000+ 工具,由社区投票、评论与互动数据实时排名。" }, - common: { brand: { name: "AI Stack", tagline: "The professional AI tools directory — ranked by the community." } }, + hero: { title: "找到最好的 AI 工具,由真实用户排名", description: "14 个分类、1000+ AI 工具。对比投票、评论与定价,选出最适合你的。" }, + common: { brand: { name: "AI Stack", tagline: "由真实用户排名的专业 AI 工具目录。" } }, + navigation: { + main: { tools: "发现", blog: "博客" }, + site: { items: ["发现","用例","最佳清单","排行榜","博客","提交工具"], hrefs: ["/tools","/ai-tools-for","/best","/rankings","/blog","/submit"] }, + }, + siteFooter: { groups: [{"title":"发现","links":[{"label":"All Tools","href":"/tools"},{"label":"Use Cases","href":"/ai-tools-for"},{"label":"Best Lists","href":"/best"},{"label":"Rankings","href":"/rankings"}]},{"title":"社区","links":[{"label":"Submit a Tool","href":"/submit"},{"label":"Blog","href":"/blog"},{"label":"Dashboard","href":"/dashboard"}]},{"title":"法律","links":[{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"},{"label":"Contact","href":"/contact"}]}] }, + siteHeader: { searchPlaceholder: "搜索 1000+ AI 工具..." }, }, } as const; diff --git a/sites/ai-stack/src/site/brand.tsx b/sites/ai-stack/src/site/brand.tsx index 07c0113..7cc836a 100644 --- a/sites/ai-stack/src/site/brand.tsx +++ b/sites/ai-stack/src/site/brand.tsx @@ -2,6 +2,26 @@ import type { SiteConfig } from "@/kit/types"; // AI Stack —— 独立站点的全部品牌/导航/页脚配置 export const siteConfig: SiteConfig = { + "brandZh": { + "name": "AI Stack", + "tagline": "由真实用户排名的专业 AI 工具目录。", + "headline": "找到最好的 AI 工具,由真实用户排名", + "subheadline": "14 个分类、1000+ AI 工具。对比投票、评论与定价,选出最适合你的。", + "nav": [ + "发现", + "用例", + "最佳清单", + "排行榜", + "博客", + "提交工具" + ], + "footer": [ + "发现", + "社区", + "法律" + ], + "searchPlaceholder": "搜索 1000+ AI 工具..." + }, "accent": "222 47% 11%", "port": 3001, "brand": { diff --git a/sites/ai-stack/src/site/home.tsx b/sites/ai-stack/src/site/home.tsx index 0e542ea..de1259f 100644 --- a/sites/ai-stack/src/site/home.tsx +++ b/sites/ai-stack/src/site/home.tsx @@ -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 }) {

    - {siteConfig.brand.headline} + {th("title")}

    - {siteConfig.brand.subheadline} + {th("description")}

    @@ -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")}
    - Popular: - {["writing", "video", "coding", "image"].map((q) => ( + {t("popularLabel")} + {t.raw("popularSearches").map((q: string) => ( 0 && (
    @@ -113,9 +116,9 @@ async function SiteHome({ locale }: { locale: string }) { {data.categories.length > 0 && (
    {data.categories.slice(0, 10).map((category) => ( @@ -144,7 +147,7 @@ async function SiteHome({ locale }: { locale: string }) { {data.newest.length > 0 && (
    @@ -153,7 +156,7 @@ async function SiteHome({ locale }: { locale: string }) { {data.editorsChoice.length > 0 && (
    @@ -165,10 +168,10 @@ async function SiteHome({ locale }: { locale: string }) { {data.useCases.length > 0 && (
    {data.useCases.slice(0, 12).map((uc) => ( @@ -191,10 +194,10 @@ async function SiteHome({ locale }: { locale: string }) { {data.collections.length > 0 && (
    {data.collections.slice(0, 3).map((col) => ( @@ -222,7 +225,7 @@ async function SiteHome({ locale }: { locale: string }) { {/* Latest Reviews */} {data.latestReviews.length > 0 && (
    - +
    {data.latestReviews.map((review, i) => (

    - {siteConfig.brand.headline} + {th("title")}

    - {siteConfig.brand.subheadline} + {th("description")}

    0 && (

    {data.useCases.slice(0, 6).map((uc) => ( @@ -119,7 +122,7 @@ async function SiteHome({ locale }: { locale: string }) { {data.trending.length > 0 && (
    @@ -139,10 +142,10 @@ async function SiteHome({ locale }: { locale: string }) { {data.collections.length > 0 && (
    {data.collections.slice(0, 3).map((col) => ( @@ -167,7 +170,7 @@ async function SiteHome({ locale }: { locale: string }) { {/* Categories */} {data.categories.length > 0 && (
    - +
    {data.categories.slice(0, 14).map((cat) => ( @@ -95,7 +98,7 @@ async function SiteHome({ locale }: { locale: string }) { href="/rankings" className="text-xs font-medium text-muted-foreground hover:text-primary" > - See full rankings + {t("seeRankings")}
    diff --git a/sites/launchai/messages/en.json b/sites/launchai/messages/en.json index 43d883e..2e71e05 100644 --- a/sites/launchai/messages/en.json +++ b/sites/launchai/messages/en.json @@ -53,12 +53,30 @@ "linkedin": "LinkedIn", "github": "GitHub" } + }, + "site": { + "items": [ + "Today", + "Leaderboard", + "Categories", + "Collections", + "Blog", + "Submit" + ], + "hrefs": [ + "/", + "/rankings", + "/tools", + "/best", + "/blog", + "/submit" + ] } }, "hero": { "badge": "Discover the Best AI Tools", - "title": "LaunchAI — Discover and Upvote Today's AI Products", - "description": "A daily launch feed for AI products. Upvote the best AI tools, follow makers and climb the leaderboard.", + "title": "Today's AI product launches", + "description": "Fresh AI products, every day. Upvote the best ones to the top.", "cta": { "primary": "Explore Tools", "secondary": "Read Blog" @@ -649,7 +667,9 @@ "latest": "Latest", "trending": "Trending" }, - "clearFilters": "Clear search & filters" + "clearFilters": "Clear search & filters", + "useCasesTitle": "Use cases", + "goodForTitle": "Good for" }, "seo": { "home": { @@ -796,5 +816,280 @@ "new": "New", "editorsChoice": "Editor's Choice", "empty": "No tools on this board yet." + }, + "siteHome": { + "trending": { + "title": "Trending this week", + "subtitle": "Ranked by votes, reviews and engagement over the last 7 days" + }, + "categories": { + "title": "Browse by category", + "viewAll": "All tools" + }, + "new": { + "title": "New AI tools" + }, + "editors": { + "title": "Editor's Choice" + }, + "useCases": { + "title": "Tools by use case", + "subtitle": "What do you want to get done?", + "viewAll": "All use cases" + }, + "bestLists": { + "title": "Best AI tool lists", + "subtitle": "Curated rankings by our editors", + "viewAll": "All lists" + }, + "reviews": { + "title": "Latest community reviews" + }, + "cta": { + "title": "Built an AI tool?", + "body": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "button": "Submit your tool" + }, + "popular": { + "label": "Popular:" + }, + "toolsCount": "{count} tools", + "feed": { + "title": "Today's feed", + "browse": "Browse all products" + }, + "leaderboard": { + "title": "Leaderboard", + "full": "Full leaderboard" + }, + "picks": { + "title": "Editor's picks" + }, + "collections": { + "title": "Collections" + }, + "launch": { + "button": "Launch your product" + }, + "featured": { + "label": "Featured story", + "read": "Read the story" + }, + "picksEditorial": { + "label": "Editor's picks" + }, + "guides": { + "title": "Buying guides", + "subtitle": "Deep dives that help you choose", + "viewAll": "All guides" + }, + "stories": { + "title": "Latest stories", + "viewAll": "All stories" + }, + "community": { + "title": "From the community", + "viewAll": "Browse directory" + }, + "ship": { + "title": "Ship faster with AI", + "subtitle": "Pick your workflow — we ranked the tools for it", + "viewAll": "All use cases" + }, + "upvoted": { + "title": "Most upvoted this week", + "viewAll": "View all" + }, + "workflows": { + "title": "Workflows & stacks", + "subtitle": "Batteries-included tool stacks for common dev tasks", + "viewAll": "All workflows" + }, + "browseCategory": { + "title": "Browse by category" + }, + "trendingNow": { + "title": "Trending now" + }, + "seeRankings": "See full rankings", + "browse": "Browse tools", + "noLaunches": "No launches yet — be the first to submit.", + "searchPlaceholder": "Search AI tools...", + "reviewsCount": "{count} reviews", + "mastheadLabel": "INDEPENDENT AI COVERAGE", + "minimalTagline": "AI TOOL SEARCH", + "minimalPlaceholder": "I need to create marketing videos...", + "useCasesBlockTitle": "Use cases", + "goodForBlockTitle": "Good for", + "searchButton": "Search", + "trendingTitle": "Trending this week", + "trendingSubtitle": "Ranked by votes, reviews and engagement over the last 7 days", + "allRankings": "All rankings", + "categoriesTitle": "Browse by category", + "categoriesViewAll": "All tools", + "newTitle": "New AI tools", + "editorsTitle": "Editor's Choice", + "useCasesTitle": "Tools by use case", + "useCasesSubtitle": "What do you want to get done?", + "useCasesViewAll": "All use cases", + "bestListsTitle": "Best AI tool lists", + "bestListsSubtitle": "Curated rankings by our editors", + "bestListsViewAll": "All lists", + "reviewsTitle": "Latest community reviews", + "ctaTitle": "Built an AI tool?", + "ctaBody": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "ctaButton": "Submit your tool", + "popularLabel": "Popular:", + "feedTitle": "Today's feed", + "feedBrowse": "Browse all products", + "leaderboardTitle": "Leaderboard", + "leaderboardFull": "Full leaderboard", + "picksTitle": "Editor's picks", + "collectionsTitle": "Collections", + "launchButton": "Launch your product", + "featuredLabel": "Featured story", + "featuredRead": "Read the story", + "picksEditorialLabel": "EDITOR'S PICKS", + "guidesTitle": "Buying guides", + "guidesSubtitle": "Deep dives that help you choose", + "guidesViewAll": "All guides", + "storiesTitle": "Latest stories", + "storiesViewAll": "All stories", + "communityTitle": "From the community", + "communityViewAll": "Browse directory", + "shipTitle": "Ship faster with AI", + "shipSubtitle": "Pick your workflow — we ranked the tools for it", + "upvotedTitle": "Most upvoted this week", + "upvotedViewAll": "View all", + "workflowsTitle": "Workflows & stacks", + "workflowsSubtitle": "Batteries-included tool stacks for common dev tasks", + "workflowsViewAll": "All workflows", + "browseCategoryTitle": "Browse by category", + "trendingNowTitle": "Trending now", + "browseButton": "Browse tools", + "toolsCompared": "{count} tools compared", + "popularSearches": [ + "writing", + "video", + "coding", + "image" + ] + }, + "best": { + "indexTitle": "Best AI Tools — Curated Lists", + "indexSubtitle": "Hand-picked rankings, updated with community signal. Every list is labeled and never sold.", + "empty": "No collections published yet.", + "curated": "Curated list", + "faq": "Frequently asked questions", + "more": "More best lists", + "toolsCompared": "{count} tools" + }, + "aiToolsFor": { + "indexTitle": "AI tools for what you do", + "indexSubtitle": "Skip the categories. Start from your task or your role — every page ranks tools by real community votes and reviews.", + "byTask": "By task", + "byAudience": "By audience", + "noData": "No use cases yet.", + "noAud": "No audiences yet.", + "noTools": "No tools tagged yet." + }, + "submitPage": { + "title": "Submit your AI tool", + "subtitle": "Get a free listing with community votes, user reviews and analytics. Submissions are reviewed by our editors, usually within 48 hours." + }, + "faq": { + "title": "Frequently asked questions" + }, + "compare": { + "intro": "A side-by-side comparison based on community votes, ratings and reviews — not sponsored placement.", + "leaning": "Right now the community leans toward {name}.", + "label": "Compare", + "noReviews": "—", + "latest": "Latest review" + }, + "alternatives": { + "noAlt": "No alternatives found yet.", + "thisTool": "{name} (this tool)", + "table": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + }, + "zhTable": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + } + }, + "notFound": { + "code": "404", + "title": "Page not found", + "body": "The page you are looking for doesn't exist or may have moved.", + "home": "Back to home", + "tools": "Browse tools" + }, + "search": { + "placeholder": "Search 1,000+ AI tools...", + "button": "Search" + }, + "siteFooter": { + "groups": [ + { + "title": "Community", + "links": [ + { + "label": "Submit a Product", + "href": "/submit" + }, + { + "label": "Leaderboard", + "href": "/rankings" + }, + { + "label": "Dashboard", + "href": "/dashboard" + } + ] + }, + { + "title": "Explore", + "links": [ + { + "label": "All Products", + "href": "/tools" + }, + { + "label": "Use Cases", + "href": "/ai-tools-for" + }, + { + "label": "Collections", + "href": "/best" + } + ] + }, + { + "title": "About", + "links": [ + { + "label": "Blog", + "href": "/blog" + }, + { + "label": "Terms", + "href": "/terms" + }, + { + "label": "Privacy", + "href": "/privacy" + } + ] + } + ] + }, + "siteHeader": { + "searchPlaceholder": "Search AI products..." } } diff --git a/sites/launchai/messages/zh.json b/sites/launchai/messages/zh.json index 25aab40..b3d9e87 100644 --- a/sites/launchai/messages/zh.json +++ b/sites/launchai/messages/zh.json @@ -53,12 +53,29 @@ "linkedin": "领英", "github": "GitHub" } + }, + "site": { + "items": [ + "今日", + "排行榜", + "分类", + "合集", + "博客", + "提交产品" + ], + "hrefs": [ + "/", + "/rankings", + "/tools", + "/best", + "/blog", + "/submit" + ] } }, "hero": { - "badge": "发现最好的 AI 工具", - "title": "LaunchAI — 发现并投票今日 AI 新品", - "description": "AI 产品每日发布社区:为最好的 AI 工具投票,登上社区排行榜。", + "title": "今日 AI 产品发布", + "description": "每天上新。为最好的产品投票,冲上排行榜。", "cta": { "primary": "探索工具", "secondary": "阅读博客" @@ -657,7 +674,9 @@ "latest": "最新", "trending": "最热" }, - "clearFilters": "清除搜索与筛选" + "clearFilters": "清除搜索与筛选", + "useCasesTitle": "使用场景", + "goodForTitle": "适合人群" }, "seo": { "home": { @@ -804,5 +823,280 @@ "new": "最新收录", "editorsChoice": "编辑精选", "empty": "该榜单暂无工具。" + }, + "siteHome": { + "trending": { + "title": "本周趋势", + "subtitle": "按最近 7 天投票、评论与互动排名" + }, + "categories": { + "title": "按分类浏览", + "viewAll": "全部工具" + }, + "new": { + "title": "最新收录" + }, + "editors": { + "title": "编辑精选" + }, + "useCases": { + "title": "按用例找工具", + "subtitle": "你想完成什么?", + "viewAll": "全部用例" + }, + "bestLists": { + "title": "最佳 AI 工具清单", + "subtitle": "编辑精选排名", + "viewAll": "全部清单" + }, + "reviews": { + "title": "最新社区评论" + }, + "cta": { + "title": "做了 AI 工具?", + "body": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "button": "提交你的工具" + }, + "popular": { + "label": "热门:" + }, + "toolsCount": "{count} 个工具", + "feed": { + "title": "今日发布流", + "browse": "浏览全部产品" + }, + "leaderboard": { + "title": "排行榜", + "full": "完整榜单" + }, + "picks": { + "title": "编辑推荐" + }, + "collections": { + "title": "合集" + }, + "launch": { + "button": "发布你的产品" + }, + "featured": { + "label": "头条文章", + "read": "阅读全文" + }, + "picksEditorial": { + "label": "编辑推荐" + }, + "guides": { + "title": "选购指南", + "subtitle": "帮你做决定的深度对比", + "viewAll": "全部指南" + }, + "stories": { + "title": "最新文章", + "viewAll": "全部文章" + }, + "community": { + "title": "来自社区", + "viewAll": "浏览目录" + }, + "ship": { + "title": "用 AI 加速交付", + "subtitle": "选好工作流,我们为它排好了工具", + "viewAll": "全部用例" + }, + "upvoted": { + "title": "本周最多投票", + "viewAll": "查看全部" + }, + "workflows": { + "title": "工作流与技术栈", + "subtitle": "常见开发任务的完整工具组合", + "viewAll": "全部工作流" + }, + "browseCategory": { + "title": "按分类浏览" + }, + "trendingNow": { + "title": "当前趋势" + }, + "seeRankings": "查看完整排行", + "browse": "浏览工具", + "noLaunches": "还没有发布——来做第一个。", + "searchPlaceholder": "搜索 AI 工具...", + "reviewsCount": "{count} 条评论", + "mastheadLabel": "独立 AI 报道", + "minimalTagline": "AI 工具搜索", + "minimalPlaceholder": "我需要制作营销视频……", + "useCasesBlockTitle": "使用场景", + "goodForBlockTitle": "适合人群", + "searchButton": "搜索", + "trendingTitle": "本周趋势", + "trendingSubtitle": "按最近 7 天投票、评论与互动排名", + "allRankings": "全部榜单", + "categoriesTitle": "按分类浏览", + "categoriesViewAll": "全部工具", + "newTitle": "最新收录", + "editorsTitle": "编辑精选", + "useCasesTitle": "按用例找工具", + "useCasesSubtitle": "你想完成什么?", + "useCasesViewAll": "全部用例", + "bestListsTitle": "最佳 AI 工具清单", + "bestListsSubtitle": "编辑精选排名", + "bestListsViewAll": "全部清单", + "reviewsTitle": "最新社区评论", + "ctaTitle": "做了 AI 工具?", + "ctaBody": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "ctaButton": "提交你的工具", + "popularLabel": "热门:", + "feedTitle": "今日发布流", + "feedBrowse": "浏览全部产品", + "leaderboardTitle": "排行榜", + "leaderboardFull": "完整榜单", + "picksTitle": "编辑推荐", + "collectionsTitle": "合集", + "launchButton": "发布你的产品", + "featuredLabel": "头条文章", + "featuredRead": "阅读全文", + "picksEditorialLabel": "编辑推荐", + "guidesTitle": "选购指南", + "guidesSubtitle": "帮你做决定的深度对比", + "guidesViewAll": "全部指南", + "storiesTitle": "最新文章", + "storiesViewAll": "全部文章", + "communityTitle": "来自社区", + "communityViewAll": "浏览目录", + "shipTitle": "用 AI 加速交付", + "shipSubtitle": "选好工作流,我们为它排好了工具", + "upvotedTitle": "本周最多投票", + "upvotedViewAll": "查看全部", + "workflowsTitle": "工作流与技术栈", + "workflowsSubtitle": "常见开发任务的完整工具组合", + "workflowsViewAll": "全部工作流", + "browseCategoryTitle": "按分类浏览", + "trendingNowTitle": "当前趋势", + "browseButton": "浏览工具", + "toolsCompared": "{count} 个工具", + "popularSearches": [ + "写作", + "视频", + "编程", + "图像" + ] + }, + "best": { + "indexTitle": "最佳 AI 工具——精选清单", + "indexSubtitle": "人工精选排名,持续吸收社区信号。每个清单都明确标注,永不售卖。", + "empty": "暂无合集。", + "curated": "编辑精选", + "faq": "常见问题", + "more": "更多最佳清单", + "toolsCompared": "{count} 个工具" + }, + "aiToolsFor": { + "indexTitle": "按任务找 AI 工具", + "indexSubtitle": "别再翻分类。从你的任务或角色出发——每页都按真实社区投票与评论排名。", + "byTask": "按任务", + "byAudience": "按人群", + "noData": "暂无用例。", + "noAud": "暂无人群。", + "noTools": "暂无关联工具。" + }, + "submitPage": { + "title": "提交你的 AI 工具", + "subtitle": "免费收录,获得社区投票、用户评论与数据分析。编辑通常在 48 小时内完成审核。" + }, + "faq": { + "title": "常见问题" + }, + "compare": { + "intro": "基于社区投票、评分与评论的并排对比——非赞助排名。", + "leaning": "当前社区更倾向 {name}。", + "label": "对比", + "noReviews": "—", + "latest": "最新评论" + }, + "alternatives": { + "noAlt": "暂无替代品。", + "thisTool": "{name}(本工具)", + "table": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + }, + "zhTable": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + } + }, + "notFound": { + "code": "404", + "title": "页面不存在", + "body": "你访问的页面不存在或已被移动。", + "home": "返回首页", + "tools": "浏览工具" + }, + "search": { + "placeholder": "搜索 1000+ AI 工具...", + "button": "搜索" + }, + "siteFooter": { + "groups": [ + { + "title": "社区", + "links": [ + { + "label": "Submit a Product", + "href": "/submit" + }, + { + "label": "Leaderboard", + "href": "/rankings" + }, + { + "label": "Dashboard", + "href": "/dashboard" + } + ] + }, + { + "title": "探索", + "links": [ + { + "label": "All Products", + "href": "/tools" + }, + { + "label": "Use Cases", + "href": "/ai-tools-for" + }, + { + "label": "Collections", + "href": "/best" + } + ] + }, + { + "title": "关于", + "links": [ + { + "label": "Blog", + "href": "/blog" + }, + { + "label": "Terms", + "href": "/terms" + }, + { + "label": "Privacy", + "href": "/privacy" + } + ] + } + ] + }, + "siteHeader": { + "searchPlaceholder": "搜索 AI 产品..." } } diff --git a/sites/launchai/src/app/[locale]/not-found.tsx b/sites/launchai/src/app/[locale]/not-found.tsx new file mode 100644 index 0000000..d19cc76 --- /dev/null +++ b/sites/launchai/src/app/[locale]/not-found.tsx @@ -0,0 +1,2 @@ +// 自动生成:[locale]/not-found.tsx 的薄路由 +export { default } from "@aidir/core/pages/[locale]/not-found"; diff --git a/sites/launchai/src/i18n/request.ts b/sites/launchai/src/i18n/request.ts index 86f12f7..a2a2d65 100644 --- a/sites/launchai/src/i18n/request.ts +++ b/sites/launchai/src/i18n/request.ts @@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config"; const brandMessages = { en: { seo: { home: {"title":"LaunchAI — Discover and Upvote Today's AI Products","description":"A daily launch feed for AI products. Upvote the best AI tools, follow makers and climb the leaderboard.","ogImage":"/og-image.png"} }, - hero: { title: "LaunchAI — Discover and Upvote Today's AI Products", description: "A daily launch feed for AI products. Upvote the best AI tools, follow makers and climb the leaderboard." }, + hero: { title: "Today's AI product launches", description: "Fresh AI products, every day. Upvote the best ones to the top." }, common: { brand: { name: "LaunchAI", tagline: "Discover and upvote today's AI products." } }, + navigation: { + main: { tools: "Today", blog: "Blog" }, + site: { items: ["Today","Leaderboard","Categories","Collections","Blog","Submit"], hrefs: ["/","/rankings","/tools","/best","/blog","/submit"] }, + }, + siteFooter: { groups: [{"title":"Community","links":[{"label":"Submit a Product","href":"/submit"},{"label":"Leaderboard","href":"/rankings"},{"label":"Dashboard","href":"/dashboard"}]},{"title":"Explore","links":[{"label":"All Products","href":"/tools"},{"label":"Use Cases","href":"/ai-tools-for"},{"label":"Collections","href":"/best"}]},{"title":"About","links":[{"label":"Blog","href":"/blog"},{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"}]}] }, + siteHeader: { searchPlaceholder: "Search AI products..." }, }, zh: { seo: { home: {"title":"LaunchAI — 发现并投票今日 AI 新品","description":"AI 产品每日发布社区:为最好的 AI 工具投票,登上社区排行榜。","ogImage":"/og-image.png"} }, - hero: { title: "LaunchAI — 发现并投票今日 AI 新品", description: "AI 产品每日发布社区:为最好的 AI 工具投票,登上社区排行榜。" }, - common: { brand: { name: "LaunchAI", tagline: "Discover and upvote today's AI products." } }, + hero: { title: "今日 AI 产品发布", description: "每天上新。为最好的产品投票,冲上排行榜。" }, + common: { brand: { name: "LaunchAI", tagline: "发现并投票今日的 AI 新品。" } }, + navigation: { + main: { tools: "今日", blog: "博客" }, + site: { items: ["今日","排行榜","分类","合集","博客","提交产品"], hrefs: ["/","/rankings","/tools","/best","/blog","/submit"] }, + }, + siteFooter: { groups: [{"title":"社区","links":[{"label":"Submit a Product","href":"/submit"},{"label":"Leaderboard","href":"/rankings"},{"label":"Dashboard","href":"/dashboard"}]},{"title":"探索","links":[{"label":"All Products","href":"/tools"},{"label":"Use Cases","href":"/ai-tools-for"},{"label":"Collections","href":"/best"}]},{"title":"关于","links":[{"label":"Blog","href":"/blog"},{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"}]}] }, + siteHeader: { searchPlaceholder: "搜索 AI 产品..." }, }, } as const; diff --git a/sites/launchai/src/site/brand.tsx b/sites/launchai/src/site/brand.tsx index 915a231..8c41cdb 100644 --- a/sites/launchai/src/site/brand.tsx +++ b/sites/launchai/src/site/brand.tsx @@ -2,6 +2,26 @@ import type { SiteConfig } from "@/kit/types"; // LaunchAI —— 独立站点的全部品牌/导航/页脚配置 export const siteConfig: SiteConfig = { + "brandZh": { + "name": "LaunchAI", + "tagline": "发现并投票今日的 AI 新品。", + "headline": "今日 AI 产品发布", + "subheadline": "每天上新。为最好的产品投票,冲上排行榜。", + "nav": [ + "今日", + "排行榜", + "分类", + "合集", + "博客", + "提交产品" + ], + "footer": [ + "社区", + "探索", + "关于" + ], + "searchPlaceholder": "搜索 AI 产品..." + }, "accent": "16 85% 55%", "port": 3002, "brand": { diff --git a/sites/launchai/src/site/home.tsx b/sites/launchai/src/site/home.tsx index 51fd621..152b366 100644 --- a/sites/launchai/src/site/home.tsx +++ b/sites/launchai/src/site/home.tsx @@ -1,6 +1,7 @@ // 自动生成:站点首页组件(源自底座 product 形态,品牌来自 @/site/brand) import { siteConfig } from "@/site/brand"; import { Flame, Trophy, Rocket, ChevronRight, MessageSquare } from "lucide-react"; +import { getTranslations } from "next-intl/server"; import { VoteButton } from "@/features/voting/components/vote-button"; import { LocaleLink } from "@/components/locale-link"; import { ToolLogo } from "@/components/tool-logo"; @@ -103,6 +104,8 @@ function LaunchRow({ } async function SiteHome({ locale }: { locale: string }) { + const t = await getTranslations("siteHome"); + const th = await getTranslations("hero"); const data = await getHomeDataSafe(10); return ( @@ -111,17 +114,17 @@ async function SiteHome({ locale }: { locale: string }) {

    - {siteConfig.brand.headline} + {th("title")}

    - {siteConfig.brand.subheadline} + {th("description")}

    - Launch your product + {t("launchButton")}
    @@ -140,14 +143,14 @@ async function SiteHome({ locale }: { locale: string }) { )) ) : (

    - No launches yet — be the first to submit. + {t("noLaunches")}

    )} - Browse all products + {t("feedBrowse")}
    @@ -155,7 +158,7 @@ async function SiteHome({ locale }: { locale: string }) { {/* New */} {data.newest.length > 0 && (
    - +
    {data.newest.slice(0, 5).map((tool) => ( @@ -200,14 +203,14 @@ async function SiteHome({ locale }: { locale: string }) { href="/rankings" className="mt-4 block rounded-lg border border-border py-2 text-center text-xs font-medium text-muted-foreground hover:border-primary/40 hover:text-primary" > - Full leaderboard + {t("leaderboardFull")}
    )} {data.editorsChoice.length > 0 && (
    -

    Editor's picks

    +

    {t("picksEditorialLabel")}

      {data.editorsChoice.slice(0, 4).map((tool) => (
    1. diff --git a/sites/the-ai-ledger/messages/en.json b/sites/the-ai-ledger/messages/en.json index 9f93fe4..6abb629 100644 --- a/sites/the-ai-ledger/messages/en.json +++ b/sites/the-ai-ledger/messages/en.json @@ -53,12 +53,30 @@ "linkedin": "LinkedIn", "github": "GitHub" } + }, + "site": { + "items": [ + "Stories", + "Guides", + "Best Picks", + "Directory", + "Rankings", + "Submit" + ], + "hrefs": [ + "/blog", + "/ai-tools-for", + "/best", + "/tools", + "/rankings", + "/submit" + ] } }, "hero": { "badge": "Discover the Best AI Tools", - "title": "The AI Ledger — AI Tools, Reviewed and Ranked", - "description": "Independent journalism on AI: buying guides, comparisons and a community-ranked directory of the best AI tools.", + "title": "AI tools, reviewed and ranked", + "description": "Guides, comparisons and a community-powered directory of the best AI tools.", "cta": { "primary": "Explore Tools", "secondary": "Read Blog" @@ -649,7 +667,9 @@ "latest": "Latest", "trending": "Trending" }, - "clearFilters": "Clear search & filters" + "clearFilters": "Clear search & filters", + "useCasesTitle": "Use cases", + "goodForTitle": "Good for" }, "seo": { "home": { @@ -796,5 +816,280 @@ "new": "New", "editorsChoice": "Editor's Choice", "empty": "No tools on this board yet." + }, + "siteHome": { + "trending": { + "title": "Trending this week", + "subtitle": "Ranked by votes, reviews and engagement over the last 7 days" + }, + "categories": { + "title": "Browse by category", + "viewAll": "All tools" + }, + "new": { + "title": "New AI tools" + }, + "editors": { + "title": "Editor's Choice" + }, + "useCases": { + "title": "Tools by use case", + "subtitle": "What do you want to get done?", + "viewAll": "All use cases" + }, + "bestLists": { + "title": "Best AI tool lists", + "subtitle": "Curated rankings by our editors", + "viewAll": "All lists" + }, + "reviews": { + "title": "Latest community reviews" + }, + "cta": { + "title": "Built an AI tool?", + "body": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "button": "Submit your tool" + }, + "popular": { + "label": "Popular:" + }, + "toolsCount": "{count} tools", + "feed": { + "title": "Today's feed", + "browse": "Browse all products" + }, + "leaderboard": { + "title": "Leaderboard", + "full": "Full leaderboard" + }, + "picks": { + "title": "Editor's picks" + }, + "collections": { + "title": "Collections" + }, + "launch": { + "button": "Launch your product" + }, + "featured": { + "label": "Featured story", + "read": "Read the story" + }, + "picksEditorial": { + "label": "Editor's picks" + }, + "guides": { + "title": "Buying guides", + "subtitle": "Deep dives that help you choose", + "viewAll": "All guides" + }, + "stories": { + "title": "Latest stories", + "viewAll": "All stories" + }, + "community": { + "title": "From the community", + "viewAll": "Browse directory" + }, + "ship": { + "title": "Ship faster with AI", + "subtitle": "Pick your workflow — we ranked the tools for it", + "viewAll": "All use cases" + }, + "upvoted": { + "title": "Most upvoted this week", + "viewAll": "View all" + }, + "workflows": { + "title": "Workflows & stacks", + "subtitle": "Batteries-included tool stacks for common dev tasks", + "viewAll": "All workflows" + }, + "browseCategory": { + "title": "Browse by category" + }, + "trendingNow": { + "title": "Trending now" + }, + "seeRankings": "See full rankings", + "browse": "Browse tools", + "noLaunches": "No launches yet — be the first to submit.", + "searchPlaceholder": "Search AI tools...", + "reviewsCount": "{count} reviews", + "mastheadLabel": "INDEPENDENT AI COVERAGE", + "minimalTagline": "AI TOOL SEARCH", + "minimalPlaceholder": "I need to create marketing videos...", + "useCasesBlockTitle": "Use cases", + "goodForBlockTitle": "Good for", + "searchButton": "Search", + "trendingTitle": "Trending this week", + "trendingSubtitle": "Ranked by votes, reviews and engagement over the last 7 days", + "allRankings": "All rankings", + "categoriesTitle": "Browse by category", + "categoriesViewAll": "All tools", + "newTitle": "New AI tools", + "editorsTitle": "Editor's Choice", + "useCasesTitle": "Tools by use case", + "useCasesSubtitle": "What do you want to get done?", + "useCasesViewAll": "All use cases", + "bestListsTitle": "Best AI tool lists", + "bestListsSubtitle": "Curated rankings by our editors", + "bestListsViewAll": "All lists", + "reviewsTitle": "Latest community reviews", + "ctaTitle": "Built an AI tool?", + "ctaBody": "Submit it to {brand} and get discovered by thousands of users looking for tools like yours.", + "ctaButton": "Submit your tool", + "popularLabel": "Popular:", + "feedTitle": "Today's feed", + "feedBrowse": "Browse all products", + "leaderboardTitle": "Leaderboard", + "leaderboardFull": "Full leaderboard", + "picksTitle": "Editor's picks", + "collectionsTitle": "Collections", + "launchButton": "Launch your product", + "featuredLabel": "Featured story", + "featuredRead": "Read the story", + "picksEditorialLabel": "EDITOR'S PICKS", + "guidesTitle": "Buying guides", + "guidesSubtitle": "Deep dives that help you choose", + "guidesViewAll": "All guides", + "storiesTitle": "Latest stories", + "storiesViewAll": "All stories", + "communityTitle": "From the community", + "communityViewAll": "Browse directory", + "shipTitle": "Ship faster with AI", + "shipSubtitle": "Pick your workflow — we ranked the tools for it", + "upvotedTitle": "Most upvoted this week", + "upvotedViewAll": "View all", + "workflowsTitle": "Workflows & stacks", + "workflowsSubtitle": "Batteries-included tool stacks for common dev tasks", + "workflowsViewAll": "All workflows", + "browseCategoryTitle": "Browse by category", + "trendingNowTitle": "Trending now", + "browseButton": "Browse tools", + "toolsCompared": "{count} tools compared", + "popularSearches": [ + "writing", + "video", + "coding", + "image" + ] + }, + "best": { + "indexTitle": "Best AI Tools — Curated Lists", + "indexSubtitle": "Hand-picked rankings, updated with community signal. Every list is labeled and never sold.", + "empty": "No collections published yet.", + "curated": "Curated list", + "faq": "Frequently asked questions", + "more": "More best lists", + "toolsCompared": "{count} tools" + }, + "aiToolsFor": { + "indexTitle": "AI tools for what you do", + "indexSubtitle": "Skip the categories. Start from your task or your role — every page ranks tools by real community votes and reviews.", + "byTask": "By task", + "byAudience": "By audience", + "noData": "No use cases yet.", + "noAud": "No audiences yet.", + "noTools": "No tools tagged yet." + }, + "submitPage": { + "title": "Submit your AI tool", + "subtitle": "Get a free listing with community votes, user reviews and analytics. Submissions are reviewed by our editors, usually within 48 hours." + }, + "faq": { + "title": "Frequently asked questions" + }, + "compare": { + "intro": "A side-by-side comparison based on community votes, ratings and reviews — not sponsored placement.", + "leaning": "Right now the community leans toward {name}.", + "label": "Compare", + "noReviews": "—", + "latest": "Latest review" + }, + "alternatives": { + "noAlt": "No alternatives found yet.", + "thisTool": "{name} (this tool)", + "table": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + }, + "zhTable": { + "tool": "Tool", + "rating": "Rating", + "votes": "Votes", + "pricing": "Pricing" + } + }, + "notFound": { + "code": "404", + "title": "Page not found", + "body": "The page you are looking for doesn't exist or may have moved.", + "home": "Back to home", + "tools": "Browse tools" + }, + "search": { + "placeholder": "Search 1,000+ AI tools...", + "button": "Search" + }, + "siteFooter": { + "groups": [ + { + "title": "Read", + "links": [ + { + "label": "Latest Stories", + "href": "/blog" + }, + { + "label": "Buying Guides", + "href": "/best" + }, + { + "label": "Use Case Guides", + "href": "/ai-tools-for" + } + ] + }, + { + "title": "Directory", + "links": [ + { + "label": "All Tools", + "href": "/tools" + }, + { + "label": "Community Rankings", + "href": "/rankings" + }, + { + "label": "Submit a Tool", + "href": "/submit" + } + ] + }, + { + "title": "Company", + "links": [ + { + "label": "Contact", + "href": "/contact" + }, + { + "label": "Terms", + "href": "/terms" + }, + { + "label": "Privacy", + "href": "/privacy" + } + ] + } + ] + }, + "siteHeader": { + "searchPlaceholder": "Search the directory..." } } diff --git a/sites/the-ai-ledger/messages/zh.json b/sites/the-ai-ledger/messages/zh.json index 4a3c770..1dbcfe8 100644 --- a/sites/the-ai-ledger/messages/zh.json +++ b/sites/the-ai-ledger/messages/zh.json @@ -53,12 +53,29 @@ "linkedin": "领英", "github": "GitHub" } + }, + "site": { + "items": [ + "文章", + "指南", + "最佳推荐", + "目录", + "排行榜", + "提交" + ], + "hrefs": [ + "/blog", + "/ai-tools-for", + "/best", + "/tools", + "/rankings", + "/submit" + ] } }, "hero": { - "badge": "发现最好的 AI 工具", - "title": "The AI Ledger — AI 工具评测与排名", - "description": "独立 AI 媒体:深度指南、横向对比,以及由社区排名的 AI 工具目录。", + "title": "AI 工具,评测与排名", + "description": "指南、对比,以及由社区驱动的最佳 AI 工具目录。", "cta": { "primary": "探索工具", "secondary": "阅读博客" @@ -657,7 +674,9 @@ "latest": "最新", "trending": "最热" }, - "clearFilters": "清除搜索与筛选" + "clearFilters": "清除搜索与筛选", + "useCasesTitle": "使用场景", + "goodForTitle": "适合人群" }, "seo": { "home": { @@ -804,5 +823,280 @@ "new": "最新收录", "editorsChoice": "编辑精选", "empty": "该榜单暂无工具。" + }, + "siteHome": { + "trending": { + "title": "本周趋势", + "subtitle": "按最近 7 天投票、评论与互动排名" + }, + "categories": { + "title": "按分类浏览", + "viewAll": "全部工具" + }, + "new": { + "title": "最新收录" + }, + "editors": { + "title": "编辑精选" + }, + "useCases": { + "title": "按用例找工具", + "subtitle": "你想完成什么?", + "viewAll": "全部用例" + }, + "bestLists": { + "title": "最佳 AI 工具清单", + "subtitle": "编辑精选排名", + "viewAll": "全部清单" + }, + "reviews": { + "title": "最新社区评论" + }, + "cta": { + "title": "做了 AI 工具?", + "body": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "button": "提交你的工具" + }, + "popular": { + "label": "热门:" + }, + "toolsCount": "{count} 个工具", + "feed": { + "title": "今日发布流", + "browse": "浏览全部产品" + }, + "leaderboard": { + "title": "排行榜", + "full": "完整榜单" + }, + "picks": { + "title": "编辑推荐" + }, + "collections": { + "title": "合集" + }, + "launch": { + "button": "发布你的产品" + }, + "featured": { + "label": "头条文章", + "read": "阅读全文" + }, + "picksEditorial": { + "label": "编辑推荐" + }, + "guides": { + "title": "选购指南", + "subtitle": "帮你做决定的深度对比", + "viewAll": "全部指南" + }, + "stories": { + "title": "最新文章", + "viewAll": "全部文章" + }, + "community": { + "title": "来自社区", + "viewAll": "浏览目录" + }, + "ship": { + "title": "用 AI 加速交付", + "subtitle": "选好工作流,我们为它排好了工具", + "viewAll": "全部用例" + }, + "upvoted": { + "title": "本周最多投票", + "viewAll": "查看全部" + }, + "workflows": { + "title": "工作流与技术栈", + "subtitle": "常见开发任务的完整工具组合", + "viewAll": "全部工作流" + }, + "browseCategory": { + "title": "按分类浏览" + }, + "trendingNow": { + "title": "当前趋势" + }, + "seeRankings": "查看完整排行", + "browse": "浏览工具", + "noLaunches": "还没有发布——来做第一个。", + "searchPlaceholder": "搜索 AI 工具...", + "reviewsCount": "{count} 条评论", + "mastheadLabel": "独立 AI 报道", + "minimalTagline": "AI 工具搜索", + "minimalPlaceholder": "我需要制作营销视频……", + "useCasesBlockTitle": "使用场景", + "goodForBlockTitle": "适合人群", + "searchButton": "搜索", + "trendingTitle": "本周趋势", + "trendingSubtitle": "按最近 7 天投票、评论与互动排名", + "allRankings": "全部榜单", + "categoriesTitle": "按分类浏览", + "categoriesViewAll": "全部工具", + "newTitle": "最新收录", + "editorsTitle": "编辑精选", + "useCasesTitle": "按用例找工具", + "useCasesSubtitle": "你想完成什么?", + "useCasesViewAll": "全部用例", + "bestListsTitle": "最佳 AI 工具清单", + "bestListsSubtitle": "编辑精选排名", + "bestListsViewAll": "全部清单", + "reviewsTitle": "最新社区评论", + "ctaTitle": "做了 AI 工具?", + "ctaBody": "提交到 {brand},让成千上万寻找工具的用户发现你。", + "ctaButton": "提交你的工具", + "popularLabel": "热门:", + "feedTitle": "今日发布流", + "feedBrowse": "浏览全部产品", + "leaderboardTitle": "排行榜", + "leaderboardFull": "完整榜单", + "picksTitle": "编辑推荐", + "collectionsTitle": "合集", + "launchButton": "发布你的产品", + "featuredLabel": "头条文章", + "featuredRead": "阅读全文", + "picksEditorialLabel": "编辑推荐", + "guidesTitle": "选购指南", + "guidesSubtitle": "帮你做决定的深度对比", + "guidesViewAll": "全部指南", + "storiesTitle": "最新文章", + "storiesViewAll": "全部文章", + "communityTitle": "来自社区", + "communityViewAll": "浏览目录", + "shipTitle": "用 AI 加速交付", + "shipSubtitle": "选好工作流,我们为它排好了工具", + "upvotedTitle": "本周最多投票", + "upvotedViewAll": "查看全部", + "workflowsTitle": "工作流与技术栈", + "workflowsSubtitle": "常见开发任务的完整工具组合", + "workflowsViewAll": "全部工作流", + "browseCategoryTitle": "按分类浏览", + "trendingNowTitle": "当前趋势", + "browseButton": "浏览工具", + "toolsCompared": "{count} 个工具", + "popularSearches": [ + "写作", + "视频", + "编程", + "图像" + ] + }, + "best": { + "indexTitle": "最佳 AI 工具——精选清单", + "indexSubtitle": "人工精选排名,持续吸收社区信号。每个清单都明确标注,永不售卖。", + "empty": "暂无合集。", + "curated": "编辑精选", + "faq": "常见问题", + "more": "更多最佳清单", + "toolsCompared": "{count} 个工具" + }, + "aiToolsFor": { + "indexTitle": "按任务找 AI 工具", + "indexSubtitle": "别再翻分类。从你的任务或角色出发——每页都按真实社区投票与评论排名。", + "byTask": "按任务", + "byAudience": "按人群", + "noData": "暂无用例。", + "noAud": "暂无人群。", + "noTools": "暂无关联工具。" + }, + "submitPage": { + "title": "提交你的 AI 工具", + "subtitle": "免费收录,获得社区投票、用户评论与数据分析。编辑通常在 48 小时内完成审核。" + }, + "faq": { + "title": "常见问题" + }, + "compare": { + "intro": "基于社区投票、评分与评论的并排对比——非赞助排名。", + "leaning": "当前社区更倾向 {name}。", + "label": "对比", + "noReviews": "—", + "latest": "最新评论" + }, + "alternatives": { + "noAlt": "暂无替代品。", + "thisTool": "{name}(本工具)", + "table": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + }, + "zhTable": { + "tool": "工具", + "rating": "评分", + "votes": "票数", + "pricing": "定价" + } + }, + "notFound": { + "code": "404", + "title": "页面不存在", + "body": "你访问的页面不存在或已被移动。", + "home": "返回首页", + "tools": "浏览工具" + }, + "search": { + "placeholder": "搜索 1000+ AI 工具...", + "button": "搜索" + }, + "siteFooter": { + "groups": [ + { + "title": "阅读", + "links": [ + { + "label": "Latest Stories", + "href": "/blog" + }, + { + "label": "Buying Guides", + "href": "/best" + }, + { + "label": "Use Case Guides", + "href": "/ai-tools-for" + } + ] + }, + { + "title": "目录", + "links": [ + { + "label": "All Tools", + "href": "/tools" + }, + { + "label": "Community Rankings", + "href": "/rankings" + }, + { + "label": "Submit a Tool", + "href": "/submit" + } + ] + }, + { + "title": "公司", + "links": [ + { + "label": "Contact", + "href": "/contact" + }, + { + "label": "Terms", + "href": "/terms" + }, + { + "label": "Privacy", + "href": "/privacy" + } + ] + } + ] + }, + "siteHeader": { + "searchPlaceholder": "搜索目录..." } } diff --git a/sites/the-ai-ledger/src/app/[locale]/not-found.tsx b/sites/the-ai-ledger/src/app/[locale]/not-found.tsx new file mode 100644 index 0000000..d19cc76 --- /dev/null +++ b/sites/the-ai-ledger/src/app/[locale]/not-found.tsx @@ -0,0 +1,2 @@ +// 自动生成:[locale]/not-found.tsx 的薄路由 +export { default } from "@aidir/core/pages/[locale]/not-found"; diff --git a/sites/the-ai-ledger/src/i18n/request.ts b/sites/the-ai-ledger/src/i18n/request.ts index bffb5c2..774aab9 100644 --- a/sites/the-ai-ledger/src/i18n/request.ts +++ b/sites/the-ai-ledger/src/i18n/request.ts @@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config"; const brandMessages = { en: { seo: { home: {"title":"The AI Ledger — AI Tools, Reviewed and Ranked","description":"Independent journalism on AI: buying guides, comparisons and a community-ranked directory of the best AI tools.","ogImage":"/og-image.png"} }, - hero: { title: "The AI Ledger — AI Tools, Reviewed and Ranked", description: "Independent journalism on AI: buying guides, comparisons and a community-ranked directory of the best AI tools." }, + hero: { title: "AI tools, reviewed and ranked", description: "Guides, comparisons and a community-powered directory of the best AI tools." }, common: { brand: { name: "The AI Ledger", tagline: "Independent journalism on AI tools, with a community-ranked directory." } }, + navigation: { + main: { tools: "Stories", blog: "Stories" }, + site: { items: ["Stories","Guides","Best Picks","Directory","Rankings","Submit"], hrefs: ["/blog","/ai-tools-for","/best","/tools","/rankings","/submit"] }, + }, + siteFooter: { groups: [{"title":"Read","links":[{"label":"Latest Stories","href":"/blog"},{"label":"Buying Guides","href":"/best"},{"label":"Use Case Guides","href":"/ai-tools-for"}]},{"title":"Directory","links":[{"label":"All Tools","href":"/tools"},{"label":"Community Rankings","href":"/rankings"},{"label":"Submit a Tool","href":"/submit"}]},{"title":"Company","links":[{"label":"Contact","href":"/contact"},{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"}]}] }, + siteHeader: { searchPlaceholder: "Search the directory..." }, }, zh: { seo: { home: {"title":"The AI Ledger — AI 工具评测与排名","description":"独立 AI 媒体:深度指南、横向对比,以及由社区排名的 AI 工具目录。","ogImage":"/og-image.png"} }, - hero: { title: "The AI Ledger — AI 工具评测与排名", description: "独立 AI 媒体:深度指南、横向对比,以及由社区排名的 AI 工具目录。" }, - common: { brand: { name: "The AI Ledger", tagline: "Independent journalism on AI tools, with a community-ranked directory." } }, + hero: { title: "AI 工具,评测与排名", description: "指南、对比,以及由社区驱动的最佳 AI 工具目录。" }, + common: { brand: { name: "The AI Ledger", tagline: "独立 AI 报道,附社区排名目录。" } }, + navigation: { + main: { tools: "文章", blog: "文章" }, + site: { items: ["文章","指南","最佳推荐","目录","排行榜","提交"], hrefs: ["/blog","/ai-tools-for","/best","/tools","/rankings","/submit"] }, + }, + siteFooter: { groups: [{"title":"阅读","links":[{"label":"Latest Stories","href":"/blog"},{"label":"Buying Guides","href":"/best"},{"label":"Use Case Guides","href":"/ai-tools-for"}]},{"title":"目录","links":[{"label":"All Tools","href":"/tools"},{"label":"Community Rankings","href":"/rankings"},{"label":"Submit a Tool","href":"/submit"}]},{"title":"公司","links":[{"label":"Contact","href":"/contact"},{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"}]}] }, + siteHeader: { searchPlaceholder: "搜索目录..." }, }, } as const; diff --git a/sites/the-ai-ledger/src/site/brand.tsx b/sites/the-ai-ledger/src/site/brand.tsx index 538c2eb..65a6981 100644 --- a/sites/the-ai-ledger/src/site/brand.tsx +++ b/sites/the-ai-ledger/src/site/brand.tsx @@ -2,6 +2,26 @@ import type { SiteConfig } from "@/kit/types"; // The AI Ledger —— 独立站点的全部品牌/导航/页脚配置 export const siteConfig: SiteConfig = { + "brandZh": { + "name": "The AI Ledger", + "tagline": "独立 AI 报道,附社区排名目录。", + "headline": "AI 工具,评测与排名", + "subheadline": "指南、对比,以及由社区驱动的最佳 AI 工具目录。", + "nav": [ + "文章", + "指南", + "最佳推荐", + "目录", + "排行榜", + "提交" + ], + "footer": [ + "阅读", + "目录", + "公司" + ], + "searchPlaceholder": "搜索目录..." + }, "accent": "36 70% 40%", "port": 3003, "brand": { diff --git a/sites/the-ai-ledger/src/site/home.tsx b/sites/the-ai-ledger/src/site/home.tsx index ec9bfee..df52662 100644 --- a/sites/the-ai-ledger/src/site/home.tsx +++ b/sites/the-ai-ledger/src/site/home.tsx @@ -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 }) {

      - Independent AI Coverage + {t("mastheadLabel")}

      - {siteConfig.brand.headline} + {th("title")}

      - {siteConfig.brand.subheadline} + {th("description")}

      @@ -72,7 +75,7 @@ async function SiteHome({ locale }: { locale: string }) {
      - Featured story + {t("featuredLabel")}

      @@ -84,7 +87,7 @@ async function SiteHome({ locale }: { locale: string }) {

      )} - Read the story + {t("featuredRead")} @@ -96,7 +99,7 @@ async function SiteHome({ locale }: { locale: string }) {
      - Editor's picks + {t("picksEditorialLabel")}
      {editorPicks.map((tool, i) => ( @@ -132,10 +135,10 @@ async function SiteHome({ locale }: { locale: string }) { {data.collections.length > 0 && (
      {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}

      - {col.toolCount} tools compared + {col.toolCount} {t("toolsCompared")}

      ))} @@ -162,7 +165,7 @@ async function SiteHome({ locale }: { locale: string }) { {/* Latest articles */} {data.articles.length > 1 && (
      - +
      {data.articles.slice(1).map((article) => ( @@ -184,9 +187,9 @@ async function SiteHome({ locale }: { locale: string }) { {data.latestReviews.length > 0 && (
      {data.latestReviews.slice(0, 4).map((review, i) => (

ToolRatingVotesPricing{tt("tool")}{tt("rating")}{tt("votes")}{tt("pricing")}