Skip to content

Commit 1e99a31

Browse files
chore(seo): redirects 单跳 + root metadata hreflang,i18n 段化收尾
i18n PR (#330) 之后存在两个 SEO 残留问题,本 PR 一并修: 1. next.config.mjs redirects 全部 destination 加 /zh/ 前缀 现状:destination 都是 /docs/...(不带 locale),用户访问老 URL 流程: /docs/CommunityShare/RAG/rag → 301 /docs/learn/ai/foundation-models/rag/rag → 308 /zh/docs/learn/ai/foundation-models/rag/rag (next-intl middleware) 两跳 redirect 对 SEO PageRank 不友好(Google 推荐单跳)。把 destination 直接指向带 /zh/ 前缀的 canonical URL,搜索引擎单跳到位。 改 46 条规则的 destination,source 保持不带 locale(匹配老外链)。 英语用户由站内 <LocaleToggle /> 切到 /en/...,cookie 同步偏好。 2. root layout metadata hreflang alternates.canonical 之前写死 /,i18n 段化后根路径会被 middleware redirect,搜索引擎拿到的 canonical 是个 redirect 目标,不准。 改为: - canonical: /zh(默认 locale 首页) - languages: zh-CN / en-US / x-default 三向声明 注:每个具体 [locale]/page 的 generateMetadata 会覆盖 root metadata 的 languages,给到该 page 各 locale 的具体 URL。这里 root 只作 fallback。
1 parent 8c0fc06 commit 1e99a31

2 files changed

Lines changed: 52 additions & 35 deletions

File tree

app/layout.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,18 @@ export const metadata: Metadata = {
5353
creator: "longsizhuo",
5454
publisher: "Involution Hell",
5555
category: "Technology",
56+
// alternates 是 fallback,被 [locale] 段下的 generateMetadata 覆盖。
57+
// 默认 canonical 指 /zh(默认 locale 首页),不指 / 因为根路径会被
58+
// next-intl middleware 308 redirect,搜索引擎索引到 /zh 更直接。
59+
// languages 同时声明 hreflang,让 root metadata 应用到不在 [locale]
60+
// 下的路径(如 /sitemap.xml 详情页 fallback 时)也能正确给出语言关系。
5661
alternates: {
57-
canonical: "/",
62+
canonical: "/zh",
63+
languages: {
64+
"zh-CN": "/zh",
65+
"en-US": "/en",
66+
"x-default": "/zh",
67+
},
5868
},
5969
robots: {
6070
index: true,

next.config.mjs

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -37,154 +37,161 @@ const config = {
3737
async redirects() {
3838
// Option C IA 大重组:按读者意图分 learn / career / community / projects 四大顶层区。
3939
// 顺序敏感——Next.js 首匹配命中,特殊文件级 + cpp_backend 老名字必须排在 wildcard 前。
40+
//
41+
// 2026-05 i18n URL 段化(PR #330):所有 destination 都带 /zh/ 前缀
42+
// (默认 locale)。不带前缀的话会先 301 到 /docs/...,next-intl
43+
// middleware 再 308 到 /zh/docs/...,对 SEO 是两跳 redirect。直接
44+
// destination 写带前缀的 canonical URL 让搜索引擎和用户都单跳到位。
45+
// 英语用户由站内 <LocaleToggle /> 切到 /en/docs/...,cookie 同步偏好。
46+
// source 保持不带 locale 形式(匹配老 URL)。
4047
return [
4148
// ============= 特殊路径(必须在 wildcard 之前) =============
4249
// CommunityShare/RAG → learn/ai/foundation-models/rag (RAG 文件归 ai 主题)
4350
{
4451
source: "/docs/CommunityShare/RAG/rag",
45-
destination: "/docs/learn/ai/foundation-models/rag/rag",
52+
destination: "/zh/docs/learn/ai/foundation-models/rag/rag",
4653
statusCode: 301,
4754
},
4855
{
4956
source: "/docs/CommunityShare/RAG/embedding",
50-
destination: "/docs/learn/ai/foundation-models/rag/embedding",
57+
destination: "/zh/docs/learn/ai/foundation-models/rag/embedding",
5158
statusCode: 301,
5259
},
5360
{
5461
// 文件名顺手规范化:context_engineering_intro → context-engineering-intro
5562
source: "/docs/CommunityShare/RAG/context_engineering_intro",
5663
destination:
57-
"/docs/learn/ai/foundation-models/rag/context-engineering-intro",
64+
"/zh/docs/learn/ai/foundation-models/rag/context-engineering-intro",
5865
statusCode: 301,
5966
},
6067
// CommunityShare/Geek/leworldmodel → community/papers(paper summary 归社区论文)
6168
{
6269
source: "/docs/CommunityShare/Geek/leworldmodel",
63-
destination: "/docs/community/papers/leworldmodel",
70+
destination: "/zh/docs/community/papers/leworldmodel",
6471
statusCode: 301,
6572
},
6673
// CommunityShare/Amazing-AI-Tools 下两篇分家:tool review 归 tools,paper 归 papers
6774
{
6875
source: "/docs/CommunityShare/Amazing-AI-Tools/perplexity-comet",
69-
destination: "/docs/community/tools/perplexity-comet",
76+
destination: "/zh/docs/community/tools/perplexity-comet",
7077
statusCode: 301,
7178
},
7279
{
7380
source:
74-
"/docs/CommunityShare/Amazing-AI-Tools/prompt-repetition-improves-non-reasoning-llms",
81+
"/zh/docs/CommunityShare/Amazing-AI-Tools/prompt-repetition-improves-non-reasoning-llms",
7582
destination:
76-
"/docs/community/papers/prompt-repetition-improves-non-reasoning-llms",
83+
"/zh/docs/community/papers/prompt-repetition-improves-non-reasoning-llms",
7784
statusCode: 301,
7885
},
7986
// PPO 强化学习主题 → learn/ai/reinforcement-learning
8087
{
8188
source:
82-
"/docs/CommunityShare/Personal-Study-Notes/Reinforcement-Learning/ppo",
83-
destination: "/docs/learn/ai/reinforcement-learning/ppo",
89+
"/zh/docs/CommunityShare/Personal-Study-Notes/Reinforcement-Learning/ppo",
90+
destination: "/zh/docs/learn/ai/reinforcement-learning/ppo",
8491
statusCode: 301,
8592
},
8693
// swanlab 之前 test run 已移到 ai/misc-tools/(main commit d6d0a3d),现改到 community/tools
8794
{
8895
source: "/docs/ai/misc-tools/swanlab",
89-
destination: "/docs/community/tools/swanlab",
96+
destination: "/zh/docs/community/tools/swanlab",
9097
statusCode: 301,
9198
},
9299
// cpp_backend 老命名(下划线 / 大驼峰)→ learn/cs/cpp-backend/ (kebab-case)
93100
{
94101
source: "/docs/computer-science/cpp_backend/mempool_simple",
95-
destination: "/docs/learn/cs/cpp-backend/mempool-simple",
102+
destination: "/zh/docs/learn/cs/cpp-backend/mempool-simple",
96103
statusCode: 301,
97104
},
98105
{
99106
source:
100-
"/docs/computer-science/cpp_backend/Handwritten_pool_components/1_Handwritten_threadpool",
107+
"/zh/docs/computer-science/cpp_backend/Handwritten_pool_components/1_Handwritten_threadpool",
101108
destination:
102-
"/docs/learn/cs/cpp-backend/handwritten-pool-components/1-handwritten-threadpool",
109+
"/zh/docs/learn/cs/cpp-backend/handwritten-pool-components/1-handwritten-threadpool",
103110
statusCode: 301,
104111
},
105112
{
106113
source:
107-
"/docs/computer-science/cpp_backend/Handwritten_pool_components/2_Handwritten_mempool1",
114+
"/zh/docs/computer-science/cpp_backend/Handwritten_pool_components/2_Handwritten_mempool1",
108115
destination:
109-
"/docs/learn/cs/cpp-backend/handwritten-pool-components/2-handwritten-mempool1",
116+
"/zh/docs/learn/cs/cpp-backend/handwritten-pool-components/2-handwritten-mempool1",
110117
statusCode: 301,
111118
},
112119
{
113120
source: "/docs/computer-science/cpp_backend/easy_compile/1_cpp_libs",
114-
destination: "/docs/learn/cs/cpp-backend/easy-compile/1-cpp-libs",
121+
destination: "/zh/docs/learn/cs/cpp-backend/easy-compile/1-cpp-libs",
115122
statusCode: 301,
116123
},
117124
{
118125
source: "/docs/computer-science/cpp_backend/easy_compile/2_base_gcc",
119-
destination: "/docs/learn/cs/cpp-backend/easy-compile/2-base-gcc",
126+
destination: "/zh/docs/learn/cs/cpp-backend/easy-compile/2-base-gcc",
120127
statusCode: 301,
121128
},
122129
{
123130
source: "/docs/computer-science/cpp_backend/easy_compile/3_Make",
124-
destination: "/docs/learn/cs/cpp-backend/easy-compile/3-make",
131+
destination: "/zh/docs/learn/cs/cpp-backend/easy-compile/3-make",
125132
statusCode: 301,
126133
},
127134
{
128135
source: "/docs/computer-science/cpp_backend/easy_compile/4_CMake",
129-
destination: "/docs/learn/cs/cpp-backend/easy-compile/4-cmake",
136+
destination: "/zh/docs/learn/cs/cpp-backend/easy-compile/4-cmake",
130137
statusCode: 301,
131138
},
132139
{
133140
source: "/docs/computer-science/cpp_backend/easy_compile/5_vcpkg",
134-
destination: "/docs/learn/cs/cpp-backend/easy-compile/5-vcpkg",
141+
destination: "/zh/docs/learn/cs/cpp-backend/easy-compile/5-vcpkg",
135142
statusCode: 301,
136143
},
137144
// all-projects/ai-town → projects/ai-town (顶层化)
138145
{
139146
source: "/docs/all-projects/ai-town",
140-
destination: "/docs/projects/ai-town",
147+
destination: "/zh/docs/projects/ai-town",
141148
statusCode: 301,
142149
},
143150
// all-projects 裸路径本身也要兜底,防止指 /docs/all-projects 直接 404
144151
{
145152
source: "/docs/all-projects",
146-
destination: "/docs/projects",
153+
destination: "/zh/docs/projects",
147154
statusCode: 301,
148155
},
149156
// CommunityShare / Amazing-AI-Tools index 顶层
150157
{
151158
source: "/docs/CommunityShare",
152-
destination: "/docs/community",
159+
destination: "/zh/docs/community",
153160
statusCode: 301,
154161
},
155162
{
156163
source: "/docs/CommunityShare/Amazing-AI-Tools",
157-
destination: "/docs/community/tools",
164+
destination: "/zh/docs/community/tools",
158165
statusCode: 301,
159166
},
160167

161168
// ============= Wildcard 顶层区重命名 =============
162169
// 学科主目录:ai → learn/ai, computer-science → learn/cs
163170
{
164171
source: "/docs/ai/:path*",
165-
destination: "/docs/learn/ai/:path*",
172+
destination: "/zh/docs/learn/ai/:path*",
166173
statusCode: 301,
167174
},
168175
{
169176
source: "/docs/computer-science/:path*",
170-
destination: "/docs/learn/cs/:path*",
177+
destination: "/zh/docs/learn/cs/:path*",
171178
statusCode: 301,
172179
},
173180
// 求职场景 jobs/{interview-prep,event-keynote} → career/{interview-prep,events}
174181
{
175182
source: "/docs/jobs/interview-prep/:path*",
176-
destination: "/docs/career/interview-prep/:path*",
183+
destination: "/zh/docs/career/interview-prep/:path*",
177184
statusCode: 301,
178185
},
179186
{
180187
source: "/docs/jobs/event-keynote/:path*",
181-
destination: "/docs/career/events/:path*",
188+
destination: "/zh/docs/career/events/:path*",
182189
statusCode: 301,
183190
},
184191
// 项目 all-projects → projects
185192
{
186193
source: "/docs/all-projects/:path*",
187-
destination: "/docs/projects/:path*",
194+
destination: "/zh/docs/projects/:path*",
188195
statusCode: 301,
189196
},
190197
// CommunityShare 分家:其他按主题归 community/*
@@ -193,27 +200,27 @@ const config = {
193200
// 生成的 slug 映射做字面匹配,单跳 301 到正确拼音 URL。
194201
{
195202
source: "/docs/CommunityShare/Language/:path*",
196-
destination: "/docs/community/language/:path*",
203+
destination: "/zh/docs/community/language/:path*",
197204
statusCode: 301,
198205
},
199206
{
200207
source: "/docs/CommunityShare/Life/:path*",
201-
destination: "/docs/community/life/:path*",
208+
destination: "/zh/docs/community/life/:path*",
202209
statusCode: 301,
203210
},
204211
{
205212
source: "/docs/CommunityShare/MentalHealth/:path*",
206-
destination: "/docs/community/mental-health/:path*",
213+
destination: "/zh/docs/community/mental-health/:path*",
207214
statusCode: 301,
208215
},
209216
{
210217
source: "/docs/CommunityShare/Geek/:path*",
211-
destination: "/docs/community/dev-tips/:path*",
218+
destination: "/zh/docs/community/dev-tips/:path*",
212219
statusCode: 301,
213220
},
214221
{
215222
source: "/docs/CommunityShare/Amazing-AI-Tools/:path*",
216-
destination: "/docs/community/tools/:path*",
223+
destination: "/zh/docs/community/tools/:path*",
217224
statusCode: 301,
218225
},
219226
];

0 commit comments

Comments
 (0)