From 619cf6bc2e0252e7759c16962b182798afac4b4e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 00:56:27 +0000 Subject: [PATCH 1/4] Initial plan From 41ff746137b77dcfa0479511e0831f79f8a0fe9a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 00:59:51 +0000 Subject: [PATCH 2/4] Add root page with language detection and redirect Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/site/app/page.tsx | 63 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 packages/site/app/page.tsx diff --git a/packages/site/app/page.tsx b/packages/site/app/page.tsx new file mode 100644 index 0000000..e289226 --- /dev/null +++ b/packages/site/app/page.tsx @@ -0,0 +1,63 @@ +import { redirect } from 'next/navigation'; +import { headers } from 'next/headers'; +import { siteConfig } from '@/lib/site-config'; + +/** + * Root page that redirects to the appropriate language version + * Detects user's preferred language from Accept-Language header + */ +export default async function RootPage() { + const headersList = await headers(); + const acceptLanguage = headersList.get('accept-language') || ''; + + // Get configured languages and default language from site config + const availableLanguages = siteConfig.i18n.languages; + const defaultLanguage = siteConfig.i18n.defaultLanguage; + + // Parse Accept-Language header to find the best match + const preferredLanguage = detectPreferredLanguage(acceptLanguage, availableLanguages); + + // Redirect to the detected or default language + const targetLanguage = preferredLanguage || defaultLanguage; + redirect(`/${targetLanguage}/docs`); +} + +/** + * Detect preferred language from Accept-Language header + * Returns the first available language that matches user preferences + */ +function detectPreferredLanguage( + acceptLanguage: string, + availableLanguages: string[] +): string | null { + if (!acceptLanguage) { + return null; + } + + // Parse Accept-Language header + // Example: "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" + const languages = acceptLanguage + .split(',') + .map(lang => { + const [code, qValue] = lang.trim().split(';q='); + const quality = qValue ? parseFloat(qValue) : 1.0; + // Extract primary language code (e.g., "en" from "en-US") + const primaryCode = code.split('-')[0].toLowerCase(); + return { code: primaryCode, quality }; + }) + .sort((a, b) => b.quality - a.quality); // Sort by quality (preference) + + // Find first matching language that is available + for (const { code } of languages) { + // Check if the language code matches any available language + if (availableLanguages.includes(code)) { + return code; + } + // Special case: map 'zh' to 'cn' + if (code === 'zh' && availableLanguages.includes('cn')) { + return 'cn'; + } + } + + return null; +} From 4b70311ca15ce8d24483dbe1e0658c9d434281eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 01:23:32 +0000 Subject: [PATCH 3/4] Implement homepage auto-redirect based on browser language Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/site/app/page.tsx | 63 -------------------------------------- packages/site/proxy.ts | 30 ++++++++++++++++-- 2 files changed, 28 insertions(+), 65 deletions(-) delete mode 100644 packages/site/app/page.tsx diff --git a/packages/site/app/page.tsx b/packages/site/app/page.tsx deleted file mode 100644 index e289226..0000000 --- a/packages/site/app/page.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { redirect } from 'next/navigation'; -import { headers } from 'next/headers'; -import { siteConfig } from '@/lib/site-config'; - -/** - * Root page that redirects to the appropriate language version - * Detects user's preferred language from Accept-Language header - */ -export default async function RootPage() { - const headersList = await headers(); - const acceptLanguage = headersList.get('accept-language') || ''; - - // Get configured languages and default language from site config - const availableLanguages = siteConfig.i18n.languages; - const defaultLanguage = siteConfig.i18n.defaultLanguage; - - // Parse Accept-Language header to find the best match - const preferredLanguage = detectPreferredLanguage(acceptLanguage, availableLanguages); - - // Redirect to the detected or default language - const targetLanguage = preferredLanguage || defaultLanguage; - redirect(`/${targetLanguage}/docs`); -} - -/** - * Detect preferred language from Accept-Language header - * Returns the first available language that matches user preferences - */ -function detectPreferredLanguage( - acceptLanguage: string, - availableLanguages: string[] -): string | null { - if (!acceptLanguage) { - return null; - } - - // Parse Accept-Language header - // Example: "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7" - const languages = acceptLanguage - .split(',') - .map(lang => { - const [code, qValue] = lang.trim().split(';q='); - const quality = qValue ? parseFloat(qValue) : 1.0; - // Extract primary language code (e.g., "en" from "en-US") - const primaryCode = code.split('-')[0].toLowerCase(); - return { code: primaryCode, quality }; - }) - .sort((a, b) => b.quality - a.quality); // Sort by quality (preference) - - // Find first matching language that is available - for (const { code } of languages) { - // Check if the language code matches any available language - if (availableLanguages.includes(code)) { - return code; - } - // Special case: map 'zh' to 'cn' - if (code === 'zh' && availableLanguages.includes('cn')) { - return 'cn'; - } - } - - return null; -} diff --git a/packages/site/proxy.ts b/packages/site/proxy.ts index 7307cc8..905305c 100644 --- a/packages/site/proxy.ts +++ b/packages/site/proxy.ts @@ -1,10 +1,36 @@ import { createI18nMiddleware } from 'fumadocs-core/i18n/middleware'; import { i18n } from '@/lib/i18n'; +import { NextResponse, NextRequest, NextFetchEvent } from 'next/server'; -export default createI18nMiddleware(i18n); +// Create fumadocs middleware +const fumadocsMiddleware = createI18nMiddleware(i18n); + +export default function proxy(request: NextRequest, event: NextFetchEvent) { + const path = request.nextUrl.pathname; + + // Handle root path separately with custom language detection + if (path === '/') { + const acceptLanguage = request.headers.get('accept-language') || ''; + + // Simple language detection: check if zh is in Accept-Language + if (acceptLanguage.toLowerCase().includes('zh')) { + // Redirect to Chinese docs + const url = request.nextUrl.clone(); + url.pathname = '/cn/docs'; + return NextResponse.redirect(url); + } else { + // Redirect to default language (English) + const url = request.nextUrl.clone(); + url.pathname = '/en/docs'; + return NextResponse.redirect(url); + } + } + + // For all other paths, pass through to fumadocs middleware + return fumadocsMiddleware(request, event); +} export const config = { // Matcher ignoring `/_next/` and `/api/` - // You may need to adjust it to ignore static assets in `/public` folder matcher: ['/((?!api|_next/static|_next/image|favicon.ico|logo.svg).*)'], }; From b9548d0e7fa2c364a606832862d7a1f7db86b0ee Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 18 Jan 2026 01:28:20 +0000 Subject: [PATCH 4/4] Add root page.tsx to enable middleware for homepage Co-authored-by: huangyiirene <7665279+huangyiirene@users.noreply.github.com> --- packages/site/app/page.tsx | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/site/app/page.tsx diff --git a/packages/site/app/page.tsx b/packages/site/app/page.tsx new file mode 100644 index 0000000..cbde5a4 --- /dev/null +++ b/packages/site/app/page.tsx @@ -0,0 +1,11 @@ +import { redirect } from 'next/navigation'; + +/** + * Root page - redirects are handled by proxy.ts middleware + * This page should never actually render as the middleware intercepts and redirects + * But Next.js requires a page component for the route to be recognized + */ +export default function RootPage() { + // Fallback redirect if middleware didn't handle it + redirect('/en/docs'); +}