From 301490c30b6f455a7b1d160c3082e803c8ae21e7 Mon Sep 17 00:00:00 2001 From: ngc2207 Date: Thu, 12 Dec 2024 10:31:10 +0800 Subject: [PATCH] feat(i18n): add internationalization support with en-US and zh-CN translations --- messages/en-US.json | 5 +++++ messages/zh-CN.json | 5 +++++ next.config.ts | 9 +++++---- package.json | 1 + src/app/dashboard/page.tsx | 7 ++++++- src/app/layout.tsx | 13 ++++++++++--- src/i18n/request.ts | 12 ++++++++++++ 7 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 messages/en-US.json create mode 100644 messages/zh-CN.json create mode 100644 src/i18n/request.ts diff --git a/messages/en-US.json b/messages/en-US.json new file mode 100644 index 0000000..3293323 --- /dev/null +++ b/messages/en-US.json @@ -0,0 +1,5 @@ +{ + "DashboardPage": { + "title": "Welcome to Judge4c!" + } +} \ No newline at end of file diff --git a/messages/zh-CN.json b/messages/zh-CN.json new file mode 100644 index 0000000..40c4183 --- /dev/null +++ b/messages/zh-CN.json @@ -0,0 +1,5 @@ +{ + "DashboardPage": { + "title": "欢迎来到 Judge4c!" + } +} \ No newline at end of file diff --git a/next.config.ts b/next.config.ts index e9ffa30..5f57d48 100644 --- a/next.config.ts +++ b/next.config.ts @@ -1,7 +1,8 @@ import type { NextConfig } from "next"; +import createNextIntlPlugin from "next-intl/plugin"; -const nextConfig: NextConfig = { - /* config options here */ -}; +const withNextIntl = createNextIntlPlugin(); -export default nextConfig; +const nextConfig: NextConfig = {}; + +export default withNextIntl(nextConfig); diff --git a/package.json b/package.json index 2f438bf..688e8e2 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "lucide-react": "^0.468.0", "next": "15.0.4", "next-auth": "^5.0.0-beta.25", + "next-intl": "^3.26.1", "next-themes": "^0.4.4", "react": "^19.0.0", "react-dom": "^19.0.0", diff --git a/src/app/dashboard/page.tsx b/src/app/dashboard/page.tsx index 0942822..4331d60 100644 --- a/src/app/dashboard/page.tsx +++ b/src/app/dashboard/page.tsx @@ -1,8 +1,13 @@ +import { useTranslations } from "next-intl"; + export default function DashboardPage() { + const t = useTranslations("DashboardPage"); return (
-
+
+

{t("title")}

+
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 7907504..3322a91 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -2,6 +2,8 @@ import "@/app/globals.css"; import { cn } from "@/lib/utils"; import type { Metadata } from "next"; import { Inter } from "next/font/google"; +import { NextIntlClientProvider } from "next-intl"; +import { getLocale, getMessages } from "next-intl/server"; import { ThemeProvider } from "@/components/theme-provider"; const inter = Inter({ subsets: ["latin"], variable: "--font-sans" }); @@ -12,13 +14,16 @@ export const metadata: Metadata = { "A full-stack, open-source online judge platform designed to elevate college programming education", }; -export default function RootLayout({ +export default async function RootLayout({ children, }: Readonly<{ children: React.ReactNode; }>) { + const locale = await getLocale(); + const messages = await getMessages(); + return ( - + @@ -29,7 +34,9 @@ export default function RootLayout({ disableTransitionOnChange enableColorScheme > -
{children}
+ +
{children}
+
diff --git a/src/i18n/request.ts b/src/i18n/request.ts new file mode 100644 index 0000000..ca1469d --- /dev/null +++ b/src/i18n/request.ts @@ -0,0 +1,12 @@ +import { auth } from "@/auth"; +import { getRequestConfig } from "next-intl/server"; + +export default getRequestConfig(async () => { + const session = await auth(); + const locale = session?.user?.language || "en-US"; + + return { + locale, + messages: (await import(`../../messages/${locale}.json`)).default, + }; +});