Files
FastGPT/document/lib/i18n.ts
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

64 lines
1.6 KiB
TypeScript

import type { I18nConfig } from 'fumadocs-core/i18n';
export const i18n: I18nConfig = {
defaultLanguage: 'zh-CN',
languages: ['zh-CN', 'en'],
hideLocale: 'never'
};
export async function getTranslations(locale: string) {
const translations = await import(`@/i18n/${locale}/common.json`);
return translations.default;
}
export function t(key: string, locale?: string) {
const keys = key.split(':');
const namespace = keys[0];
const path = keys[1].split('.');
try {
const translations = require(`@/i18n/${locale || i18n.defaultLanguage}/common.json`);
let result = translations;
for (const p of path) {
result = result[p];
}
return result || key;
} catch (error) {
return key;
}
}
/**
* Get localized URL path based on i18n configuration
* @param path - The base path (e.g., '/docs/introduction')
* @param lang - The language code
* @returns Localized path with language prefix if needed
*/
export function getLocalizedPath(path: string, lang: string): string {
// If hideLocale is 'never', always add language prefix
if (i18n.hideLocale === 'never') {
return `/${lang}${path}`;
}
// If hideLocale is 'always', never add language prefix
if (i18n.hideLocale === 'always') {
return path;
}
// If hideLocale is 'default-locale', only add prefix for non-default languages
if (i18n.hideLocale === 'default-locale') {
return lang === i18n.defaultLanguage ? path : `/${lang}${path}`;
}
// Fallback: no prefix
return path;
}
/**
* Server-side redirect with automatic language prefix
* Import from next/navigation and use this wrapper
*/
export { redirect } from 'next/navigation';