fix: 语言切换全面修复 —— 品牌层/主题首页/详情区块/404 全量 i18n(zh 矩阵 13/13)
- 站点品牌双语:每站 brandZh(品牌名/标语/hero/导航/页脚/搜索占位)由生成器写入 站点 messages 的 zh 覆盖;SiteChrome 改为 async getTranslations 按语言渲染 - 五套主题首页接线 siteHome/hero 命名空间(新增 wire-theme-i18n.py 一次性接线脚本, 仅处理组件函数体、hook 自动插入、hero 用 th 命名空间) - 详情页 Use cases/Good for/FAQ/reviewCta、用例与合集索引与详情、提交页、 对比页、Alternatives 表头与 FAQ 全部走 next-intl - 404 双语言:locale 内走 next-intl,根级按 Accept-Language - 修复 zh.json 中 84 处 zhXxx 旁挂键归位 + en.json 残留清理(i18n 694 键一致) - 回归:/zh 下 13 页全中文无英文残留、无横向溢出;五站 /zh lang=zh 全部正确
This commit is contained in:
@@ -649,7 +649,9 @@
|
|||||||
"latest": "Latest",
|
"latest": "Latest",
|
||||||
"trending": "Trending"
|
"trending": "Trending"
|
||||||
},
|
},
|
||||||
"clearFilters": "Clear search & filters"
|
"clearFilters": "Clear search & filters",
|
||||||
|
"useCasesTitle": "Use cases",
|
||||||
|
"goodForTitle": "Good for"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -796,5 +798,222 @@
|
|||||||
"new": "New",
|
"new": "New",
|
||||||
"editorsChoice": "Editor's Choice",
|
"editorsChoice": "Editor's Choice",
|
||||||
"empty": "No tools on this board yet."
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -657,7 +657,9 @@
|
|||||||
"latest": "最新",
|
"latest": "最新",
|
||||||
"trending": "最热"
|
"trending": "最热"
|
||||||
},
|
},
|
||||||
"clearFilters": "清除搜索与筛选"
|
"clearFilters": "清除搜索与筛选",
|
||||||
|
"useCasesTitle": "使用场景",
|
||||||
|
"goodForTitle": "适合人群"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -804,5 +806,222 @@
|
|||||||
"new": "最新收录",
|
"new": "最新收录",
|
||||||
"editorsChoice": "编辑精选",
|
"editorsChoice": "编辑精选",
|
||||||
"empty": "该榜单暂无工具。"
|
"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": "搜索"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,15 @@ const SITES_ROOT = path.join(REPO_ROOT, "sites");
|
|||||||
// ====================================================================
|
// ====================================================================
|
||||||
const SITES = {
|
const SITES = {
|
||||||
"ai-stack": {
|
"ai-stack": {
|
||||||
|
brandZh: {
|
||||||
|
name: "AI Stack",
|
||||||
|
tagline: "由真实用户排名的专业 AI 工具目录。",
|
||||||
|
headline: "找到最好的 AI 工具,由真实用户排名",
|
||||||
|
subheadline: "14 个分类、1000+ AI 工具。对比投票、评论与定价,选出最适合你的。",
|
||||||
|
nav: ["发现", "用例", "最佳清单", "排行榜", "博客", "提交工具"],
|
||||||
|
footer: ["发现", "社区", "法律"],
|
||||||
|
searchPlaceholder: "搜索 1000+ AI 工具...",
|
||||||
|
},
|
||||||
accent: "222 47% 11%", // 近黑(专业)
|
accent: "222 47% 11%", // 近黑(专业)
|
||||||
port: 3001,
|
port: 3001,
|
||||||
theme: "classic",
|
theme: "classic",
|
||||||
@@ -82,6 +91,15 @@ const SITES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
launchai: {
|
launchai: {
|
||||||
|
brandZh: {
|
||||||
|
name: "LaunchAI",
|
||||||
|
tagline: "发现并投票今日的 AI 新品。",
|
||||||
|
headline: "今日 AI 产品发布",
|
||||||
|
subheadline: "每天上新。为最好的产品投票,冲上排行榜。",
|
||||||
|
nav: ["今日", "排行榜", "分类", "合集", "博客", "提交产品"],
|
||||||
|
footer: ["社区", "探索", "关于"],
|
||||||
|
searchPlaceholder: "搜索 AI 产品...",
|
||||||
|
},
|
||||||
accent: "16 85% 55%", // 橙红(产品社区)
|
accent: "16 85% 55%", // 橙红(产品社区)
|
||||||
port: 3002,
|
port: 3002,
|
||||||
theme: "product",
|
theme: "product",
|
||||||
@@ -139,6 +157,15 @@ const SITES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"the-ai-ledger": {
|
"the-ai-ledger": {
|
||||||
|
brandZh: {
|
||||||
|
name: "The AI Ledger",
|
||||||
|
tagline: "独立 AI 报道,附社区排名目录。",
|
||||||
|
headline: "AI 工具,评测与排名",
|
||||||
|
subheadline: "指南、对比,以及由社区驱动的最佳 AI 工具目录。",
|
||||||
|
nav: ["文章", "指南", "最佳推荐", "目录", "排行榜", "提交"],
|
||||||
|
footer: ["阅读", "目录", "公司"],
|
||||||
|
searchPlaceholder: "搜索目录...",
|
||||||
|
},
|
||||||
accent: "36 70% 40%", // 纸墨棕(编辑部)
|
accent: "36 70% 40%", // 纸墨棕(编辑部)
|
||||||
port: 3003,
|
port: 3003,
|
||||||
theme: "editorial",
|
theme: "editorial",
|
||||||
@@ -197,6 +224,15 @@ const SITES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"devai-tools": {
|
"devai-tools": {
|
||||||
|
brandZh: {
|
||||||
|
name: "DevAI.tools",
|
||||||
|
tagline: "面向开发者的 AI 工具——精选、实测、社区排名。",
|
||||||
|
headline: "开发者的 AI 工具",
|
||||||
|
subheadline: "代码助手、运维自动化、测试副驾驶,你上手的一切。",
|
||||||
|
nav: ["工具", "工作流", "用例", "排行榜", "提交"],
|
||||||
|
footer: ["目录", "构建", "法律"],
|
||||||
|
searchPlaceholder: "搜索开发者工具...",
|
||||||
|
},
|
||||||
accent: "150 60% 30%", // 终端绿(开发者)
|
accent: "150 60% 30%", // 终端绿(开发者)
|
||||||
port: 3004,
|
port: 3004,
|
||||||
theme: "niche",
|
theme: "niche",
|
||||||
@@ -253,6 +289,15 @@ const SITES = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
findai: {
|
findai: {
|
||||||
|
brandZh: {
|
||||||
|
name: "findai",
|
||||||
|
tagline: "极简 AI 工具搜索引擎。",
|
||||||
|
headline: "你想完成什么?",
|
||||||
|
subheadline: "",
|
||||||
|
nav: ["搜索", "用例", "排行榜", "提交"],
|
||||||
|
footer: ["搜索", "关于"],
|
||||||
|
searchPlaceholder: "你需要什么?",
|
||||||
|
},
|
||||||
accent: "260 70% 52%", // 紫(极简搜索)
|
accent: "260 70% 52%", // 紫(极简搜索)
|
||||||
port: 3005,
|
port: 3005,
|
||||||
theme: "minimal",
|
theme: "minimal",
|
||||||
@@ -501,13 +546,25 @@ import { locales, defaultLocale, type Locale } from "${corePkg}/i18n.config";
|
|||||||
const brandMessages = {
|
const brandMessages = {
|
||||||
en: {
|
en: {
|
||||||
seo: { home: ${JSON.stringify({ title: site.seo.en.title, description: site.seo.en.description, ogImage: "/og-image.png" })} },
|
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)} } },
|
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: {
|
zh: {
|
||||||
seo: { home: ${JSON.stringify({ title: site.seo.zh.title, description: site.seo.zh.description, ogImage: "/og-image.png" })} },
|
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)} },
|
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.brand.name)}, tagline: ${JSON.stringify(site.brand.tagline)} } },
|
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;
|
} 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.common.brand = { ...(base.common.brand ?? {}), name: site.brand.name, tagline: site.brand.tagline };
|
||||||
base.seo = base.seo ?? {};
|
base.seo = base.seo ?? {};
|
||||||
base.seo.home = { ...(base.seo.home ?? {}), ...site.seo[locale] };
|
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.mkdirSync(path.join(siteRoot, "messages"), { recursive: true });
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
path.join(siteRoot, "messages", `${locale}.json`),
|
path.join(siteRoot, "messages", `${locale}.json`),
|
||||||
|
|||||||
@@ -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),
|
||||||
|
('<span>Popular:</span>', 'popularLabel', True),
|
||||||
|
('>\n Search\n </button>', '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()
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { getToolBySlug } from "@/features/tools/actions";
|
import { getToolBySlug } from "@/features/tools/actions";
|
||||||
import { getAlternativeTools } from "@/features/discovery/actions";
|
import { getAlternativeTools } from "@/features/discovery/actions";
|
||||||
import { pickName } from "@/features/discovery/localize";
|
import { pickName } from "@/features/discovery/localize";
|
||||||
@@ -35,6 +36,9 @@ export async function AlternativesView({
|
|||||||
}) {
|
}) {
|
||||||
const base = await getToolBySlug(baseSlug);
|
const base = await getToolBySlug(baseSlug);
|
||||||
if (!base) notFound();
|
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 alternatives = await getAlternativeTools(base.id, 12);
|
||||||
const name = locale === "zh" && base.nameZh ? base.nameZh : base.nameEn;
|
const name = locale === "zh" && base.nameZh ? base.nameZh : base.nameEn;
|
||||||
@@ -93,7 +97,7 @@ export async function AlternativesView({
|
|||||||
|
|
||||||
{alternatives.length === 0 ? (
|
{alternatives.length === 0 ? (
|
||||||
<p className="rounded-xl border border-dashed border-border p-12 text-center text-sm text-muted-foreground">
|
<p className="rounded-xl border border-dashed border-border p-12 text-center text-sm text-muted-foreground">
|
||||||
No alternatives found yet.
|
{t("noAlt")}
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<FavoritesProvider>
|
<FavoritesProvider>
|
||||||
@@ -109,10 +113,10 @@ export async function AlternativesView({
|
|||||||
<table className="w-full min-w-[560px] text-sm">
|
<table className="w-full min-w-[560px] text-sm">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="border-b border-border bg-secondary/40 text-left text-xs uppercase tracking-wide text-muted-foreground">
|
<tr className="border-b border-border bg-secondary/40 text-left text-xs uppercase tracking-wide text-muted-foreground">
|
||||||
<th className="px-4 py-3">Tool</th>
|
<th className="px-4 py-3">{tt("tool")}</th>
|
||||||
<th className="px-4 py-3">Rating</th>
|
<th className="px-4 py-3">{tt("rating")}</th>
|
||||||
<th className="px-4 py-3">Votes</th>
|
<th className="px-4 py-3">{tt("votes")}</th>
|
||||||
<th className="px-4 py-3">Pricing</th>
|
<th className="px-4 py-3">{tt("pricing")}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -124,7 +128,7 @@ export async function AlternativesView({
|
|||||||
className="font-medium text-foreground hover:text-primary"
|
className="font-medium text-foreground hover:text-primary"
|
||||||
>
|
>
|
||||||
{tool.nameEn === base.nameEn && tool.id === base.id
|
{tool.nameEn === base.nameEn && tool.id === base.id
|
||||||
? `${name} (this tool)`
|
? t("thisTool", { name })
|
||||||
: locale === "zh" && tool.nameZh
|
: locale === "zh" && tool.nameZh
|
||||||
? tool.nameZh
|
? tool.nameZh
|
||||||
: tool.nameEn}
|
: tool.nameEn}
|
||||||
@@ -160,7 +164,7 @@ export async function AlternativesView({
|
|||||||
|
|
||||||
<section className="mt-10 rounded-xl border border-border p-6">
|
<section className="mt-10 rounded-xl border border-border p-6">
|
||||||
<h2 className="text-lg font-semibold text-foreground">
|
<h2 className="text-lg font-semibold text-foreground">
|
||||||
Frequently asked questions
|
{tf("title")}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="mt-4 space-y-4">
|
<div className="mt-4 space-y-4">
|
||||||
{seo.faqs.map((faq, i) => (
|
{seo.faqs.map((faq, i) => (
|
||||||
@@ -206,6 +210,8 @@ export async function ComparisonView({
|
|||||||
|
|
||||||
const nameA = pickName(toolA, locale);
|
const nameA = pickName(toolA, locale);
|
||||||
const nameB = pickName(toolB, 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 url = `${baseUrl()}/${locale}/tools/${slugA}-vs-${slugB}`;
|
||||||
|
|
||||||
const pricingLabels: Record<string, string> = {
|
const pricingLabels: Record<string, string> = {
|
||||||
@@ -260,7 +266,7 @@ export async function ComparisonView({
|
|||||||
winner: "tie",
|
winner: "tie",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Latest review",
|
label: "latest",
|
||||||
a: reviewsA.reviews[0]?.content?.slice(0, 120) ?? "—",
|
a: reviewsA.reviews[0]?.content?.slice(0, 120) ?? "—",
|
||||||
b: reviewsB.reviews[0]?.content?.slice(0, 120) ?? "—",
|
b: reviewsB.reviews[0]?.content?.slice(0, 120) ?? "—",
|
||||||
winner: "tie",
|
winner: "tie",
|
||||||
@@ -301,11 +307,10 @@ export async function ComparisonView({
|
|||||||
{nameA} vs {nameB}: which should you use?
|
{nameA} vs {nameB}: which should you use?
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-3 max-w-2xl text-sm leading-relaxed text-muted-foreground">
|
<p className="mt-3 max-w-2xl text-sm leading-relaxed text-muted-foreground">
|
||||||
A side-by-side comparison based on community votes, ratings and
|
{tc("intro")}
|
||||||
reviews — not sponsored placement.
|
|
||||||
{winnerLabel && (
|
{winnerLabel && (
|
||||||
<>
|
<>
|
||||||
{" "}Right now the community leans toward{" "}
|
{" "}{tc("leaning", { name: winnerLabel })}{" "}
|
||||||
<Link
|
<Link
|
||||||
href={`/${locale}/tools/${slugA === toolA.slug ? slugA : slugB}`}
|
href={`/${locale}/tools/${slugA === toolA.slug ? slugA : slugB}`}
|
||||||
className="font-medium text-primary hover:underline"
|
className="font-medium text-primary hover:underline"
|
||||||
|
|||||||
@@ -1,29 +1,61 @@
|
|||||||
|
import { getTranslations, getLocale } from "next-intl/server";
|
||||||
import { ThemeHeader } from "./theme-header";
|
import { ThemeHeader } from "./theme-header";
|
||||||
import { ThemeFooter } from "./theme-footer";
|
import { ThemeFooter } from "./theme-footer";
|
||||||
import type { SiteConfig } from "./types";
|
import type { SiteConfig } from "./types";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* # 组件 SiteChrome
|
* # 组件 SiteChrome
|
||||||
* 说明:站点外壳(Header + Footer + 主题变量注入)。
|
* 说明:站点外壳(Header + Footer + 主题变量注入)—— 服务端组件,读取站点 i18n 文案。
|
||||||
* 由每个网站的 marketing layout 通过 createMarketingLayout(config) 调用。
|
* 每个网站的导航/页脚/搜索占位在 messages 的 navigation.site / siteFooter / siteHeader,
|
||||||
* 一个 SiteConfig = 一个独立网站;Core 不内置任何站点。
|
* 由生成器按语言写入;品牌名/标语取自 SiteConfig(当前语言优先 brandZh)。
|
||||||
*/
|
*/
|
||||||
export function SiteChrome({
|
export async function SiteChrome({
|
||||||
config,
|
config,
|
||||||
children,
|
children,
|
||||||
}: {
|
}: {
|
||||||
config: SiteConfig;
|
config: SiteConfig;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}) {
|
}) {
|
||||||
|
const t = await getTranslations("navigation");
|
||||||
|
const tf = await getTranslations("siteFooter");
|
||||||
|
const th = await getTranslations("siteHeader");
|
||||||
|
const locale = await getLocale();
|
||||||
|
|
||||||
|
// 当前语言的品牌(brandZh 在 SiteConfig 顶层)
|
||||||
|
const zh = config.brandZh;
|
||||||
|
const brand =
|
||||||
|
locale === "zh" && zh
|
||||||
|
? {
|
||||||
|
name: zh.name ?? config.brand.name,
|
||||||
|
tagline: zh.tagline ?? config.brand.tagline,
|
||||||
|
headline: zh.headline ?? config.brand.headline,
|
||||||
|
subheadline: zh.subheadline ?? config.brand.subheadline,
|
||||||
|
}
|
||||||
|
: config.brand;
|
||||||
|
|
||||||
|
// 导航项:label 按 i18n,href 固定
|
||||||
|
const navLabels = t.raw("site.items") as string[] | undefined;
|
||||||
|
const navHrefs = t.raw("site.hrefs") as string[] | undefined;
|
||||||
|
const navItems =
|
||||||
|
navLabels && navHrefs
|
||||||
|
? navHrefs.map((href, i) => ({ 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 (
|
return (
|
||||||
<div style={config.cssVars as React.CSSProperties}>
|
<div style={config.cssVars as React.CSSProperties}>
|
||||||
<ThemeHeader
|
<ThemeHeader
|
||||||
brand={config.brand}
|
brand={brand}
|
||||||
navItems={config.navItems}
|
navItems={navItems}
|
||||||
searchPlaceholder={config.searchPlaceholder}
|
searchPlaceholder={th.raw("searchPlaceholder") as string}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
<ThemeFooter brand={config.brand} groups={config.footerGroups} />
|
<ThemeFooter brand={brand} groups={footerGroups} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Search, TrendingUp, Sparkles, Clock, Award, LayoutGrid, MessageSquareQuote } from "lucide-react";
|
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 { ToolCard, ToolCardGrid } from "@/components/tool-card";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { SectionHeader } from "../shared/section";
|
import { SectionHeader } from "../shared/section";
|
||||||
@@ -55,6 +56,8 @@ const footerGroups = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function ClassicHome({ locale }: { locale: string }) {
|
async function ClassicHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(8);
|
const data = await getHomeDataSafe(8);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -63,17 +66,17 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
<section className="border-b border-border bg-gradient-to-b from-secondary/40 to-background">
|
<section className="border-b border-border bg-gradient-to-b from-secondary/40 to-background">
|
||||||
<div className="mx-auto max-w-7xl px-4 py-16 text-center sm:px-6 md:py-24">
|
<div className="mx-auto max-w-7xl px-4 py-16 text-center sm:px-6 md:py-24">
|
||||||
<h1 className="mx-auto max-w-3xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
|
<h1 className="mx-auto max-w-3xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
|
||||||
{brand.headline}
|
{th("title")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mx-auto mt-4 max-w-2xl text-sm text-muted-foreground sm:text-base">
|
<p className="mx-auto mt-4 max-w-2xl text-sm text-muted-foreground sm:text-base">
|
||||||
{brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
<form action={`/${locale}/tools`} className="mx-auto mt-8 max-w-xl">
|
<form action={`/${locale}/tools`} className="mx-auto mt-8 max-w-xl">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Search className="absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
<Search className="absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
||||||
<input
|
<input
|
||||||
name="search"
|
name="search"
|
||||||
placeholder="Search 1,000+ AI tools..."
|
placeholder={t("searchPlaceholder")}
|
||||||
className="h-12 w-full rounded-full border border-border bg-background pl-11 pr-28 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/30"
|
className="h-12 w-full rounded-full border border-border bg-background pl-11 pr-28 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/30"
|
||||||
aria-label="Search AI tools"
|
aria-label="Search AI tools"
|
||||||
/>
|
/>
|
||||||
@@ -81,13 +84,13 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
type="submit"
|
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"
|
className="absolute right-1.5 top-1.5 h-9 rounded-full bg-primary px-5 text-xs font-semibold text-primary-foreground transition-opacity hover:opacity-90"
|
||||||
>
|
>
|
||||||
Search
|
{t("searchButton")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground">
|
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground">
|
||||||
<span>Popular:</span>
|
<span>{t("popularLabel")}</span>
|
||||||
{["writing", "video", "coding", "image"].map((q) => (
|
{t.raw("popularSearches").map((q: string) => (
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
key={q}
|
key={q}
|
||||||
href={`/tools?search=${q}`}
|
href={`/tools?search=${q}`}
|
||||||
@@ -105,10 +108,10 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
{data.trending.length > 0 && (
|
{data.trending.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Trending this week"
|
title={t("trendingTitle")}
|
||||||
subtitle="Ranked by votes, reviews and engagement over the last 7 days"
|
subtitle={t("trendingSubtitle")}
|
||||||
viewAllHref="/rankings?board=trending"
|
viewAllHref="/rankings?board=trending"
|
||||||
viewAllLabel="All rankings"
|
viewAllLabel={t("allRankings")}
|
||||||
/>
|
/>
|
||||||
<ToolCardGrid tools={data.trending} locale={locale} ranked />
|
<ToolCardGrid tools={data.trending} locale={locale} ranked />
|
||||||
</section>
|
</section>
|
||||||
@@ -118,9 +121,9 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
{data.categories.length > 0 && (
|
{data.categories.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Browse by category"
|
title={t("categoriesTitle")}
|
||||||
viewAllHref="/tools"
|
viewAllHref="/tools"
|
||||||
viewAllLabel="All tools"
|
viewAllLabel={t("categoriesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
|
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
|
||||||
{data.categories.slice(0, 10).map((category) => (
|
{data.categories.slice(0, 10).map((category) => (
|
||||||
@@ -149,7 +152,7 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
{data.newest.length > 0 && (
|
{data.newest.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="New AI tools"
|
title={t("newTitle")}
|
||||||
viewAllHref="/rankings?board=new"
|
viewAllHref="/rankings?board=new"
|
||||||
/>
|
/>
|
||||||
<ToolCardGrid tools={data.newest.slice(0, 4)} locale={locale} />
|
<ToolCardGrid tools={data.newest.slice(0, 4)} locale={locale} />
|
||||||
@@ -158,7 +161,7 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
{data.editorsChoice.length > 0 && (
|
{data.editorsChoice.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Editor's Choice"
|
title={t("editorsTitle")}
|
||||||
viewAllHref="/rankings?board=editors-choice"
|
viewAllHref="/rankings?board=editors-choice"
|
||||||
/>
|
/>
|
||||||
<ToolCardGrid tools={data.editorsChoice.slice(0, 4)} locale={locale} />
|
<ToolCardGrid tools={data.editorsChoice.slice(0, 4)} locale={locale} />
|
||||||
@@ -170,10 +173,10 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
{data.useCases.length > 0 && (
|
{data.useCases.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Tools by use case"
|
title={t("useCasesTitle")}
|
||||||
subtitle="What do you want to get done?"
|
subtitle={t("useCasesSubtitle")}
|
||||||
viewAllHref="/ai-tools-for"
|
viewAllHref="/ai-tools-for"
|
||||||
viewAllLabel="All use cases"
|
viewAllLabel={t("useCasesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{data.useCases.slice(0, 12).map((uc) => (
|
{data.useCases.slice(0, 12).map((uc) => (
|
||||||
@@ -196,10 +199,10 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
{data.collections.length > 0 && (
|
{data.collections.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Best AI tool lists"
|
title={t("bestListsTitle")}
|
||||||
subtitle="Curated rankings by our editors"
|
subtitle={t("bestListsSubtitle")}
|
||||||
viewAllHref="/best"
|
viewAllHref="/best"
|
||||||
viewAllLabel="All lists"
|
viewAllLabel={t("bestListsViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{data.collections.slice(0, 3).map((col) => (
|
{data.collections.slice(0, 3).map((col) => (
|
||||||
@@ -227,7 +230,7 @@ async function ClassicHome({ locale }: { locale: string }) {
|
|||||||
{/* Latest Reviews */}
|
{/* Latest Reviews */}
|
||||||
{data.latestReviews.length > 0 && (
|
{data.latestReviews.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader title="Latest community reviews" />
|
<SectionHeader title={t("reviewsTitle")} />
|
||||||
<div className="grid gap-3 md:grid-cols-2">
|
<div className="grid gap-3 md:grid-cols-2">
|
||||||
{data.latestReviews.map((review, i) => (
|
{data.latestReviews.map((review, i) => (
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { BookOpen, PenTool, ArrowRight, Star } from "lucide-react";
|
import { BookOpen, PenTool, ArrowRight, Star } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { SectionHeader } from "../shared/section";
|
import { SectionHeader } from "../shared/section";
|
||||||
import { getHomeDataSafe } from "../shared/home-data";
|
import { getHomeDataSafe } from "../shared/home-data";
|
||||||
@@ -50,6 +51,8 @@ const footerGroups = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function EditorialHome({ locale }: { locale: string }) {
|
async function EditorialHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(6);
|
const data = await getHomeDataSafe(6);
|
||||||
const featured = data.articles[0];
|
const featured = data.articles[0];
|
||||||
const editorPicks = data.editorsChoice.slice(0, 4);
|
const editorPicks = data.editorsChoice.slice(0, 4);
|
||||||
@@ -60,13 +63,13 @@ async function EditorialHome({ locale }: { locale: string }) {
|
|||||||
<section className="border-b border-border">
|
<section className="border-b border-border">
|
||||||
<div className="mx-auto max-w-4xl px-4 py-16 text-center sm:px-6 md:py-20">
|
<div className="mx-auto max-w-4xl px-4 py-16 text-center sm:px-6 md:py-20">
|
||||||
<p className="text-xs font-medium uppercase tracking-[0.3em] text-muted-foreground">
|
<p className="text-xs font-medium uppercase tracking-[0.3em] text-muted-foreground">
|
||||||
Independent AI Coverage
|
{t("mastheadLabel")}
|
||||||
</p>
|
</p>
|
||||||
<h1 className="mt-4 text-4xl font-bold tracking-tight text-foreground md:text-5xl">
|
<h1 className="mt-4 text-4xl font-bold tracking-tight text-foreground md:text-5xl">
|
||||||
{brand.headline}
|
{th("title")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mx-auto mt-4 max-w-xl text-base leading-relaxed text-muted-foreground">
|
<p className="mx-auto mt-4 max-w-xl text-base leading-relaxed text-muted-foreground">
|
||||||
{brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -77,7 +80,7 @@ async function EditorialHome({ locale }: { locale: string }) {
|
|||||||
<section>
|
<section>
|
||||||
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
||||||
<BookOpen className="h-3.5 w-3.5" />
|
<BookOpen className="h-3.5 w-3.5" />
|
||||||
Featured story
|
{t("featuredLabel")}
|
||||||
</div>
|
</div>
|
||||||
<LocaleLink href={`/blog/${featured.slug}`} className="group block">
|
<LocaleLink href={`/blog/${featured.slug}`} className="group block">
|
||||||
<h2 className="text-2xl font-bold leading-snug text-foreground group-hover:underline md:text-3xl">
|
<h2 className="text-2xl font-bold leading-snug text-foreground group-hover:underline md:text-3xl">
|
||||||
@@ -89,7 +92,7 @@ async function EditorialHome({ locale }: { locale: string }) {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<span className="mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary">
|
<span className="mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary">
|
||||||
Read the story
|
{t("featuredRead")}
|
||||||
<ArrowRight className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" />
|
<ArrowRight className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" />
|
||||||
</span>
|
</span>
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
@@ -101,7 +104,7 @@ async function EditorialHome({ locale }: { locale: string }) {
|
|||||||
<section>
|
<section>
|
||||||
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
||||||
<PenTool className="h-3.5 w-3.5" />
|
<PenTool className="h-3.5 w-3.5" />
|
||||||
Editor's picks
|
{t("picksEditorialLabel")}
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-border border-y border-border">
|
<div className="divide-y divide-border border-y border-border">
|
||||||
{editorPicks.map((tool, i) => (
|
{editorPicks.map((tool, i) => (
|
||||||
@@ -137,10 +140,10 @@ async function EditorialHome({ locale }: { locale: string }) {
|
|||||||
{data.collections.length > 0 && (
|
{data.collections.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Buying guides"
|
title={t("guidesTitle")}
|
||||||
subtitle="Deep dives that help you choose"
|
subtitle={t("guidesSubtitle")}
|
||||||
viewAllHref="/best"
|
viewAllHref="/best"
|
||||||
viewAllLabel="All guides"
|
viewAllLabel={t("guidesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-6 sm:grid-cols-2">
|
<div className="grid gap-6 sm:grid-cols-2">
|
||||||
{data.collections.slice(0, 4).map((col) => (
|
{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}
|
{locale === "zh" && col.introZh ? col.introZh : col.introEn}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-2 text-xs uppercase tracking-wide text-muted-foreground">
|
<p className="mt-2 text-xs uppercase tracking-wide text-muted-foreground">
|
||||||
{col.toolCount} tools compared
|
{col.toolCount} {t("toolsCompared")}
|
||||||
</p>
|
</p>
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
))}
|
))}
|
||||||
@@ -167,7 +170,7 @@ async function EditorialHome({ locale }: { locale: string }) {
|
|||||||
{/* Latest articles */}
|
{/* Latest articles */}
|
||||||
{data.articles.length > 1 && (
|
{data.articles.length > 1 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader title="Latest stories" viewAllHref="/blog" />
|
<SectionHeader title={t("storiesTitle")} viewAllHref="/blog" />
|
||||||
<div className="grid gap-6 sm:grid-cols-2">
|
<div className="grid gap-6 sm:grid-cols-2">
|
||||||
{data.articles.slice(1).map((article) => (
|
{data.articles.slice(1).map((article) => (
|
||||||
<LocaleLink key={article.slug} href={`/blog/${article.slug}`} className="group">
|
<LocaleLink key={article.slug} href={`/blog/${article.slug}`} className="group">
|
||||||
@@ -189,9 +192,9 @@ async function EditorialHome({ locale }: { locale: string }) {
|
|||||||
{data.latestReviews.length > 0 && (
|
{data.latestReviews.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="From the community"
|
title={t("communityTitle")}
|
||||||
viewAllHref="/tools"
|
viewAllHref="/tools"
|
||||||
viewAllLabel="Browse directory"
|
viewAllLabel={t("communityViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-6 sm:grid-cols-2">
|
<div className="grid gap-6 sm:grid-cols-2">
|
||||||
{data.latestReviews.slice(0, 4).map((review, i) => (
|
{data.latestReviews.slice(0, 4).map((review, i) => (
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Search } from "lucide-react";
|
import { Search } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { ToolCardGrid } from "@/components/tool-card";
|
import { ToolCardGrid } from "@/components/tool-card";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { getHomeDataSafe } from "../shared/home-data";
|
import { getHomeDataSafe } from "../shared/home-data";
|
||||||
@@ -48,6 +49,8 @@ const popularSearches = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function MinimalHome({ locale }: { locale: string }) {
|
async function MinimalHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(6);
|
const data = await getHomeDataSafe(6);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -67,7 +70,7 @@ async function MinimalHome({ locale }: { locale: string }) {
|
|||||||
<input
|
<input
|
||||||
name="search"
|
name="search"
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder="I need to create marketing videos..."
|
placeholder={t("minimalPlaceholder")}
|
||||||
className="h-14 w-full rounded-full border border-border bg-background pl-14 pr-6 text-base text-foreground shadow-lg shadow-black/[0.03] placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-4 focus:ring-primary/10"
|
className="h-14 w-full rounded-full border border-border bg-background pl-14 pr-6 text-base text-foreground shadow-lg shadow-black/[0.03] placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-4 focus:ring-primary/10"
|
||||||
aria-label="Search AI tools"
|
aria-label="Search AI tools"
|
||||||
/>
|
/>
|
||||||
@@ -99,7 +102,7 @@ async function MinimalHome({ locale }: { locale: string }) {
|
|||||||
href="/rankings"
|
href="/rankings"
|
||||||
className="text-xs font-medium text-muted-foreground hover:text-primary"
|
className="text-xs font-medium text-muted-foreground hover:text-primary"
|
||||||
>
|
>
|
||||||
See full rankings
|
{t("seeRankings")}
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Code2, Terminal, Workflow, Layers } from "lucide-react";
|
import { Code2, Terminal, Workflow, Layers } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { ToolCard } from "@/components/tool-card";
|
import { ToolCard } from "@/components/tool-card";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { SectionHeader } from "../shared/section";
|
import { SectionHeader } from "../shared/section";
|
||||||
@@ -49,6 +50,8 @@ const footerGroups = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function NicheHome({ locale }: { locale: string }) {
|
async function NicheHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(6);
|
const data = await getHomeDataSafe(6);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -70,10 +73,10 @@ async function NicheHome({ locale }: { locale: string }) {
|
|||||||
</p>
|
</p>
|
||||||
<p className="flex items-center gap-2 text-foreground">
|
<p className="flex items-center gap-2 text-foreground">
|
||||||
<Terminal className="h-3.5 w-3.5 text-emerald-600 dark:text-emerald-400" />
|
<Terminal className="h-3.5 w-3.5 text-emerald-600 dark:text-emerald-400" />
|
||||||
{brand.headline}
|
{th("title")}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs leading-relaxed text-muted-foreground">
|
<p className="text-xs leading-relaxed text-muted-foreground">
|
||||||
{brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
<p className="pt-2">
|
<p className="pt-2">
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
@@ -93,10 +96,10 @@ async function NicheHome({ locale }: { locale: string }) {
|
|||||||
{data.useCases.length > 0 && (
|
{data.useCases.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Ship faster with AI"
|
title={t("shipTitle")}
|
||||||
subtitle="Pick your workflow — we ranked the tools for it"
|
subtitle={t("shipSubtitle")}
|
||||||
viewAllHref="/ai-tools-for"
|
viewAllHref="/ai-tools-for"
|
||||||
viewAllLabel="All use cases"
|
viewAllLabel={t("useCasesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{data.useCases.slice(0, 6).map((uc) => (
|
{data.useCases.slice(0, 6).map((uc) => (
|
||||||
@@ -124,7 +127,7 @@ async function NicheHome({ locale }: { locale: string }) {
|
|||||||
{data.trending.length > 0 && (
|
{data.trending.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Most upvoted this week"
|
title={t("upvotedTitle")}
|
||||||
viewAllHref="/rankings?board=trending"
|
viewAllHref="/rankings?board=trending"
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 md:grid-cols-2">
|
<div className="grid gap-3 md:grid-cols-2">
|
||||||
@@ -144,10 +147,10 @@ async function NicheHome({ locale }: { locale: string }) {
|
|||||||
{data.collections.length > 0 && (
|
{data.collections.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Workflows & stacks"
|
title={t("workflowsTitle")}
|
||||||
subtitle="Batteries-included tool stacks for common dev tasks"
|
subtitle={t("workflowsSubtitle")}
|
||||||
viewAllHref="/best"
|
viewAllHref="/best"
|
||||||
viewAllLabel="All workflows"
|
viewAllLabel={t("workflowsViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{data.collections.slice(0, 3).map((col) => (
|
{data.collections.slice(0, 3).map((col) => (
|
||||||
@@ -172,7 +175,7 @@ async function NicheHome({ locale }: { locale: string }) {
|
|||||||
{/* Categories */}
|
{/* Categories */}
|
||||||
{data.categories.length > 0 && (
|
{data.categories.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader title="Browse by category" viewAllHref="/tools" />
|
<SectionHeader title={t("categoriesTitle")} viewAllHref="/tools" />
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{data.categories.slice(0, 14).map((cat) => (
|
{data.categories.slice(0, 14).map((cat) => (
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Flame, Trophy, Rocket, ChevronRight, MessageSquare } from "lucide-react";
|
import { Flame, Trophy, Rocket, ChevronRight, MessageSquare } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { VoteButton } from "@/features/voting/components/vote-button";
|
import { VoteButton } from "@/features/voting/components/vote-button";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { ToolLogo } from "@/components/tool-logo";
|
import { ToolLogo } from "@/components/tool-logo";
|
||||||
@@ -107,6 +108,8 @@ function LaunchRow({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function ProductHome({ locale }: { locale: string }) {
|
async function ProductHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(10);
|
const data = await getHomeDataSafe(10);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -115,17 +118,17 @@ async function ProductHome({ locale }: { locale: string }) {
|
|||||||
<section className="border-b border-border bg-gradient-to-b from-primary/5 to-background">
|
<section className="border-b border-border bg-gradient-to-b from-primary/5 to-background">
|
||||||
<div className="mx-auto max-w-5xl px-4 py-12 text-center sm:px-6 md:py-16">
|
<div className="mx-auto max-w-5xl px-4 py-12 text-center sm:px-6 md:py-16">
|
||||||
<h1 className="text-2xl font-extrabold tracking-tight text-foreground sm:text-4xl">
|
<h1 className="text-2xl font-extrabold tracking-tight text-foreground sm:text-4xl">
|
||||||
{brand.headline}
|
{th("title")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-3 text-sm text-muted-foreground sm:text-base">
|
<p className="mt-3 text-sm text-muted-foreground sm:text-base">
|
||||||
{brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
href="/submit"
|
href="/submit"
|
||||||
className="mt-6 inline-flex items-center gap-1.5 rounded-full bg-primary px-6 py-2.5 text-sm font-semibold text-primary-foreground shadow transition-all hover:opacity-90"
|
className="mt-6 inline-flex items-center gap-1.5 rounded-full bg-primary px-6 py-2.5 text-sm font-semibold text-primary-foreground shadow transition-all hover:opacity-90"
|
||||||
>
|
>
|
||||||
<Rocket className="h-4 w-4" />
|
<Rocket className="h-4 w-4" />
|
||||||
Launch your product
|
{t("launchButton")}
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -144,14 +147,14 @@ async function ProductHome({ locale }: { locale: string }) {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<p className="px-6 py-12 text-center text-sm text-muted-foreground">
|
<p className="px-6 py-12 text-center text-sm text-muted-foreground">
|
||||||
No launches yet — be the first to submit.
|
{t("noLaunches")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
href="/tools"
|
href="/tools"
|
||||||
className="flex items-center justify-center gap-1 border-t border-border py-3 text-xs font-medium text-muted-foreground hover:text-primary"
|
className="flex items-center justify-center gap-1 border-t border-border py-3 text-xs font-medium text-muted-foreground hover:text-primary"
|
||||||
>
|
>
|
||||||
Browse all products
|
{t("feedBrowse")}
|
||||||
<ChevronRight className="h-3 w-3" />
|
<ChevronRight className="h-3 w-3" />
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
@@ -159,7 +162,7 @@ async function ProductHome({ locale }: { locale: string }) {
|
|||||||
{/* New */}
|
{/* New */}
|
||||||
{data.newest.length > 0 && (
|
{data.newest.length > 0 && (
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<SectionHeader title="Fresh launches" viewAllHref="/rankings?board=new" />
|
<SectionHeader title={t("newTitle")} viewAllHref="/rankings?board=new" />
|
||||||
<div className="overflow-hidden rounded-2xl border border-border bg-background">
|
<div className="overflow-hidden rounded-2xl border border-border bg-background">
|
||||||
{data.newest.slice(0, 5).map((tool) => (
|
{data.newest.slice(0, 5).map((tool) => (
|
||||||
<LaunchRow key={tool.id} tool={tool} locale={locale} />
|
<LaunchRow key={tool.id} tool={tool} locale={locale} />
|
||||||
@@ -204,14 +207,14 @@ async function ProductHome({ locale }: { locale: string }) {
|
|||||||
href="/rankings"
|
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"
|
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")}
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{data.editorsChoice.length > 0 && (
|
{data.editorsChoice.length > 0 && (
|
||||||
<div className="rounded-2xl border border-border bg-background p-5">
|
<div className="rounded-2xl border border-border bg-background p-5">
|
||||||
<h3 className="text-sm font-bold text-foreground">Editor's picks</h3>
|
<h3 className="text-sm font-bold text-foreground">{t("picksEditorialLabel")}</h3>
|
||||||
<ol className="mt-4 space-y-3">
|
<ol className="mt-4 space-y-3">
|
||||||
{data.editorsChoice.slice(0, 4).map((tool) => (
|
{data.editorsChoice.slice(0, 4).map((tool) => (
|
||||||
<li key={tool.id}>
|
<li key={tool.id}>
|
||||||
|
|||||||
@@ -32,6 +32,16 @@ export interface SiteConfig {
|
|||||||
seo?: Record<string, { title: string; description: string }>;
|
seo?: Record<string, { title: string; description: string }>;
|
||||||
/** 品牌强调色 HSL 三元组(登录页分栏模板) */
|
/** 品牌强调色 HSL 三元组(登录页分栏模板) */
|
||||||
accent?: string;
|
accent?: string;
|
||||||
|
/** 中文品牌文案(导航/页脚/hero/搜索占位) */
|
||||||
|
brandZh?: {
|
||||||
|
name?: string;
|
||||||
|
tagline?: string;
|
||||||
|
headline?: string;
|
||||||
|
subheadline?: string;
|
||||||
|
nav?: string[];
|
||||||
|
footer?: string[];
|
||||||
|
searchPlaceholder?: string;
|
||||||
|
};
|
||||||
/** 品牌侧栏标语(登录页) */
|
/** 品牌侧栏标语(登录页) */
|
||||||
brandTagline?: string;
|
brandTagline?: string;
|
||||||
/** 主题级 CSS 变量覆盖(HSL 三元组,可选) */
|
/** 主题级 CSS 变量覆盖(HSL 三元组,可选) */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { setRequestLocale } from "next-intl/server";
|
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||||
import { generatePageMetadata } from "@/lib/metadata";
|
import { generatePageMetadata } from "@/lib/metadata";
|
||||||
import {
|
import {
|
||||||
getUseCaseBySlug,
|
getUseCaseBySlug,
|
||||||
@@ -82,6 +82,7 @@ export default async function AiToolsForEntityPage({
|
|||||||
}) {
|
}) {
|
||||||
const { slug, locale } = await params;
|
const { slug, locale } = await params;
|
||||||
setRequestLocale(locale);
|
setRequestLocale(locale);
|
||||||
|
const tf = await getTranslations({ locale, namespace: "faq" });
|
||||||
|
|
||||||
const resolved = await resolveEntity(slug);
|
const resolved = await resolveEntity(slug);
|
||||||
if (!resolved) notFound();
|
if (!resolved) notFound();
|
||||||
@@ -168,7 +169,7 @@ export default async function AiToolsForEntityPage({
|
|||||||
|
|
||||||
<section className="mt-10 rounded-xl border border-border p-6">
|
<section className="mt-10 rounded-xl border border-border p-6">
|
||||||
<h2 className="text-lg font-semibold text-foreground">
|
<h2 className="text-lg font-semibold text-foreground">
|
||||||
Frequently asked questions
|
{tf("title")}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="mt-4 space-y-4">
|
<div className="mt-4 space-y-4">
|
||||||
{seo.faqs.map((faq, i) => (
|
{seo.faqs.map((faq, i) => (
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { setRequestLocale } from "next-intl/server";
|
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||||
import { generatePageMetadata } from "@/lib/metadata";
|
import { generatePageMetadata } from "@/lib/metadata";
|
||||||
import { getUseCases, getAudiences } from "@/features/discovery/actions";
|
import { getUseCases, getAudiences } from "@/features/discovery/actions";
|
||||||
import { pickName } from "@/features/discovery/localize";
|
import { pickName } from "@/features/discovery/localize";
|
||||||
import { CollectionPageJsonLd } from "@/components/json-ld";
|
import { CollectionPageJsonLd } from "@/components/json-ld";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { Target, Users } from "lucide-react";
|
import { Target, Users } from "lucide-react";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
|
||||||
export const revalidate = 3600;
|
export const revalidate = 3600;
|
||||||
|
|
||||||
@@ -31,6 +32,7 @@ export default async function AiToolsForPage({
|
|||||||
}) {
|
}) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
setRequestLocale(locale);
|
setRequestLocale(locale);
|
||||||
|
const t = await getTranslations("aiToolsFor");
|
||||||
|
|
||||||
const [useCases, audiences] = await Promise.all([
|
const [useCases, audiences] = await Promise.all([
|
||||||
getUseCases().catch(() => []),
|
getUseCases().catch(() => []),
|
||||||
@@ -49,11 +51,10 @@ export default async function AiToolsForPage({
|
|||||||
|
|
||||||
<div className="mb-10">
|
<div className="mb-10">
|
||||||
<h1 className="text-2xl font-bold tracking-tight text-foreground sm:text-3xl">
|
<h1 className="text-2xl font-bold tracking-tight text-foreground sm:text-3xl">
|
||||||
AI tools for what you do
|
{t("indexTitle")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-2 max-w-2xl text-sm text-muted-foreground">
|
<p className="mt-2 max-w-2xl text-sm text-muted-foreground">
|
||||||
Skip the categories. Start from your task or your role — every page
|
{t("indexSubtitle")}
|
||||||
ranks tools by real community votes and reviews.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -61,10 +62,10 @@ export default async function AiToolsForPage({
|
|||||||
<section className="mb-12">
|
<section className="mb-12">
|
||||||
<h2 className="mb-4 flex items-center gap-2 text-lg font-semibold text-foreground">
|
<h2 className="mb-4 flex items-center gap-2 text-lg font-semibold text-foreground">
|
||||||
<Target className="h-4 w-4 text-primary" />
|
<Target className="h-4 w-4 text-primary" />
|
||||||
By task
|
{t("byTask")}
|
||||||
</h2>
|
</h2>
|
||||||
{useCases.length === 0 ? (
|
{useCases.length === 0 ? (
|
||||||
<p className="text-sm text-muted-foreground">No use cases yet.</p>
|
<p className="text-sm text-muted-foreground">{t("noData")}</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{useCases.map((uc) => (
|
{useCases.map((uc) => (
|
||||||
@@ -96,10 +97,10 @@ export default async function AiToolsForPage({
|
|||||||
<section>
|
<section>
|
||||||
<h2 className="mb-4 flex items-center gap-2 text-lg font-semibold text-foreground">
|
<h2 className="mb-4 flex items-center gap-2 text-lg font-semibold text-foreground">
|
||||||
<Users className="h-4 w-4 text-primary" />
|
<Users className="h-4 w-4 text-primary" />
|
||||||
By audience
|
{t("byAudience")}
|
||||||
</h2>
|
</h2>
|
||||||
{audiences.length === 0 ? (
|
{audiences.length === 0 ? (
|
||||||
<p className="text-sm text-muted-foreground">No audiences yet.</p>
|
<p className="text-sm text-muted-foreground">{t("noAud")}</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{audiences.map((aud) => (
|
{audiences.map((aud) => (
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { notFound } from "next/navigation";
|
import { notFound } from "next/navigation";
|
||||||
import { setRequestLocale } from "next-intl/server";
|
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||||
import { generatePageMetadata } from "@/lib/metadata";
|
import { generatePageMetadata } from "@/lib/metadata";
|
||||||
import {
|
import {
|
||||||
getCollectionBySlug,
|
getCollectionBySlug,
|
||||||
@@ -63,6 +63,8 @@ export default async function BestCollectionPage({
|
|||||||
}) {
|
}) {
|
||||||
const { slug, locale } = await params;
|
const { slug, locale } = await params;
|
||||||
setRequestLocale(locale);
|
setRequestLocale(locale);
|
||||||
|
const tf = await getTranslations({ locale, namespace: "faq" });
|
||||||
|
const tb = await getTranslations({ locale, namespace: "best" });
|
||||||
|
|
||||||
const collection = await getCollectionBySlug(slug);
|
const collection = await getCollectionBySlug(slug);
|
||||||
if (!collection) notFound();
|
if (!collection) notFound();
|
||||||
@@ -147,7 +149,7 @@ export default async function BestCollectionPage({
|
|||||||
{/* FAQ(内链 + FAQPage schema) */}
|
{/* FAQ(内链 + FAQPage schema) */}
|
||||||
<section className="rounded-xl border border-border p-6">
|
<section className="rounded-xl border border-border p-6">
|
||||||
<h2 className="text-lg font-semibold text-foreground">
|
<h2 className="text-lg font-semibold text-foreground">
|
||||||
Frequently asked questions
|
{tf("title")}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="mt-4 space-y-4">
|
<div className="mt-4 space-y-4">
|
||||||
{seo.faqs.map((faq, i) => (
|
{seo.faqs.map((faq, i) => (
|
||||||
@@ -163,7 +165,7 @@ export default async function BestCollectionPage({
|
|||||||
|
|
||||||
{/* 相关榜单(内链) */}
|
{/* 相关榜单(内链) */}
|
||||||
<section className="mt-10">
|
<section className="mt-10">
|
||||||
<h2 className="mb-3 text-sm font-semibold text-foreground">More best lists</h2>
|
<h2 className="mb-3 text-sm font-semibold text-foreground">{tb("more")}</h2>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{allCollections
|
{allCollections
|
||||||
.filter((col) => col.id !== collection.id)
|
.filter((col) => col.id !== collection.id)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { setRequestLocale } from "next-intl/server";
|
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||||
import { generatePageMetadata } from "@/lib/metadata";
|
import { generatePageMetadata } from "@/lib/metadata";
|
||||||
import { getCollections } from "@/features/discovery/actions";
|
import { getCollections } from "@/features/discovery/actions";
|
||||||
import { CollectionPageJsonLd } from "@/components/json-ld";
|
import { CollectionPageJsonLd } from "@/components/json-ld";
|
||||||
@@ -30,6 +30,7 @@ export default async function BestIndexPage({
|
|||||||
}) {
|
}) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
setRequestLocale(locale);
|
setRequestLocale(locale);
|
||||||
|
const t = await getTranslations("best");
|
||||||
const collections = await getCollections().catch(() => []);
|
const collections = await getCollections().catch(() => []);
|
||||||
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3001";
|
const baseUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3001";
|
||||||
|
|
||||||
@@ -44,17 +45,16 @@ export default async function BestIndexPage({
|
|||||||
|
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<h1 className="text-2xl font-bold tracking-tight text-foreground sm:text-3xl">
|
<h1 className="text-2xl font-bold tracking-tight text-foreground sm:text-3xl">
|
||||||
Best AI Tools — Curated Lists
|
{t("indexTitle")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-2 text-sm text-muted-foreground">
|
<p className="mt-2 text-sm text-muted-foreground">
|
||||||
Hand-picked rankings, updated with community signal. Every list is
|
{t("indexSubtitle")}
|
||||||
labeled and never sold.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{collections.length === 0 ? (
|
{collections.length === 0 ? (
|
||||||
<p className="rounded-xl border border-dashed border-border p-12 text-center text-sm text-muted-foreground">
|
<p className="rounded-xl border border-dashed border-border p-12 text-center text-sm text-muted-foreground">
|
||||||
No collections published yet.
|
{t("empty")}
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="grid gap-4 sm:grid-cols-2">
|
<div className="grid gap-4 sm:grid-cols-2">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { setRequestLocale } from "next-intl/server";
|
import { getTranslations, setRequestLocale } from "next-intl/server";
|
||||||
import { generatePageMetadata } from "@/lib/metadata";
|
import { generatePageMetadata } from "@/lib/metadata";
|
||||||
import { getCategoriesWithCount } from "@/features/tools/actions";
|
import { getCategoriesWithCount } from "@/features/tools/actions";
|
||||||
import { SubmitToolForm } from "@/features/submission/components/submit-tool-form";
|
import { SubmitToolForm } from "@/features/submission/components/submit-tool-form";
|
||||||
@@ -28,6 +28,7 @@ export default async function SubmitPage({
|
|||||||
}) {
|
}) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
setRequestLocale(locale);
|
setRequestLocale(locale);
|
||||||
|
const t = await getTranslations("submitPage");
|
||||||
|
|
||||||
const categories = await getCategoriesWithCount().catch(() => []);
|
const categories = await getCategoriesWithCount().catch(() => []);
|
||||||
|
|
||||||
@@ -35,11 +36,10 @@ export default async function SubmitPage({
|
|||||||
<div className="mx-auto max-w-2xl px-4 py-10 sm:px-6">
|
<div className="mx-auto max-w-2xl px-4 py-10 sm:px-6">
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<h1 className="text-2xl font-bold tracking-tight text-foreground sm:text-3xl">
|
<h1 className="text-2xl font-bold tracking-tight text-foreground sm:text-3xl">
|
||||||
Submit your AI tool
|
{t("title")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">
|
<p className="mt-2 text-sm leading-relaxed text-muted-foreground">
|
||||||
Get a free listing with community votes, user reviews and analytics.
|
{t("subtitle")}
|
||||||
Submissions are reviewed by our editors, usually within 48 hours.
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -121,6 +121,8 @@ export async function generateMetadata({ params }: ToolDetailPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const t = await getTranslations({ locale, namespace: "tools" });
|
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);
|
const tool = await getToolBySlug(slug);
|
||||||
if (!tool) {
|
if (!tool) {
|
||||||
return { title: t("notFound") };
|
return { title: t("notFound") };
|
||||||
@@ -162,6 +164,8 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const t = await getTranslations({ locale, namespace: "tools" });
|
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);
|
const tool = await getToolBySlug(slug);
|
||||||
|
|
||||||
if (!tool) {
|
if (!tool) {
|
||||||
@@ -341,7 +345,7 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) {
|
|||||||
<div>
|
<div>
|
||||||
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-foreground">
|
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-foreground">
|
||||||
<Target className="h-4 w-4 text-primary" />
|
<Target className="h-4 w-4 text-primary" />
|
||||||
Use cases
|
{ts("useCasesBlockTitle")}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{relations.useCases.map((uc) => (
|
{relations.useCases.map((uc) => (
|
||||||
@@ -360,7 +364,7 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) {
|
|||||||
<div>
|
<div>
|
||||||
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-foreground">
|
<h2 className="mb-3 flex items-center gap-2 text-sm font-semibold text-foreground">
|
||||||
<Users className="h-4 w-4 text-primary" />
|
<Users className="h-4 w-4 text-primary" />
|
||||||
Good for
|
{ts("goodForBlockTitle")}
|
||||||
</h2>
|
</h2>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{relations.audiences.map((aud) => (
|
{relations.audiences.map((aud) => (
|
||||||
@@ -465,7 +469,7 @@ export default async function ToolDetailPage({ params }: ToolDetailPageProps) {
|
|||||||
|
|
||||||
{/* FAQ */}
|
{/* FAQ */}
|
||||||
<section className="rounded-xl border border-border p-6">
|
<section className="rounded-xl border border-border p-6">
|
||||||
<h2 className="text-lg font-semibold text-foreground">FAQ</h2>
|
<h2 className="text-lg font-semibold text-foreground">{tf("title")}</h2>
|
||||||
<div className="mt-4 space-y-4">
|
<div className="mt-4 space-y-4">
|
||||||
{faqs.map((faq, i) => (
|
{faqs.map((faq, i) => (
|
||||||
<div key={i}>
|
<div key={i}>
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
<div style={{ minHeight: "60vh", display: "flex", alignItems: "center", justifyContent: "center", padding: "24px" }}>
|
||||||
|
<div style={{ textAlign: "center", maxWidth: "420px" }}>
|
||||||
|
<div style={{ width: 64, height: 64, margin: "0 auto 20px", borderRadius: 16, background: "#0a0a0a", display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
|
||||||
|
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" />
|
||||||
|
<path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<p style={{ fontSize: 13, letterSpacing: "0.2em", color: "#737373", margin: "0 0 8px" }}>{t("code")}</p>
|
||||||
|
<h1 style={{ fontSize: 24, margin: "0 0 8px" }}>{t("title")}</h1>
|
||||||
|
<p style={{ fontSize: 14, color: "#525252", lineHeight: 1.6, margin: "0 0 24px" }}>{t("body")}</p>
|
||||||
|
<div style={{ display: "flex", gap: 12, justifyContent: "center" }}>
|
||||||
|
<Link href="/" className="inline-block rounded-lg bg-primary px-5 py-2.5 text-sm font-medium text-primary-foreground">
|
||||||
|
{t("home")}
|
||||||
|
</Link>
|
||||||
|
<Link href="/tools" className="inline-block rounded-lg border border-border px-5 py-2.5 text-sm font-medium text-foreground">
|
||||||
|
{t("tools")}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,38 +1,38 @@
|
|||||||
import Link from 'next/link';
|
import Link from "next/link";
|
||||||
import { defaultLocale } from '@/i18n.config';
|
import { headers } from "next/headers";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* # 组件 NotFound
|
* # 组件 NotFound(根级)
|
||||||
* 说明:品牌化 404 页(图标 + 双入口:首页 / 工具目录)。
|
* 说明:无法使用 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 (
|
return (
|
||||||
<html>
|
<div style={{ minHeight: "100vh", display: "flex", alignItems: "center", justifyContent: "center", padding: "24px", fontFamily: "system-ui, sans-serif" }}>
|
||||||
<body style={{ margin: 0, fontFamily: 'system-ui, sans-serif', background: '#fafafa', color: '#0a0a0a' }}>
|
<div style={{ textAlign: "center", maxWidth: "420px" }}>
|
||||||
<div style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '24px' }}>
|
<div style={{ width: 64, height: 64, margin: "0 auto 20px", borderRadius: 16, background: "#0a0a0a", display: "flex", alignItems: "center", justifyContent: "center" }}>
|
||||||
<div style={{ textAlign: 'center', maxWidth: '420px' }}>
|
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
|
||||||
<div style={{ width: 64, height: 64, margin: '0 auto 20px', borderRadius: 16, background: '#0a0a0a', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
|
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" />
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
|
<path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
||||||
<path d="M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8" />
|
</svg>
|
||||||
<path d="M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" />
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<p style={{ fontSize: 13, letterSpacing: '0.2em', color: '#737373', margin: '0 0 8px' }}>404</p>
|
|
||||||
<h1 style={{ fontSize: 24, margin: '0 0 8px' }}>Page not found</h1>
|
|
||||||
<p style={{ fontSize: 14, color: '#525252', lineHeight: 1.6, margin: '0 0 24px' }}>
|
|
||||||
The page you are looking for doesn't exist or may have moved.
|
|
||||||
</p>
|
|
||||||
<div style={{ display: 'flex', gap: 12, justifyContent: 'center' }}>
|
|
||||||
<Link href={`/${defaultLocale}`} style={{ display: 'inline-block', padding: '10px 20px', borderRadius: 8, background: '#0a0a0a', color: '#fff', textDecoration: 'none', fontSize: 14 }}>
|
|
||||||
Back to home
|
|
||||||
</Link>
|
|
||||||
<Link href={`/${defaultLocale}/tools`} style={{ display: 'inline-block', padding: '10px 20px', borderRadius: 8, border: '1px solid #e5e5e5', color: '#0a0a0a', textDecoration: 'none', fontSize: 14 }}>
|
|
||||||
Browse tools
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</body>
|
<p style={{ fontSize: 13, letterSpacing: "0.2em", color: "#737373", margin: "0 0 8px" }}>{text.code}</p>
|
||||||
</html>
|
<h1 style={{ fontSize: 24, margin: "0 0 8px" }}>{text.title}</h1>
|
||||||
|
<p style={{ fontSize: 14, color: "#525252", lineHeight: 1.6, margin: "0 0 24px" }}>{text.body}</p>
|
||||||
|
<div style={{ display: "flex", gap: 12, justifyContent: "center" }}>
|
||||||
|
<Link href="/" className="inline-block rounded-lg bg-primary px-5 py-2.5 text-sm font-medium text-primary-foreground">
|
||||||
|
{text.home}
|
||||||
|
</Link>
|
||||||
|
<Link href="/tools" className="inline-block rounded-lg border border-border px-5 py-2.5 text-sm font-medium text-foreground">
|
||||||
|
{text.tools}
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,12 +53,30 @@
|
|||||||
"linkedin": "LinkedIn",
|
"linkedin": "LinkedIn",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"Discover",
|
||||||
|
"Use Cases",
|
||||||
|
"Best Lists",
|
||||||
|
"Rankings",
|
||||||
|
"Blog",
|
||||||
|
"Submit"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/tools",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/best",
|
||||||
|
"/rankings",
|
||||||
|
"/blog",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "Discover the Best AI Tools",
|
"badge": "Discover the Best AI Tools",
|
||||||
"title": "AI Stack — Find the Best AI Tools, Ranked by Real Users",
|
"title": "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.",
|
"description": "1,000+ AI tools across 14 categories. Compare votes, reviews and pricing to pick the right one.",
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "Explore Tools",
|
"primary": "Explore Tools",
|
||||||
"secondary": "Read Blog"
|
"secondary": "Read Blog"
|
||||||
@@ -649,7 +667,9 @@
|
|||||||
"latest": "Latest",
|
"latest": "Latest",
|
||||||
"trending": "Trending"
|
"trending": "Trending"
|
||||||
},
|
},
|
||||||
"clearFilters": "Clear search & filters"
|
"clearFilters": "Clear search & filters",
|
||||||
|
"useCasesTitle": "Use cases",
|
||||||
|
"goodForTitle": "Good for"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -796,5 +816,284 @@
|
|||||||
"new": "New",
|
"new": "New",
|
||||||
"editorsChoice": "Editor's Choice",
|
"editorsChoice": "Editor's Choice",
|
||||||
"empty": "No tools on this board yet."
|
"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..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,12 +53,29 @@
|
|||||||
"linkedin": "领英",
|
"linkedin": "领英",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"发现",
|
||||||
|
"用例",
|
||||||
|
"最佳清单",
|
||||||
|
"排行榜",
|
||||||
|
"博客",
|
||||||
|
"提交工具"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/tools",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/best",
|
||||||
|
"/rankings",
|
||||||
|
"/blog",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "发现最好的 AI 工具",
|
"title": "找到最好的 AI 工具,由真实用户排名",
|
||||||
"title": "AI Stack — 由真实用户排名的 AI 工具目录",
|
"description": "14 个分类、1000+ AI 工具。对比投票、评论与定价,选出最适合你的。",
|
||||||
"description": "专业 AI 工具导航:14 个分类、1000+ 工具,由社区投票、评论与互动数据实时排名。",
|
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "探索工具",
|
"primary": "探索工具",
|
||||||
"secondary": "阅读博客"
|
"secondary": "阅读博客"
|
||||||
@@ -657,7 +674,9 @@
|
|||||||
"latest": "最新",
|
"latest": "最新",
|
||||||
"trending": "最热"
|
"trending": "最热"
|
||||||
},
|
},
|
||||||
"clearFilters": "清除搜索与筛选"
|
"clearFilters": "清除搜索与筛选",
|
||||||
|
"useCasesTitle": "使用场景",
|
||||||
|
"goodForTitle": "适合人群"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -804,5 +823,284 @@
|
|||||||
"new": "最新收录",
|
"new": "最新收录",
|
||||||
"editorsChoice": "编辑精选",
|
"editorsChoice": "编辑精选",
|
||||||
"empty": "该榜单暂无工具。"
|
"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 工具..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// 自动生成:[locale]/not-found.tsx 的薄路由
|
||||||
|
export { default } from "@aidir/core/pages/[locale]/not-found";
|
||||||
@@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config";
|
|||||||
const brandMessages = {
|
const brandMessages = {
|
||||||
en: {
|
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"} },
|
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." } },
|
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: {
|
zh: {
|
||||||
seo: { home: {"title":"AI Stack — 由真实用户排名的 AI 工具目录","description":"专业 AI 工具导航:14 个分类、1000+ 工具,由社区投票、评论与互动数据实时排名。","ogImage":"/og-image.png"} },
|
seo: { home: {"title":"AI Stack — 由真实用户排名的 AI 工具目录","description":"专业 AI 工具导航:14 个分类、1000+ 工具,由社区投票、评论与互动数据实时排名。","ogImage":"/og-image.png"} },
|
||||||
hero: { title: "AI Stack — 由真实用户排名的 AI 工具目录", description: "专业 AI 工具导航:14 个分类、1000+ 工具,由社区投票、评论与互动数据实时排名。" },
|
hero: { title: "找到最好的 AI 工具,由真实用户排名", description: "14 个分类、1000+ AI 工具。对比投票、评论与定价,选出最适合你的。" },
|
||||||
common: { brand: { name: "AI Stack", tagline: "The professional AI tools directory — ranked by the community." } },
|
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;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,26 @@ import type { SiteConfig } from "@/kit/types";
|
|||||||
|
|
||||||
// AI Stack —— 独立站点的全部品牌/导航/页脚配置
|
// AI Stack —— 独立站点的全部品牌/导航/页脚配置
|
||||||
export const siteConfig: SiteConfig = {
|
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%",
|
"accent": "222 47% 11%",
|
||||||
"port": 3001,
|
"port": 3001,
|
||||||
"brand": {
|
"brand": {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// 自动生成:站点首页组件(源自底座 classic 形态,品牌来自 @/site/brand)
|
// 自动生成:站点首页组件(源自底座 classic 形态,品牌来自 @/site/brand)
|
||||||
import { siteConfig } from "@/site/brand";
|
import { siteConfig } from "@/site/brand";
|
||||||
import { Search, TrendingUp, Sparkles, Clock, Award, LayoutGrid, MessageSquareQuote } from "lucide-react";
|
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 { ToolCard, ToolCardGrid } from "@/components/tool-card";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { SectionHeader } from "@/kit/section";
|
import { SectionHeader } from "@/kit/section";
|
||||||
@@ -50,6 +51,8 @@ const footerGroups = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function SiteHome({ locale }: { locale: string }) {
|
async function SiteHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(8);
|
const data = await getHomeDataSafe(8);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -58,17 +61,17 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
<section className="border-b border-border bg-gradient-to-b from-secondary/40 to-background">
|
<section className="border-b border-border bg-gradient-to-b from-secondary/40 to-background">
|
||||||
<div className="mx-auto max-w-7xl px-4 py-16 text-center sm:px-6 md:py-24">
|
<div className="mx-auto max-w-7xl px-4 py-16 text-center sm:px-6 md:py-24">
|
||||||
<h1 className="mx-auto max-w-3xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
|
<h1 className="mx-auto max-w-3xl text-3xl font-bold tracking-tight text-foreground sm:text-4xl md:text-5xl">
|
||||||
{siteConfig.brand.headline}
|
{th("title")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mx-auto mt-4 max-w-2xl text-sm text-muted-foreground sm:text-base">
|
<p className="mx-auto mt-4 max-w-2xl text-sm text-muted-foreground sm:text-base">
|
||||||
{siteConfig.brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
<form action={`/${locale}/tools`} className="mx-auto mt-8 max-w-xl">
|
<form action={`/${locale}/tools`} className="mx-auto mt-8 max-w-xl">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Search className="absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
<Search className="absolute left-4 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
|
||||||
<input
|
<input
|
||||||
name="search"
|
name="search"
|
||||||
placeholder="Search 1,000+ AI tools..."
|
placeholder={t("searchPlaceholder")}
|
||||||
className="h-12 w-full rounded-full border border-border bg-background pl-11 pr-28 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/30"
|
className="h-12 w-full rounded-full border border-border bg-background pl-11 pr-28 text-sm text-foreground shadow-sm placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-primary/30"
|
||||||
aria-label="Search AI tools"
|
aria-label="Search AI tools"
|
||||||
/>
|
/>
|
||||||
@@ -76,13 +79,13 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
type="submit"
|
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"
|
className="absolute right-1.5 top-1.5 h-9 rounded-full bg-primary px-5 text-xs font-semibold text-primary-foreground transition-opacity hover:opacity-90"
|
||||||
>
|
>
|
||||||
Search
|
{t("searchButton")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground">
|
<div className="mt-4 flex flex-wrap items-center justify-center gap-2 text-xs text-muted-foreground">
|
||||||
<span>Popular:</span>
|
<span>{t("popularLabel")}</span>
|
||||||
{["writing", "video", "coding", "image"].map((q) => (
|
{t.raw("popularSearches").map((q: string) => (
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
key={q}
|
key={q}
|
||||||
href={`/tools?search=${q}`}
|
href={`/tools?search=${q}`}
|
||||||
@@ -100,10 +103,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.trending.length > 0 && (
|
{data.trending.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Trending this week"
|
title={t("trendingTitle")}
|
||||||
subtitle="Ranked by votes, reviews and engagement over the last 7 days"
|
subtitle={t("trendingSubtitle")}
|
||||||
viewAllHref="/rankings?board=trending"
|
viewAllHref="/rankings?board=trending"
|
||||||
viewAllLabel="All rankings"
|
viewAllLabel={t("allRankings")}
|
||||||
/>
|
/>
|
||||||
<ToolCardGrid tools={data.trending} locale={locale} ranked />
|
<ToolCardGrid tools={data.trending} locale={locale} ranked />
|
||||||
</section>
|
</section>
|
||||||
@@ -113,9 +116,9 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.categories.length > 0 && (
|
{data.categories.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Browse by category"
|
title={t("categoriesTitle")}
|
||||||
viewAllHref="/tools"
|
viewAllHref="/tools"
|
||||||
viewAllLabel="All tools"
|
viewAllLabel={t("categoriesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
|
<div className="grid grid-cols-2 gap-3 sm:grid-cols-3 lg:grid-cols-5">
|
||||||
{data.categories.slice(0, 10).map((category) => (
|
{data.categories.slice(0, 10).map((category) => (
|
||||||
@@ -144,7 +147,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.newest.length > 0 && (
|
{data.newest.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="New AI tools"
|
title={t("newTitle")}
|
||||||
viewAllHref="/rankings?board=new"
|
viewAllHref="/rankings?board=new"
|
||||||
/>
|
/>
|
||||||
<ToolCardGrid tools={data.newest.slice(0, 4)} locale={locale} />
|
<ToolCardGrid tools={data.newest.slice(0, 4)} locale={locale} />
|
||||||
@@ -153,7 +156,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.editorsChoice.length > 0 && (
|
{data.editorsChoice.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Editor's Choice"
|
title={t("editorsTitle")}
|
||||||
viewAllHref="/rankings?board=editors-choice"
|
viewAllHref="/rankings?board=editors-choice"
|
||||||
/>
|
/>
|
||||||
<ToolCardGrid tools={data.editorsChoice.slice(0, 4)} locale={locale} />
|
<ToolCardGrid tools={data.editorsChoice.slice(0, 4)} locale={locale} />
|
||||||
@@ -165,10 +168,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.useCases.length > 0 && (
|
{data.useCases.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Tools by use case"
|
title={t("useCasesTitle")}
|
||||||
subtitle="What do you want to get done?"
|
subtitle={t("useCasesSubtitle")}
|
||||||
viewAllHref="/ai-tools-for"
|
viewAllHref="/ai-tools-for"
|
||||||
viewAllLabel="All use cases"
|
viewAllLabel={t("useCasesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{data.useCases.slice(0, 12).map((uc) => (
|
{data.useCases.slice(0, 12).map((uc) => (
|
||||||
@@ -191,10 +194,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.collections.length > 0 && (
|
{data.collections.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Best AI tool lists"
|
title={t("bestListsTitle")}
|
||||||
subtitle="Curated rankings by our editors"
|
subtitle={t("bestListsSubtitle")}
|
||||||
viewAllHref="/best"
|
viewAllHref="/best"
|
||||||
viewAllLabel="All lists"
|
viewAllLabel={t("bestListsViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{data.collections.slice(0, 3).map((col) => (
|
{data.collections.slice(0, 3).map((col) => (
|
||||||
@@ -222,7 +225,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{/* Latest Reviews */}
|
{/* Latest Reviews */}
|
||||||
{data.latestReviews.length > 0 && (
|
{data.latestReviews.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader title="Latest community reviews" />
|
<SectionHeader title={t("reviewsTitle")} />
|
||||||
<div className="grid gap-3 md:grid-cols-2">
|
<div className="grid gap-3 md:grid-cols-2">
|
||||||
{data.latestReviews.map((review, i) => (
|
{data.latestReviews.map((review, i) => (
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
|
|||||||
@@ -53,12 +53,28 @@
|
|||||||
"linkedin": "LinkedIn",
|
"linkedin": "LinkedIn",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"Tools",
|
||||||
|
"Workflows",
|
||||||
|
"Use Cases",
|
||||||
|
"Rankings",
|
||||||
|
"Submit"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/tools",
|
||||||
|
"/best",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/rankings",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "Discover the Best AI Tools",
|
"badge": "Discover the Best AI Tools",
|
||||||
"title": "DevAI.tools — AI Tools for Developers",
|
"title": "AI tools for developers",
|
||||||
"description": "Code assistants, DevOps automation and testing copilots — the AI tools developers actually upvote, ranked daily.",
|
"description": "Code assistants, DevOps automation, testing copilots and everything else you ship with.",
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "Explore Tools",
|
"primary": "Explore Tools",
|
||||||
"secondary": "Read Blog"
|
"secondary": "Read Blog"
|
||||||
@@ -649,7 +665,9 @@
|
|||||||
"latest": "Latest",
|
"latest": "Latest",
|
||||||
"trending": "Trending"
|
"trending": "Trending"
|
||||||
},
|
},
|
||||||
"clearFilters": "Clear search & filters"
|
"clearFilters": "Clear search & filters",
|
||||||
|
"useCasesTitle": "Use cases",
|
||||||
|
"goodForTitle": "Good for"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -796,5 +814,276 @@
|
|||||||
"new": "New",
|
"new": "New",
|
||||||
"editorsChoice": "Editor's Choice",
|
"editorsChoice": "Editor's Choice",
|
||||||
"empty": "No tools on this board yet."
|
"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": "Directory",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "All Tools",
|
||||||
|
"href": "/tools"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Rankings",
|
||||||
|
"href": "/rankings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Use Cases",
|
||||||
|
"href": "/ai-tools-for"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Build",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "Workflows",
|
||||||
|
"href": "/best"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Submit a Tool",
|
||||||
|
"href": "/submit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Blog",
|
||||||
|
"href": "/blog"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Legal",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "Terms",
|
||||||
|
"href": "/terms"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Privacy",
|
||||||
|
"href": "/privacy"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"siteHeader": {
|
||||||
|
"searchPlaceholder": "Search dev tools..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,12 +53,27 @@
|
|||||||
"linkedin": "领英",
|
"linkedin": "领英",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"工具",
|
||||||
|
"工作流",
|
||||||
|
"用例",
|
||||||
|
"排行榜",
|
||||||
|
"提交"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/tools",
|
||||||
|
"/best",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/rankings",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "发现最好的 AI 工具",
|
"title": "开发者的 AI 工具",
|
||||||
"title": "DevAI.tools — 开发者 AI 工具",
|
"description": "代码助手、运维自动化、测试副驾驶,你上手的一切。",
|
||||||
"description": "面向开发者的 AI 工具目录:代码助手、运维自动化、测试副驾驶,由社区每日排名。",
|
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "探索工具",
|
"primary": "探索工具",
|
||||||
"secondary": "阅读博客"
|
"secondary": "阅读博客"
|
||||||
@@ -657,7 +672,9 @@
|
|||||||
"latest": "最新",
|
"latest": "最新",
|
||||||
"trending": "最热"
|
"trending": "最热"
|
||||||
},
|
},
|
||||||
"clearFilters": "清除搜索与筛选"
|
"clearFilters": "清除搜索与筛选",
|
||||||
|
"useCasesTitle": "使用场景",
|
||||||
|
"goodForTitle": "适合人群"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -804,5 +821,276 @@
|
|||||||
"new": "最新收录",
|
"new": "最新收录",
|
||||||
"editorsChoice": "编辑精选",
|
"editorsChoice": "编辑精选",
|
||||||
"empty": "该榜单暂无工具。"
|
"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": "Rankings",
|
||||||
|
"href": "/rankings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Use Cases",
|
||||||
|
"href": "/ai-tools-for"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "构建",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "Workflows",
|
||||||
|
"href": "/best"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Submit a Tool",
|
||||||
|
"href": "/submit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Blog",
|
||||||
|
"href": "/blog"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "法律",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "Terms",
|
||||||
|
"href": "/terms"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Privacy",
|
||||||
|
"href": "/privacy"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"siteHeader": {
|
||||||
|
"searchPlaceholder": "搜索开发者工具..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// 自动生成:[locale]/not-found.tsx 的薄路由
|
||||||
|
export { default } from "@aidir/core/pages/[locale]/not-found";
|
||||||
@@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config";
|
|||||||
const brandMessages = {
|
const brandMessages = {
|
||||||
en: {
|
en: {
|
||||||
seo: { home: {"title":"DevAI.tools — AI Tools for Developers","description":"Code assistants, DevOps automation and testing copilots — the AI tools developers actually upvote, ranked daily.","ogImage":"/og-image.png"} },
|
seo: { home: {"title":"DevAI.tools — AI Tools for Developers","description":"Code assistants, DevOps automation and testing copilots — the AI tools developers actually upvote, ranked daily.","ogImage":"/og-image.png"} },
|
||||||
hero: { title: "DevAI.tools — AI Tools for Developers", description: "Code assistants, DevOps automation and testing copilots — the AI tools developers actually upvote, ranked daily." },
|
hero: { title: "AI tools for developers", description: "Code assistants, DevOps automation, testing copilots and everything else you ship with." },
|
||||||
common: { brand: { name: "DevAI.tools", tagline: "AI tools for developers — curated, tested, ranked by the community." } },
|
common: { brand: { name: "DevAI.tools", tagline: "AI tools for developers — curated, tested, ranked by the community." } },
|
||||||
|
navigation: {
|
||||||
|
main: { tools: "Tools", blog: "Blog" },
|
||||||
|
site: { items: ["Tools","Workflows","Use Cases","Rankings","Submit"], hrefs: ["/tools","/best","/ai-tools-for","/rankings","/submit"] },
|
||||||
|
},
|
||||||
|
siteFooter: { groups: [{"title":"Directory","links":[{"label":"All Tools","href":"/tools"},{"label":"Rankings","href":"/rankings"},{"label":"Use Cases","href":"/ai-tools-for"}]},{"title":"Build","links":[{"label":"Workflows","href":"/best"},{"label":"Submit a Tool","href":"/submit"},{"label":"Blog","href":"/blog"}]},{"title":"Legal","links":[{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"}]}] },
|
||||||
|
siteHeader: { searchPlaceholder: "Search dev tools..." },
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
seo: { home: {"title":"DevAI.tools — 开发者 AI 工具","description":"面向开发者的 AI 工具目录:代码助手、运维自动化、测试副驾驶,由社区每日排名。","ogImage":"/og-image.png"} },
|
seo: { home: {"title":"DevAI.tools — 开发者 AI 工具","description":"面向开发者的 AI 工具目录:代码助手、运维自动化、测试副驾驶,由社区每日排名。","ogImage":"/og-image.png"} },
|
||||||
hero: { title: "DevAI.tools — 开发者 AI 工具", description: "面向开发者的 AI 工具目录:代码助手、运维自动化、测试副驾驶,由社区每日排名。" },
|
hero: { title: "开发者的 AI 工具", description: "代码助手、运维自动化、测试副驾驶,你上手的一切。" },
|
||||||
common: { brand: { name: "DevAI.tools", tagline: "AI tools for developers — curated, tested, ranked by the community." } },
|
common: { brand: { name: "DevAI.tools", tagline: "面向开发者的 AI 工具——精选、实测、社区排名。" } },
|
||||||
|
navigation: {
|
||||||
|
main: { tools: "工具", blog: "博客" },
|
||||||
|
site: { items: ["工具","工作流","用例","排行榜","提交"], hrefs: ["/tools","/best","/ai-tools-for","/rankings","/submit"] },
|
||||||
|
},
|
||||||
|
siteFooter: { groups: [{"title":"目录","links":[{"label":"All Tools","href":"/tools"},{"label":"Rankings","href":"/rankings"},{"label":"Use Cases","href":"/ai-tools-for"}]},{"title":"构建","links":[{"label":"Workflows","href":"/best"},{"label":"Submit a Tool","href":"/submit"},{"label":"Blog","href":"/blog"}]},{"title":"法律","links":[{"label":"Terms","href":"/terms"},{"label":"Privacy","href":"/privacy"}]}] },
|
||||||
|
siteHeader: { searchPlaceholder: "搜索开发者工具..." },
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,25 @@ import type { SiteConfig } from "@/kit/types";
|
|||||||
|
|
||||||
// DevAI.tools —— 独立站点的全部品牌/导航/页脚配置
|
// DevAI.tools —— 独立站点的全部品牌/导航/页脚配置
|
||||||
export const siteConfig: SiteConfig = {
|
export const siteConfig: SiteConfig = {
|
||||||
|
"brandZh": {
|
||||||
|
"name": "DevAI.tools",
|
||||||
|
"tagline": "面向开发者的 AI 工具——精选、实测、社区排名。",
|
||||||
|
"headline": "开发者的 AI 工具",
|
||||||
|
"subheadline": "代码助手、运维自动化、测试副驾驶,你上手的一切。",
|
||||||
|
"nav": [
|
||||||
|
"工具",
|
||||||
|
"工作流",
|
||||||
|
"用例",
|
||||||
|
"排行榜",
|
||||||
|
"提交"
|
||||||
|
],
|
||||||
|
"footer": [
|
||||||
|
"目录",
|
||||||
|
"构建",
|
||||||
|
"法律"
|
||||||
|
],
|
||||||
|
"searchPlaceholder": "搜索开发者工具..."
|
||||||
|
},
|
||||||
"accent": "150 60% 30%",
|
"accent": "150 60% 30%",
|
||||||
"port": 3004,
|
"port": 3004,
|
||||||
"brand": {
|
"brand": {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// 自动生成:站点首页组件(源自底座 niche 形态,品牌来自 @/site/brand)
|
// 自动生成:站点首页组件(源自底座 niche 形态,品牌来自 @/site/brand)
|
||||||
import { siteConfig } from "@/site/brand";
|
import { siteConfig } from "@/site/brand";
|
||||||
import { Code2, Terminal, Workflow, Layers } from "lucide-react";
|
import { Code2, Terminal, Workflow, Layers } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { ToolCard } from "@/components/tool-card";
|
import { ToolCard } from "@/components/tool-card";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { SectionHeader } from "@/kit/section";
|
import { SectionHeader } from "@/kit/section";
|
||||||
@@ -44,6 +45,8 @@ const footerGroups = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function SiteHome({ locale }: { locale: string }) {
|
async function SiteHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(6);
|
const data = await getHomeDataSafe(6);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -65,10 +68,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
</p>
|
</p>
|
||||||
<p className="flex items-center gap-2 text-foreground">
|
<p className="flex items-center gap-2 text-foreground">
|
||||||
<Terminal className="h-3.5 w-3.5 text-emerald-600 dark:text-emerald-400" />
|
<Terminal className="h-3.5 w-3.5 text-emerald-600 dark:text-emerald-400" />
|
||||||
{siteConfig.brand.headline}
|
{th("title")}
|
||||||
</p>
|
</p>
|
||||||
<p className="text-xs leading-relaxed text-muted-foreground">
|
<p className="text-xs leading-relaxed text-muted-foreground">
|
||||||
{siteConfig.brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
<p className="pt-2">
|
<p className="pt-2">
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
@@ -88,10 +91,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.useCases.length > 0 && (
|
{data.useCases.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Ship faster with AI"
|
title={t("shipTitle")}
|
||||||
subtitle="Pick your workflow — we ranked the tools for it"
|
subtitle={t("shipSubtitle")}
|
||||||
viewAllHref="/ai-tools-for"
|
viewAllHref="/ai-tools-for"
|
||||||
viewAllLabel="All use cases"
|
viewAllLabel={t("useCasesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{data.useCases.slice(0, 6).map((uc) => (
|
{data.useCases.slice(0, 6).map((uc) => (
|
||||||
@@ -119,7 +122,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.trending.length > 0 && (
|
{data.trending.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Most upvoted this week"
|
title={t("upvotedTitle")}
|
||||||
viewAllHref="/rankings?board=trending"
|
viewAllHref="/rankings?board=trending"
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 md:grid-cols-2">
|
<div className="grid gap-3 md:grid-cols-2">
|
||||||
@@ -139,10 +142,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.collections.length > 0 && (
|
{data.collections.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Workflows & stacks"
|
title={t("workflowsTitle")}
|
||||||
subtitle="Batteries-included tool stacks for common dev tasks"
|
subtitle={t("workflowsSubtitle")}
|
||||||
viewAllHref="/best"
|
viewAllHref="/best"
|
||||||
viewAllLabel="All workflows"
|
viewAllLabel={t("workflowsViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
<div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{data.collections.slice(0, 3).map((col) => (
|
{data.collections.slice(0, 3).map((col) => (
|
||||||
@@ -167,7 +170,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{/* Categories */}
|
{/* Categories */}
|
||||||
{data.categories.length > 0 && (
|
{data.categories.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader title="Browse by category" viewAllHref="/tools" />
|
<SectionHeader title={t("categoriesTitle")} viewAllHref="/tools" />
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{data.categories.slice(0, 14).map((cat) => (
|
{data.categories.slice(0, 14).map((cat) => (
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
|
|||||||
@@ -53,11 +53,25 @@
|
|||||||
"linkedin": "LinkedIn",
|
"linkedin": "LinkedIn",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"Search",
|
||||||
|
"Use Cases",
|
||||||
|
"Rankings",
|
||||||
|
"Submit"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/tools",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/rankings",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "Discover the Best AI Tools",
|
"badge": "Discover the Best AI Tools",
|
||||||
"title": "findai — The Minimal AI Tool Search Engine",
|
"title": "What are you trying to do?",
|
||||||
"description": "One search box, every AI tool. Describe what you're trying to do and find the right AI tool, ranked by the community.",
|
"description": "One search box, every AI tool. Describe what you're trying to do and find the right AI tool, ranked by the community.",
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "Explore Tools",
|
"primary": "Explore Tools",
|
||||||
@@ -649,7 +663,9 @@
|
|||||||
"latest": "Latest",
|
"latest": "Latest",
|
||||||
"trending": "Trending"
|
"trending": "Trending"
|
||||||
},
|
},
|
||||||
"clearFilters": "Clear search & filters"
|
"clearFilters": "Clear search & filters",
|
||||||
|
"useCasesTitle": "Use cases",
|
||||||
|
"goodForTitle": "Good for"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -796,5 +812,263 @@
|
|||||||
"new": "New",
|
"new": "New",
|
||||||
"editorsChoice": "Editor's Choice",
|
"editorsChoice": "Editor's Choice",
|
||||||
"empty": "No tools on this board yet."
|
"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": "Search",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "All Tools",
|
||||||
|
"href": "/tools"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Use Cases",
|
||||||
|
"href": "/ai-tools-for"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Rankings",
|
||||||
|
"href": "/rankings"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "About",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "Submit a Tool",
|
||||||
|
"href": "/submit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Privacy",
|
||||||
|
"href": "/privacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Terms",
|
||||||
|
"href": "/terms"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"siteHeader": {
|
||||||
|
"searchPlaceholder": "What do you need?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,11 +53,24 @@
|
|||||||
"linkedin": "领英",
|
"linkedin": "领英",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"搜索",
|
||||||
|
"用例",
|
||||||
|
"排行榜",
|
||||||
|
"提交"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/tools",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/rankings",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "发现最好的 AI 工具",
|
"title": "你想完成什么?",
|
||||||
"title": "findai — 极简 AI 工具搜索引擎",
|
|
||||||
"description": "一个搜索框,找遍全部 AI 工具。说出你想做的事,社区排名替你选。",
|
"description": "一个搜索框,找遍全部 AI 工具。说出你想做的事,社区排名替你选。",
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "探索工具",
|
"primary": "探索工具",
|
||||||
@@ -657,7 +670,9 @@
|
|||||||
"latest": "最新",
|
"latest": "最新",
|
||||||
"trending": "最热"
|
"trending": "最热"
|
||||||
},
|
},
|
||||||
"clearFilters": "清除搜索与筛选"
|
"clearFilters": "清除搜索与筛选",
|
||||||
|
"useCasesTitle": "使用场景",
|
||||||
|
"goodForTitle": "适合人群"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -804,5 +819,263 @@
|
|||||||
"new": "最新收录",
|
"new": "最新收录",
|
||||||
"editorsChoice": "编辑精选",
|
"editorsChoice": "编辑精选",
|
||||||
"empty": "该榜单暂无工具。"
|
"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": "Rankings",
|
||||||
|
"href": "/rankings"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "关于",
|
||||||
|
"links": [
|
||||||
|
{
|
||||||
|
"label": "Submit a Tool",
|
||||||
|
"href": "/submit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Privacy",
|
||||||
|
"href": "/privacy"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Terms",
|
||||||
|
"href": "/terms"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"siteHeader": {
|
||||||
|
"searchPlaceholder": "你需要什么?"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// 自动生成:[locale]/not-found.tsx 的薄路由
|
||||||
|
export { default } from "@aidir/core/pages/[locale]/not-found";
|
||||||
@@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config";
|
|||||||
const brandMessages = {
|
const brandMessages = {
|
||||||
en: {
|
en: {
|
||||||
seo: { home: {"title":"findai — The Minimal AI Tool Search Engine","description":"One search box, every AI tool. Describe what you're trying to do and find the right AI tool, ranked by the community.","ogImage":"/og-image.png"} },
|
seo: { home: {"title":"findai — The Minimal AI Tool Search Engine","description":"One search box, every AI tool. Describe what you're trying to do and find the right AI tool, ranked by the community.","ogImage":"/og-image.png"} },
|
||||||
hero: { title: "findai — The Minimal AI Tool Search Engine", description: "One search box, every AI tool. Describe what you're trying to do and find the right AI tool, ranked by the community." },
|
hero: { title: "What are you trying to do?", description: "One search box, every AI tool. Describe what you're trying to do and find the right AI tool, ranked by the community." },
|
||||||
common: { brand: { name: "findai", tagline: "The minimal AI tool search engine." } },
|
common: { brand: { name: "findai", tagline: "The minimal AI tool search engine." } },
|
||||||
|
navigation: {
|
||||||
|
main: { tools: "Search", blog: "Blog" },
|
||||||
|
site: { items: ["Search","Use Cases","Rankings","Submit"], hrefs: ["/tools","/ai-tools-for","/rankings","/submit"] },
|
||||||
|
},
|
||||||
|
siteFooter: { groups: [{"title":"Search","links":[{"label":"All Tools","href":"/tools"},{"label":"Use Cases","href":"/ai-tools-for"},{"label":"Rankings","href":"/rankings"}]},{"title":"About","links":[{"label":"Submit a Tool","href":"/submit"},{"label":"Privacy","href":"/privacy"},{"label":"Terms","href":"/terms"}]}] },
|
||||||
|
siteHeader: { searchPlaceholder: "What do you need?" },
|
||||||
},
|
},
|
||||||
zh: {
|
zh: {
|
||||||
seo: { home: {"title":"findai — 极简 AI 工具搜索引擎","description":"一个搜索框,找遍全部 AI 工具。说出你想做的事,社区排名替你选。","ogImage":"/og-image.png"} },
|
seo: { home: {"title":"findai — 极简 AI 工具搜索引擎","description":"一个搜索框,找遍全部 AI 工具。说出你想做的事,社区排名替你选。","ogImage":"/og-image.png"} },
|
||||||
hero: { title: "findai — 极简 AI 工具搜索引擎", description: "一个搜索框,找遍全部 AI 工具。说出你想做的事,社区排名替你选。" },
|
hero: { title: "你想完成什么?", description: "一个搜索框,找遍全部 AI 工具。说出你想做的事,社区排名替你选。" },
|
||||||
common: { brand: { name: "findai", tagline: "The minimal AI tool search engine." } },
|
common: { brand: { name: "findai", tagline: "极简 AI 工具搜索引擎。" } },
|
||||||
|
navigation: {
|
||||||
|
main: { tools: "搜索", blog: "博客" },
|
||||||
|
site: { items: ["搜索","用例","排行榜","提交"], hrefs: ["/tools","/ai-tools-for","/rankings","/submit"] },
|
||||||
|
},
|
||||||
|
siteFooter: { groups: [{"title":"搜索","links":[{"label":"All Tools","href":"/tools"},{"label":"Use Cases","href":"/ai-tools-for"},{"label":"Rankings","href":"/rankings"}]},{"title":"关于","links":[{"label":"Submit a Tool","href":"/submit"},{"label":"Privacy","href":"/privacy"},{"label":"Terms","href":"/terms"}]}] },
|
||||||
|
siteHeader: { searchPlaceholder: "你需要什么?" },
|
||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,23 @@ import type { SiteConfig } from "@/kit/types";
|
|||||||
|
|
||||||
// findai —— 独立站点的全部品牌/导航/页脚配置
|
// findai —— 独立站点的全部品牌/导航/页脚配置
|
||||||
export const siteConfig: SiteConfig = {
|
export const siteConfig: SiteConfig = {
|
||||||
|
"brandZh": {
|
||||||
|
"name": "findai",
|
||||||
|
"tagline": "极简 AI 工具搜索引擎。",
|
||||||
|
"headline": "你想完成什么?",
|
||||||
|
"subheadline": "",
|
||||||
|
"nav": [
|
||||||
|
"搜索",
|
||||||
|
"用例",
|
||||||
|
"排行榜",
|
||||||
|
"提交"
|
||||||
|
],
|
||||||
|
"footer": [
|
||||||
|
"搜索",
|
||||||
|
"关于"
|
||||||
|
],
|
||||||
|
"searchPlaceholder": "你需要什么?"
|
||||||
|
},
|
||||||
"accent": "260 70% 52%",
|
"accent": "260 70% 52%",
|
||||||
"port": 3005,
|
"port": 3005,
|
||||||
"brand": {
|
"brand": {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// 自动生成:站点首页组件(源自底座 minimal 形态,品牌来自 @/site/brand)
|
// 自动生成:站点首页组件(源自底座 minimal 形态,品牌来自 @/site/brand)
|
||||||
import { siteConfig } from "@/site/brand";
|
import { siteConfig } from "@/site/brand";
|
||||||
import { Search } from "lucide-react";
|
import { Search } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { ToolCardGrid } from "@/components/tool-card";
|
import { ToolCardGrid } from "@/components/tool-card";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { getHomeDataSafe } from "@/kit/home-data";
|
import { getHomeDataSafe } from "@/kit/home-data";
|
||||||
@@ -44,6 +45,8 @@ const popularSearches = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function SiteHome({ locale }: { locale: string }) {
|
async function SiteHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(6);
|
const data = await getHomeDataSafe(6);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -63,7 +66,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
<input
|
<input
|
||||||
name="search"
|
name="search"
|
||||||
autoFocus
|
autoFocus
|
||||||
placeholder="I need to create marketing videos..."
|
placeholder={t("minimalPlaceholder")}
|
||||||
className="h-14 w-full rounded-full border border-border bg-background pl-14 pr-6 text-base text-foreground shadow-lg shadow-black/[0.03] placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-4 focus:ring-primary/10"
|
className="h-14 w-full rounded-full border border-border bg-background pl-14 pr-6 text-base text-foreground shadow-lg shadow-black/[0.03] placeholder:text-muted-foreground focus:border-primary/50 focus:outline-none focus:ring-4 focus:ring-primary/10"
|
||||||
aria-label="Search AI tools"
|
aria-label="Search AI tools"
|
||||||
/>
|
/>
|
||||||
@@ -95,7 +98,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
href="/rankings"
|
href="/rankings"
|
||||||
className="text-xs font-medium text-muted-foreground hover:text-primary"
|
className="text-xs font-medium text-muted-foreground hover:text-primary"
|
||||||
>
|
>
|
||||||
See full rankings
|
{t("seeRankings")}
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -53,12 +53,30 @@
|
|||||||
"linkedin": "LinkedIn",
|
"linkedin": "LinkedIn",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"Today",
|
||||||
|
"Leaderboard",
|
||||||
|
"Categories",
|
||||||
|
"Collections",
|
||||||
|
"Blog",
|
||||||
|
"Submit"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/",
|
||||||
|
"/rankings",
|
||||||
|
"/tools",
|
||||||
|
"/best",
|
||||||
|
"/blog",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "Discover the Best AI Tools",
|
"badge": "Discover the Best AI Tools",
|
||||||
"title": "LaunchAI — Discover and Upvote Today's AI Products",
|
"title": "Today's AI product launches",
|
||||||
"description": "A daily launch feed for AI products. Upvote the best AI tools, follow makers and climb the leaderboard.",
|
"description": "Fresh AI products, every day. Upvote the best ones to the top.",
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "Explore Tools",
|
"primary": "Explore Tools",
|
||||||
"secondary": "Read Blog"
|
"secondary": "Read Blog"
|
||||||
@@ -649,7 +667,9 @@
|
|||||||
"latest": "Latest",
|
"latest": "Latest",
|
||||||
"trending": "Trending"
|
"trending": "Trending"
|
||||||
},
|
},
|
||||||
"clearFilters": "Clear search & filters"
|
"clearFilters": "Clear search & filters",
|
||||||
|
"useCasesTitle": "Use cases",
|
||||||
|
"goodForTitle": "Good for"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -796,5 +816,280 @@
|
|||||||
"new": "New",
|
"new": "New",
|
||||||
"editorsChoice": "Editor's Choice",
|
"editorsChoice": "Editor's Choice",
|
||||||
"empty": "No tools on this board yet."
|
"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..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,12 +53,29 @@
|
|||||||
"linkedin": "领英",
|
"linkedin": "领英",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"今日",
|
||||||
|
"排行榜",
|
||||||
|
"分类",
|
||||||
|
"合集",
|
||||||
|
"博客",
|
||||||
|
"提交产品"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/",
|
||||||
|
"/rankings",
|
||||||
|
"/tools",
|
||||||
|
"/best",
|
||||||
|
"/blog",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "发现最好的 AI 工具",
|
"title": "今日 AI 产品发布",
|
||||||
"title": "LaunchAI — 发现并投票今日 AI 新品",
|
"description": "每天上新。为最好的产品投票,冲上排行榜。",
|
||||||
"description": "AI 产品每日发布社区:为最好的 AI 工具投票,登上社区排行榜。",
|
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "探索工具",
|
"primary": "探索工具",
|
||||||
"secondary": "阅读博客"
|
"secondary": "阅读博客"
|
||||||
@@ -657,7 +674,9 @@
|
|||||||
"latest": "最新",
|
"latest": "最新",
|
||||||
"trending": "最热"
|
"trending": "最热"
|
||||||
},
|
},
|
||||||
"clearFilters": "清除搜索与筛选"
|
"clearFilters": "清除搜索与筛选",
|
||||||
|
"useCasesTitle": "使用场景",
|
||||||
|
"goodForTitle": "适合人群"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -804,5 +823,280 @@
|
|||||||
"new": "最新收录",
|
"new": "最新收录",
|
||||||
"editorsChoice": "编辑精选",
|
"editorsChoice": "编辑精选",
|
||||||
"empty": "该榜单暂无工具。"
|
"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 产品..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// 自动生成:[locale]/not-found.tsx 的薄路由
|
||||||
|
export { default } from "@aidir/core/pages/[locale]/not-found";
|
||||||
@@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config";
|
|||||||
const brandMessages = {
|
const brandMessages = {
|
||||||
en: {
|
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"} },
|
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." } },
|
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: {
|
zh: {
|
||||||
seo: { home: {"title":"LaunchAI — 发现并投票今日 AI 新品","description":"AI 产品每日发布社区:为最好的 AI 工具投票,登上社区排行榜。","ogImage":"/og-image.png"} },
|
seo: { home: {"title":"LaunchAI — 发现并投票今日 AI 新品","description":"AI 产品每日发布社区:为最好的 AI 工具投票,登上社区排行榜。","ogImage":"/og-image.png"} },
|
||||||
hero: { title: "LaunchAI — 发现并投票今日 AI 新品", description: "AI 产品每日发布社区:为最好的 AI 工具投票,登上社区排行榜。" },
|
hero: { title: "今日 AI 产品发布", description: "每天上新。为最好的产品投票,冲上排行榜。" },
|
||||||
common: { brand: { name: "LaunchAI", tagline: "Discover and upvote today's AI products." } },
|
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;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,26 @@ import type { SiteConfig } from "@/kit/types";
|
|||||||
|
|
||||||
// LaunchAI —— 独立站点的全部品牌/导航/页脚配置
|
// LaunchAI —— 独立站点的全部品牌/导航/页脚配置
|
||||||
export const siteConfig: SiteConfig = {
|
export const siteConfig: SiteConfig = {
|
||||||
|
"brandZh": {
|
||||||
|
"name": "LaunchAI",
|
||||||
|
"tagline": "发现并投票今日的 AI 新品。",
|
||||||
|
"headline": "今日 AI 产品发布",
|
||||||
|
"subheadline": "每天上新。为最好的产品投票,冲上排行榜。",
|
||||||
|
"nav": [
|
||||||
|
"今日",
|
||||||
|
"排行榜",
|
||||||
|
"分类",
|
||||||
|
"合集",
|
||||||
|
"博客",
|
||||||
|
"提交产品"
|
||||||
|
],
|
||||||
|
"footer": [
|
||||||
|
"社区",
|
||||||
|
"探索",
|
||||||
|
"关于"
|
||||||
|
],
|
||||||
|
"searchPlaceholder": "搜索 AI 产品..."
|
||||||
|
},
|
||||||
"accent": "16 85% 55%",
|
"accent": "16 85% 55%",
|
||||||
"port": 3002,
|
"port": 3002,
|
||||||
"brand": {
|
"brand": {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// 自动生成:站点首页组件(源自底座 product 形态,品牌来自 @/site/brand)
|
// 自动生成:站点首页组件(源自底座 product 形态,品牌来自 @/site/brand)
|
||||||
import { siteConfig } from "@/site/brand";
|
import { siteConfig } from "@/site/brand";
|
||||||
import { Flame, Trophy, Rocket, ChevronRight, MessageSquare } from "lucide-react";
|
import { Flame, Trophy, Rocket, ChevronRight, MessageSquare } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { VoteButton } from "@/features/voting/components/vote-button";
|
import { VoteButton } from "@/features/voting/components/vote-button";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { ToolLogo } from "@/components/tool-logo";
|
import { ToolLogo } from "@/components/tool-logo";
|
||||||
@@ -103,6 +104,8 @@ function LaunchRow({
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function SiteHome({ locale }: { locale: string }) {
|
async function SiteHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(10);
|
const data = await getHomeDataSafe(10);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -111,17 +114,17 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
<section className="border-b border-border bg-gradient-to-b from-primary/5 to-background">
|
<section className="border-b border-border bg-gradient-to-b from-primary/5 to-background">
|
||||||
<div className="mx-auto max-w-5xl px-4 py-12 text-center sm:px-6 md:py-16">
|
<div className="mx-auto max-w-5xl px-4 py-12 text-center sm:px-6 md:py-16">
|
||||||
<h1 className="text-2xl font-extrabold tracking-tight text-foreground sm:text-4xl">
|
<h1 className="text-2xl font-extrabold tracking-tight text-foreground sm:text-4xl">
|
||||||
{siteConfig.brand.headline}
|
{th("title")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mt-3 text-sm text-muted-foreground sm:text-base">
|
<p className="mt-3 text-sm text-muted-foreground sm:text-base">
|
||||||
{siteConfig.brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
href="/submit"
|
href="/submit"
|
||||||
className="mt-6 inline-flex items-center gap-1.5 rounded-full bg-primary px-6 py-2.5 text-sm font-semibold text-primary-foreground shadow transition-all hover:opacity-90"
|
className="mt-6 inline-flex items-center gap-1.5 rounded-full bg-primary px-6 py-2.5 text-sm font-semibold text-primary-foreground shadow transition-all hover:opacity-90"
|
||||||
>
|
>
|
||||||
<Rocket className="h-4 w-4" />
|
<Rocket className="h-4 w-4" />
|
||||||
Launch your product
|
{t("launchButton")}
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -140,14 +143,14 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<p className="px-6 py-12 text-center text-sm text-muted-foreground">
|
<p className="px-6 py-12 text-center text-sm text-muted-foreground">
|
||||||
No launches yet — be the first to submit.
|
{t("noLaunches")}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<LocaleLink
|
<LocaleLink
|
||||||
href="/tools"
|
href="/tools"
|
||||||
className="flex items-center justify-center gap-1 border-t border-border py-3 text-xs font-medium text-muted-foreground hover:text-primary"
|
className="flex items-center justify-center gap-1 border-t border-border py-3 text-xs font-medium text-muted-foreground hover:text-primary"
|
||||||
>
|
>
|
||||||
Browse all products
|
{t("feedBrowse")}
|
||||||
<ChevronRight className="h-3 w-3" />
|
<ChevronRight className="h-3 w-3" />
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
@@ -155,7 +158,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{/* New */}
|
{/* New */}
|
||||||
{data.newest.length > 0 && (
|
{data.newest.length > 0 && (
|
||||||
<div className="mt-8">
|
<div className="mt-8">
|
||||||
<SectionHeader title="Fresh launches" viewAllHref="/rankings?board=new" />
|
<SectionHeader title={t("newTitle")} viewAllHref="/rankings?board=new" />
|
||||||
<div className="overflow-hidden rounded-2xl border border-border bg-background">
|
<div className="overflow-hidden rounded-2xl border border-border bg-background">
|
||||||
{data.newest.slice(0, 5).map((tool) => (
|
{data.newest.slice(0, 5).map((tool) => (
|
||||||
<LaunchRow key={tool.id} tool={tool} locale={locale} />
|
<LaunchRow key={tool.id} tool={tool} locale={locale} />
|
||||||
@@ -200,14 +203,14 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
href="/rankings"
|
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"
|
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")}
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{data.editorsChoice.length > 0 && (
|
{data.editorsChoice.length > 0 && (
|
||||||
<div className="rounded-2xl border border-border bg-background p-5">
|
<div className="rounded-2xl border border-border bg-background p-5">
|
||||||
<h3 className="text-sm font-bold text-foreground">Editor's picks</h3>
|
<h3 className="text-sm font-bold text-foreground">{t("picksEditorialLabel")}</h3>
|
||||||
<ol className="mt-4 space-y-3">
|
<ol className="mt-4 space-y-3">
|
||||||
{data.editorsChoice.slice(0, 4).map((tool) => (
|
{data.editorsChoice.slice(0, 4).map((tool) => (
|
||||||
<li key={tool.id}>
|
<li key={tool.id}>
|
||||||
|
|||||||
@@ -53,12 +53,30 @@
|
|||||||
"linkedin": "LinkedIn",
|
"linkedin": "LinkedIn",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"Stories",
|
||||||
|
"Guides",
|
||||||
|
"Best Picks",
|
||||||
|
"Directory",
|
||||||
|
"Rankings",
|
||||||
|
"Submit"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/blog",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/best",
|
||||||
|
"/tools",
|
||||||
|
"/rankings",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "Discover the Best AI Tools",
|
"badge": "Discover the Best AI Tools",
|
||||||
"title": "The AI Ledger — AI Tools, Reviewed and Ranked",
|
"title": "AI tools, reviewed and ranked",
|
||||||
"description": "Independent journalism on AI: buying guides, comparisons and a community-ranked directory of the best AI tools.",
|
"description": "Guides, comparisons and a community-powered directory of the best AI tools.",
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "Explore Tools",
|
"primary": "Explore Tools",
|
||||||
"secondary": "Read Blog"
|
"secondary": "Read Blog"
|
||||||
@@ -649,7 +667,9 @@
|
|||||||
"latest": "Latest",
|
"latest": "Latest",
|
||||||
"trending": "Trending"
|
"trending": "Trending"
|
||||||
},
|
},
|
||||||
"clearFilters": "Clear search & filters"
|
"clearFilters": "Clear search & filters",
|
||||||
|
"useCasesTitle": "Use cases",
|
||||||
|
"goodForTitle": "Good for"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -796,5 +816,280 @@
|
|||||||
"new": "New",
|
"new": "New",
|
||||||
"editorsChoice": "Editor's Choice",
|
"editorsChoice": "Editor's Choice",
|
||||||
"empty": "No tools on this board yet."
|
"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..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,12 +53,29 @@
|
|||||||
"linkedin": "领英",
|
"linkedin": "领英",
|
||||||
"github": "GitHub"
|
"github": "GitHub"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"site": {
|
||||||
|
"items": [
|
||||||
|
"文章",
|
||||||
|
"指南",
|
||||||
|
"最佳推荐",
|
||||||
|
"目录",
|
||||||
|
"排行榜",
|
||||||
|
"提交"
|
||||||
|
],
|
||||||
|
"hrefs": [
|
||||||
|
"/blog",
|
||||||
|
"/ai-tools-for",
|
||||||
|
"/best",
|
||||||
|
"/tools",
|
||||||
|
"/rankings",
|
||||||
|
"/submit"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"hero": {
|
"hero": {
|
||||||
"badge": "发现最好的 AI 工具",
|
"title": "AI 工具,评测与排名",
|
||||||
"title": "The AI Ledger — AI 工具评测与排名",
|
"description": "指南、对比,以及由社区驱动的最佳 AI 工具目录。",
|
||||||
"description": "独立 AI 媒体:深度指南、横向对比,以及由社区排名的 AI 工具目录。",
|
|
||||||
"cta": {
|
"cta": {
|
||||||
"primary": "探索工具",
|
"primary": "探索工具",
|
||||||
"secondary": "阅读博客"
|
"secondary": "阅读博客"
|
||||||
@@ -657,7 +674,9 @@
|
|||||||
"latest": "最新",
|
"latest": "最新",
|
||||||
"trending": "最热"
|
"trending": "最热"
|
||||||
},
|
},
|
||||||
"clearFilters": "清除搜索与筛选"
|
"clearFilters": "清除搜索与筛选",
|
||||||
|
"useCasesTitle": "使用场景",
|
||||||
|
"goodForTitle": "适合人群"
|
||||||
},
|
},
|
||||||
"seo": {
|
"seo": {
|
||||||
"home": {
|
"home": {
|
||||||
@@ -804,5 +823,280 @@
|
|||||||
"new": "最新收录",
|
"new": "最新收录",
|
||||||
"editorsChoice": "编辑精选",
|
"editorsChoice": "编辑精选",
|
||||||
"empty": "该榜单暂无工具。"
|
"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": "搜索目录..."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
// 自动生成:[locale]/not-found.tsx 的薄路由
|
||||||
|
export { default } from "@aidir/core/pages/[locale]/not-found";
|
||||||
@@ -6,13 +6,25 @@ import { locales, defaultLocale, type Locale } from "@aidir/core/i18n.config";
|
|||||||
const brandMessages = {
|
const brandMessages = {
|
||||||
en: {
|
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"} },
|
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." } },
|
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: {
|
zh: {
|
||||||
seo: { home: {"title":"The AI Ledger — AI 工具评测与排名","description":"独立 AI 媒体:深度指南、横向对比,以及由社区排名的 AI 工具目录。","ogImage":"/og-image.png"} },
|
seo: { home: {"title":"The AI Ledger — AI 工具评测与排名","description":"独立 AI 媒体:深度指南、横向对比,以及由社区排名的 AI 工具目录。","ogImage":"/og-image.png"} },
|
||||||
hero: { title: "The AI Ledger — AI 工具评测与排名", description: "独立 AI 媒体:深度指南、横向对比,以及由社区排名的 AI 工具目录。" },
|
hero: { title: "AI 工具,评测与排名", description: "指南、对比,以及由社区驱动的最佳 AI 工具目录。" },
|
||||||
common: { brand: { name: "The AI Ledger", tagline: "Independent journalism on AI tools, with a community-ranked directory." } },
|
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;
|
} as const;
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,26 @@ import type { SiteConfig } from "@/kit/types";
|
|||||||
|
|
||||||
// The AI Ledger —— 独立站点的全部品牌/导航/页脚配置
|
// The AI Ledger —— 独立站点的全部品牌/导航/页脚配置
|
||||||
export const siteConfig: SiteConfig = {
|
export const siteConfig: SiteConfig = {
|
||||||
|
"brandZh": {
|
||||||
|
"name": "The AI Ledger",
|
||||||
|
"tagline": "独立 AI 报道,附社区排名目录。",
|
||||||
|
"headline": "AI 工具,评测与排名",
|
||||||
|
"subheadline": "指南、对比,以及由社区驱动的最佳 AI 工具目录。",
|
||||||
|
"nav": [
|
||||||
|
"文章",
|
||||||
|
"指南",
|
||||||
|
"最佳推荐",
|
||||||
|
"目录",
|
||||||
|
"排行榜",
|
||||||
|
"提交"
|
||||||
|
],
|
||||||
|
"footer": [
|
||||||
|
"阅读",
|
||||||
|
"目录",
|
||||||
|
"公司"
|
||||||
|
],
|
||||||
|
"searchPlaceholder": "搜索目录..."
|
||||||
|
},
|
||||||
"accent": "36 70% 40%",
|
"accent": "36 70% 40%",
|
||||||
"port": 3003,
|
"port": 3003,
|
||||||
"brand": {
|
"brand": {
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// 自动生成:站点首页组件(源自底座 editorial 形态,品牌来自 @/site/brand)
|
// 自动生成:站点首页组件(源自底座 editorial 形态,品牌来自 @/site/brand)
|
||||||
import { siteConfig } from "@/site/brand";
|
import { siteConfig } from "@/site/brand";
|
||||||
import { BookOpen, PenTool, ArrowRight, Star } from "lucide-react";
|
import { BookOpen, PenTool, ArrowRight, Star } from "lucide-react";
|
||||||
|
import { getTranslations } from "next-intl/server";
|
||||||
import { LocaleLink } from "@/components/locale-link";
|
import { LocaleLink } from "@/components/locale-link";
|
||||||
import { SectionHeader } from "@/kit/section";
|
import { SectionHeader } from "@/kit/section";
|
||||||
import { getHomeDataSafe } from "@/kit/home-data";
|
import { getHomeDataSafe } from "@/kit/home-data";
|
||||||
@@ -45,6 +46,8 @@ const footerGroups = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
async function SiteHome({ locale }: { locale: string }) {
|
async function SiteHome({ locale }: { locale: string }) {
|
||||||
|
const t = await getTranslations("siteHome");
|
||||||
|
const th = await getTranslations("hero");
|
||||||
const data = await getHomeDataSafe(6);
|
const data = await getHomeDataSafe(6);
|
||||||
const featured = data.articles[0];
|
const featured = data.articles[0];
|
||||||
const editorPicks = data.editorsChoice.slice(0, 4);
|
const editorPicks = data.editorsChoice.slice(0, 4);
|
||||||
@@ -55,13 +58,13 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
<section className="border-b border-border">
|
<section className="border-b border-border">
|
||||||
<div className="mx-auto max-w-4xl px-4 py-16 text-center sm:px-6 md:py-20">
|
<div className="mx-auto max-w-4xl px-4 py-16 text-center sm:px-6 md:py-20">
|
||||||
<p className="text-xs font-medium uppercase tracking-[0.3em] text-muted-foreground">
|
<p className="text-xs font-medium uppercase tracking-[0.3em] text-muted-foreground">
|
||||||
Independent AI Coverage
|
{t("mastheadLabel")}
|
||||||
</p>
|
</p>
|
||||||
<h1 className="mt-4 text-4xl font-bold tracking-tight text-foreground md:text-5xl">
|
<h1 className="mt-4 text-4xl font-bold tracking-tight text-foreground md:text-5xl">
|
||||||
{siteConfig.brand.headline}
|
{th("title")}
|
||||||
</h1>
|
</h1>
|
||||||
<p className="mx-auto mt-4 max-w-xl text-base leading-relaxed text-muted-foreground">
|
<p className="mx-auto mt-4 max-w-xl text-base leading-relaxed text-muted-foreground">
|
||||||
{siteConfig.brand.subheadline}
|
{th("description")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@@ -72,7 +75,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
<section>
|
<section>
|
||||||
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
||||||
<BookOpen className="h-3.5 w-3.5" />
|
<BookOpen className="h-3.5 w-3.5" />
|
||||||
Featured story
|
{t("featuredLabel")}
|
||||||
</div>
|
</div>
|
||||||
<LocaleLink href={`/blog/${featured.slug}`} className="group block">
|
<LocaleLink href={`/blog/${featured.slug}`} className="group block">
|
||||||
<h2 className="text-2xl font-bold leading-snug text-foreground group-hover:underline md:text-3xl">
|
<h2 className="text-2xl font-bold leading-snug text-foreground group-hover:underline md:text-3xl">
|
||||||
@@ -84,7 +87,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
<span className="mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary">
|
<span className="mt-3 inline-flex items-center gap-1 text-sm font-medium text-primary">
|
||||||
Read the story
|
{t("featuredRead")}
|
||||||
<ArrowRight className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" />
|
<ArrowRight className="h-3.5 w-3.5 transition-transform group-hover:translate-x-0.5" />
|
||||||
</span>
|
</span>
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
@@ -96,7 +99,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
<section>
|
<section>
|
||||||
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
<div className="mb-4 flex items-center gap-2 text-xs font-semibold uppercase tracking-widest text-primary">
|
||||||
<PenTool className="h-3.5 w-3.5" />
|
<PenTool className="h-3.5 w-3.5" />
|
||||||
Editor's picks
|
{t("picksEditorialLabel")}
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-border border-y border-border">
|
<div className="divide-y divide-border border-y border-border">
|
||||||
{editorPicks.map((tool, i) => (
|
{editorPicks.map((tool, i) => (
|
||||||
@@ -132,10 +135,10 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.collections.length > 0 && (
|
{data.collections.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="Buying guides"
|
title={t("guidesTitle")}
|
||||||
subtitle="Deep dives that help you choose"
|
subtitle={t("guidesSubtitle")}
|
||||||
viewAllHref="/best"
|
viewAllHref="/best"
|
||||||
viewAllLabel="All guides"
|
viewAllLabel={t("guidesViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-6 sm:grid-cols-2">
|
<div className="grid gap-6 sm:grid-cols-2">
|
||||||
{data.collections.slice(0, 4).map((col) => (
|
{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}
|
{locale === "zh" && col.introZh ? col.introZh : col.introEn}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-2 text-xs uppercase tracking-wide text-muted-foreground">
|
<p className="mt-2 text-xs uppercase tracking-wide text-muted-foreground">
|
||||||
{col.toolCount} tools compared
|
{col.toolCount} {t("toolsCompared")}
|
||||||
</p>
|
</p>
|
||||||
</LocaleLink>
|
</LocaleLink>
|
||||||
))}
|
))}
|
||||||
@@ -162,7 +165,7 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{/* Latest articles */}
|
{/* Latest articles */}
|
||||||
{data.articles.length > 1 && (
|
{data.articles.length > 1 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader title="Latest stories" viewAllHref="/blog" />
|
<SectionHeader title={t("storiesTitle")} viewAllHref="/blog" />
|
||||||
<div className="grid gap-6 sm:grid-cols-2">
|
<div className="grid gap-6 sm:grid-cols-2">
|
||||||
{data.articles.slice(1).map((article) => (
|
{data.articles.slice(1).map((article) => (
|
||||||
<LocaleLink key={article.slug} href={`/blog/${article.slug}`} className="group">
|
<LocaleLink key={article.slug} href={`/blog/${article.slug}`} className="group">
|
||||||
@@ -184,9 +187,9 @@ async function SiteHome({ locale }: { locale: string }) {
|
|||||||
{data.latestReviews.length > 0 && (
|
{data.latestReviews.length > 0 && (
|
||||||
<section>
|
<section>
|
||||||
<SectionHeader
|
<SectionHeader
|
||||||
title="From the community"
|
title={t("communityTitle")}
|
||||||
viewAllHref="/tools"
|
viewAllHref="/tools"
|
||||||
viewAllLabel="Browse directory"
|
viewAllLabel={t("communityViewAll")}
|
||||||
/>
|
/>
|
||||||
<div className="grid gap-6 sm:grid-cols-2">
|
<div className="grid gap-6 sm:grid-cols-2">
|
||||||
{data.latestReviews.slice(0, 4).map((review, i) => (
|
{data.latestReviews.slice(0, 4).map((review, i) => (
|
||||||
|
|||||||
Reference in New Issue
Block a user