feat: i18n 双语系统 + 150 篇文档翻译 + Hero UX 迭代#281
Merged
longsizhuo merged 20 commits intomainfrom Apr 15, 2026
Merged
Conversation
fumadocs 的 page.file.path 返回相对 app/docs/ 的路径(如 ai/xxx/index.mdx) 而不是仓库根路径,导致前端调 /api/docs/history 时报 400。 在 normalizeDocsPath 里补上 app/docs/ 前缀兼容。
- DocShareButton: 去掉 rounded-md / h-11,改为 font-mono uppercase + border + 翻转色 hover - EditOnGithub: 同步改为相同风格,图标 h-8→h-4 - DocHistoryPanel: 骨架屏和头像去掉 rounded-full,保持方角报纸风 - ContributorRow: Dialog 硬编码 #111111/#F9F9F7 换成 CSS 变量;POWER LEVEL 标签移动端隐藏 - HotDocsTab: 加 sessionStorage 5 分钟缓存,减少重复打后端 - SettingsForm: AI 提供商从原生 select 改为 segment button group;中文 label 去掉 uppercase tracking-widest
问题:
- fumadocs 的 RootProvider 内置 next-themes,与自己的 ThemeProvider
同时往 <html class> 写 light/dark,导致进入 /settings 时从黑闪白
- Header 右上角 ThemeToggle 切换主题后,/settings 表单选中态不更新
- Settings 保存时的语言设置写不到文档页能读到的位置
修复:
- RootProvider 加 theme={{ enabled: false }},禁用 fumadocs 内置主题
- SettingsForm 用 useTheme() 读当前主题作为初始值
- 监听 currentTheme 变化,同步到表单选中态
- 切主题按钮立即 setTheme(所见即所得,不用等保存)
- handleSave 保存成功后把 language 写 cookie,供 /docs Server Component 读
- BrandMark 外层包 <Link href="/">,点 logo 回首页 - Header 三个锚点从 #features 改为 /#features 等绝对路径, 从 /rank 或任意子页点导航能跳回主页对应区块 方案 F(最小修复),比引入 Header 全站 layout 或新组件成本更低。
- 新建 middleware.ts:首次访问 /docs 时根据 IP geo / Accept-Language 判断默认 locale,写入 cookie;默认 zh(社区主体语言) - [...slug]/page.tsx: 从 cookie 读 locale,尝试加载 slug.en.mdx / slug.zh.mdx 翻译版,不存在时静默 fallback 到原文(不展示碍眼横幅) - docs-i18n-design.md: 完整双语化设计方案(frontmatter 约定、 contributors 脚本改造、翻译流程、术语词表方向)
- 新建 HotDocsPreview.tsx(async Server Component + ISR 300s) fetch 自家 /api/analytics/top-docs?window=7d&limit=5, 后端或数据挂掉时静默降级,不影响首页其他模块 - 新建 app/api/analytics/top-docs/route.ts:从 analyticsEvent 表 按 eventData.path 聚合 7d 阅读量,供前端 SSR 使用 - Hero.tsx Leaderboard 区域改 12 列 grid: 贡献者 Top3 (lg:col-span-8) / 热门文档 Top5 (lg:col-span-4) SEO 价值:首页 HTML 中包含 5 条热门文章标题+链接,Google 爬虫 可直接建立首页 → 文章的链接关系,帮助长尾关键词索引。
翻译版文件 frontmatter 有 translatedFrom 字段,这类文件由 AI 产出、不应污染 contributor 统计。 在 parseDocFrontmatter 新增 isTranslation 字段,主循环里 检测到翻译版则打印跳过日志并 continue,不拉 commit 历史、 不写入 doc_contributors 表。 影响:generate-leaderboard.mjs 无需改动(它从 DB 聚合, 源头已过滤),DB schema 不变。
覆盖不同场景的 MVP 样本,用于验证翻译 agent 的能力边界: - ai/reinforcement-learning-overview (zh→en) — AI 术语密集 - ai/compute-platforms-handbook (zh→en) — 代码块保留 - computer-science/01-singly-linked-list (en→zh) — 长文 + ASCII 图 - jobs/bq (zh→en) — 文化语境 / STAR / BQ 行话 - CommunityShare/Geek/cloudflare-r2-sharex (zh→en) — 表格 + 中文 URL 编码 每份翻译版: - 继承原文 docId(共享同一文档的版本) - frontmatter 有 translatedFrom/translatedAt 标记,contributors 脚本会跳过 - 代码块 / math / URL / MDX 属性名原样保留 - 仅翻译 title、description、正文文本与 MDX 文本内容 MVP 5 篇总 token ~29.4k,平均 5.9k/篇。
translator-community 产出。双向翻译: - Geek: git101 / picturecdn / swanlab / raspberry-guide / CommonUsedMarkdown / Katex×2 (全部 zh→en),leworldmodel (en→zh) - RAG: context_engineering_intro / embedding / rag (全部 zh→en) - Amazing-AI-Tools: perplexity-comet (zh→en), prompt-repetition-improves-non-reasoning-llms (en→zh) 跳过:3 个 <Cards> 索引页、1 个 MVP 已翻译文件。 所有翻译版 frontmatter 继承原文 docId,带 translatedFrom 标记 供 contributors 脚本跳过统计。
translator-ai-1 产出。全部 zh→en。覆盖: - Introduction-of-Multi-agents-system (1) - MoE (2) - Multi-agents-system-on-Code-Translation (1) - agents-todo (2) - ai-math-basics (9) — 含 calculus / linear-algebra / probability 等子目录 - compute-platforms (1,handbook 已在 MVP 提交) - foundation-models (7) — lifecycle / datasets / training / finetune 等 - generative-todo (1) 所有翻译版 frontmatter 继承原文 docId,带 translatedFrom: zh 标记供 contributors 脚本跳过统计。
translator-cs-jobs 产出: - computer-science: 双向翻译 - data-structures (en→zh, 5 篇): index / array / linked-list - frontend (zh→en, 2 篇) - cpp_backend (zh→en, 8 篇): mempool / threadpool / 编译系列 - index.mdx (zh→en) - jobs (zh→en, 5 篇): event-keynote 2 / interview-prep 3 - all-projects (zh→en, 2 篇): ai-town / multimodal-rl 代码块内变量名和 API 原样保留,仅翻译注释。 frontmatter 继承原文 docId,带 translatedFrom 标记。
translator-leetcode 产出。Leetcode 题解目录特殊处理: - 原文件名含方括号/中文/空格/_translated 后缀,命名风格混乱 - 翻译版统一改为 kebab-case 英文 slug: [146]LRU 缓存_translated.md → 146-lru-cache.en.md [121]买卖股票的最佳时期_translated.md → 121-best-time-to-buy-and-sell-stock.en.md 双向翻译: - zh→en: 35 篇(绝大多数原文是中文题解) - en→zh: 7 篇(2241 ATM / 2270 Split Array / 3138 Anagram / 46 全排列 / 9021 TUT / 93 IP / Counting Stars / 等英文原文) 代码块(Python/C++/Java)原样保留,仅译注释。LaTeX 公式保留。 frontmatter 继承原文 docId,带 translatedFrom 标记。 跳过:1 个 <Cards> 索引页。
translator-ai-2 产出 + MDX 语法修复。全部 zh→en。 覆盖: - llm-basics (12 篇): courses / cuda / deep-learning / embeddings / pytorch / transformer - methodology (1) - misc-tools (1) - model-datasets-platforms (1) - multimodal (10): courses / llava / mllm / qwenvl / ViT / VAE / VQVAE / RQVAE 等 - recommender-systems (7): 王树森推荐系统笔记全集(粗排/精排/重排/冷启动等) MDX 语法修复: - 2 个 recommender-systems 文件的裸 <1000 / <30 / <24 / <8 用反引号包裹 (MDX 把 <digit 当成 JSX tag 开头导致 build 失败) - app/api/analytics/top-docs/route.ts: Prisma JSON filter startsWith 写法错误,改为内存筛选 术语决策(新发现): - 笔记 → post (Xiaohongshu 场景) - 粗排/精排/重排 → pre-ranking / full ranking / re-ranking - 保量 → exposure guarantee - 融合分数 → fused score - 老汤模型 → aged model (inline explanation)
- wangshusen_recommend_note_improvement.en.mdx: 补 H1 - wangshusen_recommend_note_retrieval.en.mdx: H5 → H4 - leworldmodel.md / 1545-...en.md: 小修 - generated/site-leaderboard.json: 自动更新
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
修 CI lint error: @next/next/no-html-link-for-pages
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a cookie-based bilingual (zh/en) docs experience with auto-detection, adds a large batch of translated documentation, and iterates the homepage Hero + ranking UX by adding “Hot Docs” surfacing and analytics support.
Changes:
- Add locale auto-detection middleware + cookie-based docs locale selection with silent fallback to original docs.
- Add Top Docs surfacing: Hero “Hot This Week” preview +
/rankHot Docs tab client caching, plus a new Next API route for top-docs with ISR. - Update contributor backfill script to skip translated docs based on
translatedFromfrontmatter; add/adjust many translated docs and minor UX component styling tweaks.
Reviewed changes
Copilot reviewed 157 out of 158 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/backfill-contributors.mjs | Skip translation variants (frontmatter translatedFrom) when building contributor stats. |
| middleware.ts | New middleware to set default locale cookie based on geo + Accept-Language (docs-only matcher). |
| app/docs/[...slug]/page.tsx | Load translated doc variant based on locale cookie by appending .en/.zh suffix to last slug segment; silent fallback to original. |
| app/layout.tsx | Disable fumadocs built-in theming to avoid next-themes conflicts / flicker. |
| app/api/docs/history/route.ts | Normalize fumadocs relative doc paths to repo-root app/docs/... for history lookups. |
| app/api/analytics/top-docs/route.ts | New ISR endpoint for top docs based on analytics events in Prisma. |
| app/components/rank/HotDocsTab.tsx | Add sessionStorage TTL cache to avoid repeat fetches within a session. |
| app/components/HotDocsPreview.tsx | New Hero-side “Hot This Week” preview panel fetching top docs. |
| app/components/Hero.tsx | Restructure Hero layout into 12-col grid and include HotDocsPreview. |
| app/components/Header.tsx | Convert in-page anchors to absolute /#... to work from nested routes. |
| app/components/BrandMark.tsx | Make BrandMark clickable (Link to /) to fix navigation from nested routes like /rank. |
| app/components/EditOnGithub.tsx | Style/size adjustments for the edit button to match refreshed UX. |
| app/components/DocShareButton.tsx | Style updates for share button to match refreshed UX. |
| app/components/DocHistoryPanel.tsx | Minor UI consistency tweaks (avatar/skeleton rounding, hover container). |
| app/docs/computer-science/index.en.mdx | Add translated doc (note: currently contains mixed EN+ZH content). |
| app/docs/** (many new/updated .en/.zh docs) | Large-scale doc translation additions across multiple directories with docId + translation frontmatter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export async function GET(req: NextRequest) { | ||
| const { searchParams } = new URL(req.url); | ||
| const window = searchParams.get("window") ?? "7d"; | ||
| const limit = Math.min(Number(searchParams.get("limit") ?? "5"), 20); |
Comment on lines
+30
to
+46
| // 统计各路径 PV(内存过滤 /docs/ 前缀) | ||
| const counts: Record<string, number> = {}; | ||
| for (const row of rows) { | ||
| const data = row.eventData as { path?: string; title?: string } | null; | ||
| const path = data?.path; | ||
| if (path && path.startsWith("/docs/")) { | ||
| counts[path] = (counts[path] ?? 0) + 1; | ||
| } | ||
| } | ||
|
|
||
| const top = Object.entries(counts) | ||
| .sort((a, b) => b[1] - a[1]) | ||
| .slice(0, limit) | ||
| .map(([path, views]) => ({ path, views })); | ||
|
|
||
| return Response.json(top); | ||
| } |
Comment on lines
+9
to
+20
| async function fetchTopDocs(): Promise<TopDocDto[]> { | ||
| const backendUrl = process.env.BACKEND_URL ?? "http://localhost:8081"; | ||
| try { | ||
| const res = await fetch( | ||
| `${backendUrl}/analytics/top-docs?window=7d&limit=5`, | ||
| { next: { revalidate: 300 } }, | ||
| ); | ||
| if (!res.ok) return []; | ||
| const json = await res.json(); | ||
| // 后端用 ApiResponse<List<TopDocDto>> 包裹,data 字段存实际数据 | ||
| return json.data ?? json; | ||
| } catch { |
Comment on lines
+22
to
+28
| const acceptLang = req.headers.get("accept-language") ?? ""; | ||
|
|
||
| // 默认中文;只有明确英文 Accept-Language 且非中国 IP 才切 en | ||
| const isExplicitlyEnglish = | ||
| !acceptLang.toLowerCase().startsWith("zh") && | ||
| acceptLang.toLowerCase().startsWith("en") && | ||
| country !== "CN"; |
- 新增 app/components/DispatchNetwork.tsx:48px 高报纸末版"发行网络"风格横条 - 内容:GitHub / Discord / Zotero 三个入口 + Join CTA - 移除 page.tsx 对 Features 和 Community 的引用 - 组件文件保留未删,后续可能复用;主页不再渲染 用户原因:Top Rank 之后的 Mission Statement 四格口号和 Community 三卡链接 完全 useless,和 Footer 重复劳动。方案三(极简 bar)被选中。
1. top-docs/route.ts: limit 参数加 Number.isFinite 校验防 NaN
2. top-docs/route.ts: 返回结构统一为 ApiResponse{success,data},补齐 title 字段
(通过 fumadocs source.getPage 回填,同时保留埋点带来的 title)
3. HotDocsPreview.tsx: 改走同源 /api/analytics/top-docs 走 ISR,
不再直连 BACKEND_URL,消除 '白做缓存' 问题
4. docs/[...slug]/page.tsx: generateMetadata 也按 locale 取页面,
避免英文页显示中文 title/description
5. middleware.ts: Accept-Language 解析改为按 q 值排序取首选语言,
正确处理 'fr-CA,fr;q=0.9,en;q=0.8' 这类多语言 header
6. computer-science/index.en.mdx: 删除正文末尾混入的整段中文
之前 150 篇中文 + 150 篇英文翻译全塞进同一个 /search.json, 构建产物 23MB 触发 FALLBACK_BODY_TOO_LARGE 导致 Vercel 部署失败。 方案: - 新增 lib/search-index.ts 抽出 pageToIndex 和 isEnglishPage 工具 - /search.zh.json — 中文 / 无语言标的原文 + lang="zh" 翻译版(约 13MB) - /search.en.json — 仅 lang="en" 翻译版,用 Orama 英文分词(约 11MB) - layout.tsx 读 locale cookie 动态选 API(默认 zh) - createSearchAPI 的 indexes 必须是 Dynamic<T>=()=>T[]|Promise<T[]>,不是裸 Promise 下一步扩容:文档数量继续增长可按目录再切片(ai/cs/leetcode 各自独立 json)。
Vercel Fluid CPU 用到 85%,原因是前端 /api/analytics 每次埋点都跑 Next function 做 resolveUserId + Prisma 直写。现改为走 next.config 已有的 /analytics/:path* rewrite 直转 Java,Vercel 只做 edge 代理不跑 function。 前端改动: - lib/analytics.ts: URL /api/analytics → /analytics/events,header x-satoken → satoken - 删除 app/api/analytics/route.ts(Prisma 直写逻辑搬到 Java) 配套后端改动(另开 PR): - AnalyticsController 加 POST /events - 新增 AnalyticsEventIngestService 用 JdbcTemplate INSERT - SaTokenConfigure 白名单放行 /analytics/events(匿名也收) AnalyticsEvent 表保留:GA4 走 top-docs,这张表暂无读取方但 未来自建 dashboard / 登录用户精细追踪可直接复用。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
docId+translatedFromfrontmatter 约定让 contributors 脚本跳过翻译版<digit当 JSX tag)Test plan