Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 61 additions & 2 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,64 @@
import { redirect } from 'next/navigation';
import { headers } from 'next/headers';
import { i18n } from '@/lib/i18n';

export default function HomePage() {
redirect('/en/docs');
export default async function HomePage() {
const headersList = await headers();
const acceptLanguage = headersList.get('accept-language') || '';

// Parse the Accept-Language header and find the best match
const preferredLang = getPreferredLanguage(acceptLanguage, i18n.languages);

redirect(`/${preferredLang}/docs`);
}

function getPreferredLanguage(acceptLanguage: string, availableLanguages: readonly string[]): string {
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getPreferredLanguage function lacks test coverage for critical edge cases including empty Accept-Language headers, malformed quality values, case sensitivity handling, and fallback behavior. Consider adding unit tests to verify correct behavior across these scenarios.

Copilot uses AI. Check for mistakes.
// Parse Accept-Language header (e.g., "zh-CN,zh;q=0.9,en;q=0.8")
const languages = acceptLanguage
.split(',')
.map(lang => {
const parts = lang.trim().split(';');
const code = parts[0].trim();

// Skip empty language codes
if (!code) {
return null;
}

// Parse quality value, default to 1.0 if not present or invalid
let quality = 1.0;
if (parts[1]) {
const qPart = parts[1].trim();
if (qPart.startsWith('q=')) {
const parsedQuality = parseFloat(qPart.substring(2));
if (!isNaN(parsedQuality)) {
quality = parsedQuality;
}
}
}

return { code, quality };
})
.filter((lang): lang is { code: string; quality: number } => lang !== null)
.sort((a, b) => b.quality - a.quality);

// Try to find the best match (exact or partial) respecting quality order
for (const lang of languages) {
// Try exact match first
if (availableLanguages.includes(lang.code)) {
return lang.code;
Comment on lines +47 to +49
Copy link

Copilot AI Jan 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Case-sensitive comparison may fail to match language codes. The Accept-Language header can contain mixed case (e.g., 'en-US', 'EN-us'), but this performs exact case-sensitive matching. Consider normalizing both the lang.code and availableLanguages entries to lowercase before comparison to ensure reliable matching.

Suggested change
// Try exact match first
if (availableLanguages.includes(lang.code)) {
return lang.code;
// Try exact match first (case-insensitive)
const exactMatch = availableLanguages.find(
available => available.toLowerCase() === lang.code.toLowerCase()
);
if (exactMatch) {
return exactMatch;

Copilot uses AI. Check for mistakes.
}

// Try partial match (e.g., "zh" matches "zh-CN")
const langPrefix = lang.code.split('-')[0].toLowerCase();
const match = availableLanguages.find(available =>
available.toLowerCase().startsWith(langPrefix)
);
if (match) {
return match;
}
}

// Default to the configured default language
return i18n.defaultLanguage;
}
Loading