diff --git a/next.config.ts b/next.config.ts index f4ed92f..24f61e8 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,4 +1,7 @@ import type { NextConfig } from 'next'; +import createNextIntlPlugin from 'next-intl/plugin'; +// 指定 i18n 配置文件路径,让 next-intl 知道支持的语言 +const withNextIntl = createNextIntlPlugin('./src/lib/i18n.ts'); const nextConfig: NextConfig = { /* config options here */ @@ -32,4 +35,4 @@ const nextConfig: NextConfig = { }, }; -export default nextConfig; +export default withNextIntl(nextConfig); diff --git a/src/app/(main)/character/[id]/page.tsx b/src/app/(main)/character/[id]/page.tsx index 8438848..fd5a643 100644 --- a/src/app/(main)/character/[id]/page.tsx +++ b/src/app/(main)/character/[id]/page.tsx @@ -4,10 +4,12 @@ import { Chip } from '@/components/ui/chip'; import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar'; import { IconButton } from '@/components/ui/button'; import Link from 'next/link'; +import { getTranslations } from 'next-intl/server'; export default async function Page({ params }: { params: Promise<{ id: string }> }) { const { id } = await params; const character = await fetchCharacter(id); + const t = await getTranslations('character'); return (
@@ -45,7 +47,7 @@ export default async function Page({ params }: { params: Promise<{ id: string }> 9.9k
-
Liked
+
{t('liked')}
@@ -57,11 +59,11 @@ export default async function Page({ params }: { params: Promise<{ id: string }> /> 123456
-
Hot
+
{t('hot')}
-
Introduction
+
{t('introduction')}
{character?.description}
diff --git a/src/locales/en.ts b/src/i18n/en-US.ts similarity index 98% rename from src/locales/en.ts rename to src/i18n/en-US.ts index eedc35b..3985ea7 100644 --- a/src/locales/en.ts +++ b/src/i18n/en-US.ts @@ -22,6 +22,11 @@ export default { check_in: 'Check-in', check_in_desc: 'Daily Free crush coinsh', }, + character: { + liked: 'Liked', + hot: 'Hot', + introduction: 'Introduction', + }, chat: { chats: 'Chats', drawer: { diff --git a/src/locales/zh.ts b/src/i18n/zh-CN.ts similarity index 98% rename from src/locales/zh.ts rename to src/i18n/zh-CN.ts index 97d6a38..9dec178 100644 --- a/src/locales/zh.ts +++ b/src/i18n/zh-CN.ts @@ -22,6 +22,11 @@ export default { check_in: '签到', check_in_desc: '每日签到,免费获取金币', }, + character: { + liked: '喜欢', + hot: '热度', + introduction: '人物简介', + }, chat: { chats: '聊天', drawer: { diff --git a/src/layout/BasicLayout/components/LocaleSwitch.tsx b/src/layout/BasicLayout/components/LocaleSwitch.tsx index 65be262..f3f38b1 100644 --- a/src/layout/BasicLayout/components/LocaleSwitch.tsx +++ b/src/layout/BasicLayout/components/LocaleSwitch.tsx @@ -13,13 +13,13 @@ export default function LocaleSwitch() { const { locale, setLocale } = useLocale(); return ( - setLocale(value as 'zh-CN' | 'en-US')}> - - En + + En ); diff --git a/src/layout/Providers/IntlProvider.tsx b/src/layout/Providers/IntlProvider.tsx index df8b18f..e5ddb13 100644 --- a/src/layout/Providers/IntlProvider.tsx +++ b/src/layout/Providers/IntlProvider.tsx @@ -7,7 +7,7 @@ import Cookies from 'js-cookie'; import { useMemoizedFn } from 'ahooks'; import { useLayoutStore } from '@/stores'; -type Locale = 'zh' | 'en'; +type Locale = 'zh-CN' | 'en-US'; interface LocaleContextType { locale: Locale; setLocale: (locale: Locale) => void; @@ -33,15 +33,15 @@ function setLocaleToCookie(locale: Locale) { function getLocaleFromCookie(): Locale { const cookieLocale = Cookies.get('locale') as Locale | undefined; - if (cookieLocale && (cookieLocale === 'zh' || cookieLocale === 'en')) { + if (cookieLocale && (cookieLocale === 'zh-CN' || cookieLocale === 'en-US')) { return cookieLocale; } - setLocaleToCookie('en'); - return 'en'; + setLocaleToCookie('en-US'); + return 'en-US'; } export function IntlProvider({ children }: IntlProviderProps) { - const [locale, setLocaleState] = useState('en'); + const [locale, setLocaleState] = useState('en-US'); const [messages, setMessages] = useState>(); const router = useRouter(); @@ -52,22 +52,23 @@ export function IntlProvider({ children }: IntlProviderProps) { const loadLocale = useMemoizedFn(async (locale: Locale) => { // 动态加载, 提升首屏加载速度 - const messages = await import(`@/locales/${locale}.ts`); + const messages = await import(`@/i18n/${locale}.ts`); setMessages(messages.default); }); useEffect(() => { const cookieLocale = getLocaleFromCookie(); + if (cookieLocale) { loadLocale(cookieLocale); setLocaleState(cookieLocale); } }, []); - const setLocale = useMemoizedFn((newLocale: Locale) => { + const setLocale = useMemoizedFn(async (newLocale: Locale) => { setLocaleState(newLocale); setLocaleToCookie(newLocale); - loadLocale(newLocale); + await loadLocale(newLocale); router.refresh(); }); diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts new file mode 100644 index 0000000..da38a4e --- /dev/null +++ b/src/lib/i18n.ts @@ -0,0 +1,20 @@ +import { cookies } from 'next/headers'; +import { getRequestConfig } from 'next-intl/server'; + +// 内存缓存:存储已经加载过的语言包 +const locales: Record = {}; + +export default getRequestConfig(async () => { + const store = await cookies(); + const cookieLocale = store.get('locale')?.value || 'en-US'; + + // 如果缓存中没有这个语言,才去加载 + if (!locales[cookieLocale]) { + locales[cookieLocale] = (await import(`@/i18n/${cookieLocale}.ts`)).default; + } + + return { + locale: cookieLocale, + messages: locales[cookieLocale], // 直接从缓存中读取 + }; +}); diff --git a/src/proxy.ts b/src/proxy.ts index 62ab494..c0d8e1f 100644 --- a/src/proxy.ts +++ b/src/proxy.ts @@ -32,10 +32,6 @@ function generateDeviceId(userAgent?: string): string { export default function proxy(request: NextRequest) { const { pathname } = request.nextUrl; - // console.log('🔄 [MIDDLEWARE] 开始处理路径:', pathname) - // console.log('🔄 [MIDDLEWARE] 请求方法:', request.method) - // console.log('🔄 [MIDDLEWARE] User-Agent:', request.headers.get('user-agent')?.substring(0, 50)) - // console.log('🔄 [MIDDLEWARE] 请求头:', Object.fromEntries(request.headers.entries())) // 获取现有设备ID let deviceId = request.cookies.get(DEVICE_ID_COOKIE_NAME)?.value; @@ -46,9 +42,8 @@ export default function proxy(request: NextRequest) { const userAgent = request.headers.get('user-agent') || undefined; deviceId = generateDeviceId(userAgent); needSetCookie = true; - // console.log('🆕 [MIDDLEWARE] 生成新设备ID:', deviceId) } else { - console.log('✅ [MIDDLEWARE] 获取现有设备ID:', deviceId); + // console.log('✅ [MIDDLEWARE] 获取现有设备ID:', deviceId); } // 认证逻辑 @@ -59,14 +54,6 @@ export default function proxy(request: NextRequest) { (route) => pathname.startsWith(route) && !pathname.startsWith('/login/fields') ); - // console.log('🔑 [MIDDLEWARE] 认证状态:', { - // isAuthenticated, - // pathname, - // isProtectedRoute, - // isAuthRoute, - // token: token ? '存在' : '不存在' - // }); - // 如果是受保护的路由但用户未登录,重定向到登录页 if (isProtectedRoute && !isAuthenticated) { console.log('🚫 [MIDDLEWARE] 重定向到登录页:', pathname); @@ -96,6 +83,17 @@ export default function proxy(request: NextRequest) { }, }); + // 如果locale cookie不存在,设置为en-US + if (!request.cookies.get('locale')?.value) { + response.cookies.set('locale', 'en-US', { + maxAge: 365 * 24 * 60 * 60, // 365天 + httpOnly: false, + secure: process.env.NODE_ENV === 'production', + sameSite: 'lax', + path: '/', + }); + } + // 如果需要设置设备ID cookie if (needSetCookie) { response.cookies.set(DEVICE_ID_COOKIE_NAME, deviceId, { @@ -107,12 +105,6 @@ export default function proxy(request: NextRequest) { }); } - if (pathname.startsWith('/@')) { - const userId = pathname.slice(2); // 去掉/@ - return NextResponse.rewrite(new URL(`/user/${userId}`, request.url)); - } - - console.log('✅ [MIDDLEWARE] 成功处理完毕:', pathname); return response; }