Files
FastGPT/document/LOCALIZED_NAVIGATION.md
T
Archer 2fd4b6030b feat(i18n): Fix language loss in navigation and add language selector (#6467)
* feat(docs): enable i18n language selector

* docs(i18n): translate introduction page to English

* fix(i18n): fix language switching issue by always showing locale prefix

* fix(docs): use relative paths for internal links to preserve language

* refactor(i18n): add getLocalizedPath helper to simplify URL generation

* refactor(i18n): make getLocalizedPath respect hideLocale config

* feat(i18n): fallback to default language when translation missing, keep URL unchanged

* feat(i18n): fix language loss in navigation and add language selector

- Set hideLocale to 'never' to always show language prefix
- Add localized-navigation.ts with useLocalizedRouter hook
- Update all navigation points to preserve language:
  1. Tab navigation (already using getLocalizedPath)
  2. Sidebar navigation (handled by Fumadocs)
  3. Home/404 redirects (using getLocalizedPath)
  4. MDX Redirect component (using useLocalizedRouter)
  5. Old page redirects (updated not-found.tsx)
  6. Document links (custom LocalizedLink component)
- Configure language selector in layout.config.tsx
- Add LOCALIZED_NAVIGATION.md documentation

* fix(i18n): fix type errors and useEffect dependencies

* refactor(i18n): move redirects to middleware for SSR support

- Move old path redirects from client-side (not-found.tsx) to server-side (middleware.ts)
- Use 301 permanent redirects for better SEO
- Preserve language prefix in redirects
- Fix SSR issue caused by client-side redirects

* refactor(i18n): clean up not-found.tsx, remove duplicate redirect maps

- Remove duplicate exactMap and prefixMap (now in middleware)
- Keep dynamic meta.json lookup for unknown pages
- Simplify to only handle fallback cases
- Two-layer approach: middleware (SSR) + not-found (dynamic)

* refactor(i18n): simplify not-found to always redirect to introduction

- Remove dynamic meta.json lookup
- Always redirect to introduction page on 404
- Ensures no 404 pages are shown
- Keep language prefix in redirect

* fix(i18n): fix middleware type error with ts-expect-error

- Add @ts-expect-error for Fumadocs middleware signature mismatch
- Fix syntax error in config matcher (remove literal \n)

---------

Co-authored-by: archer <archer@archerdeMac-mini.local>
2026-02-26 16:29:03 +08:00

108 lines
3.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 国际化路由适配说明
## 问题
路由跳转时语言前缀丢失,导致用户在切换页面后回到默认语言。
## 解决方案
### 1. 核心配置
- **`lib/i18n.ts`**: 设置 `hideLocale: 'never'`,确保所有语言(包括默认语言)都显示语言前缀
- **`lib/localized-navigation.ts`**: 提供客户端路由工具,自动处理语言前缀
### 2. 修复的路由跳转位置
#### ✅ 一级导航(Tab Navigation
- **文件**: `app/[lang]/docs/layout.tsx`
- **方法**: 使用 `getLocalizedPath()` 为每个 tab 的 URL 添加语言前缀
- **状态**: 已完成
#### ✅ 二级导航(Sidebar
- **文件**: `lib/source.ts`
- **方法**: Fumadocs 的 loader 自动根据 i18n 配置生成带语言前缀的链接
- **状态**: 已完成(无需修改)
#### ✅ 空页面重定向
- **文件**:
- `app/[lang]/(home)/page.tsx` - 首页重定向
- `app/[lang]/(home)/[...not-found]/page.tsx` - 404 重定向
- **方法**: 使用 `getLocalizedPath()` 添加语言前缀
- **状态**: 已完成
#### ✅ MDX 组件重定向
- **文件**: `components/docs/Redirect.tsx`
- **方法**: 使用 `useLocalizedRouter()` hook
- **状态**: 已完成
#### ✅ 旧页面重定向
- **文件**: `components/docs/not-found.tsx`
- **方法**:
- 使用 `useCurrentLang()` 获取当前语言
- 从 pathname 中移除语言前缀进行匹配
- 使用 `useLocalizedPath()` 为重定向目标添加语言前缀
- **状态**: 已完成
#### ✅ 文档内链接
- **文件**:
- `components/docs/LocalizedLink.tsx` - 自定义 Link 组件
- `mdx-components.tsx` - 配置 MDX 使用 LocalizedLink
- **方法**: 拦截 MDX 中的 `<a>` 标签,自动为内部链接添加语言前缀
- **状态**: 已完成
### 3. 语言选择器
- **文件**: `app/layout.config.tsx`
- **配置**:
```typescript
i18n: {
locale,
languages: [
{ name: '简体中文', locale: 'zh-CN' },
{ name: 'English', locale: 'en' }
],
hideLocale: 'never'
}
```
- **状态**: 已完成
## 使用方法
### 客户端组件
```tsx
'use client';
import { useLocalizedRouter } from '@/lib/localized-navigation';
function MyComponent() {
const router = useLocalizedRouter();
router.push('/docs/introduction'); // 自动添加语言前缀
}
```
### 服务端组件
```tsx
import { getLocalizedPath } from '@/lib/i18n';
import { redirect } from 'next/navigation';
export default async function Page({ params }: { params: Promise<{ lang: string }> }) {
const { lang } = await params;
redirect(getLocalizedPath('/docs/intro', lang));
}
```
### MDX 文档
```mdx
<!-- 内部链接会自动添加语言前缀 -->
[查看介绍](/docs/introduction)
<!-- 或使用 Redirect 组件 -->
<Redirect to="/docs/faq" />
```
## 测试清单
- [ ] 一级导航切换保持语言
- [ ] 侧边栏导航保持语言
- [ ] 首页重定向保持语言
- [ ] 404 页面重定向保持语言
- [ ] 旧链接重定向保持语言
- [ ] 文档内链接保持语言
- [ ] 语言选择器正常工作
- [ ] 搜索结果链接保持语言