feat(i18n): add internationalization support with en-US and zh-CN translations

This commit is contained in:
ngc2207 2024-12-12 10:31:10 +08:00
parent 52a7ee5d0b
commit 301490c30b
7 changed files with 44 additions and 8 deletions

5
messages/en-US.json Normal file
View File

@ -0,0 +1,5 @@
{
"DashboardPage": {
"title": "Welcome to Judge4c!"
}
}

5
messages/zh-CN.json Normal file
View File

@ -0,0 +1,5 @@
{
"DashboardPage": {
"title": "欢迎来到 Judge4c"
}
}

View File

@ -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);

View File

@ -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",

View File

@ -1,8 +1,13 @@
import { useTranslations } from "next-intl";
export default function DashboardPage() {
const t = useTranslations("DashboardPage");
return (
<div className="flex flex-1 flex-col gap-4 p-4 pt-0">
<div className="grid auto-rows-min gap-4 md:grid-cols-3">
<div className="aspect-video rounded-xl bg-muted/50" />
<div className="aspect-video rounded-xl bg-muted/50 flex items-center justify-center">
<h1 className="text-2xl font-bold">{t("title")}</h1>
</div>
<div className="aspect-video rounded-xl bg-muted/50" />
<div className="aspect-video rounded-xl bg-muted/50" />
</div>

View File

@ -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 (
<html lang="en" className="h-full" suppressHydrationWarning>
<html lang={locale} className="h-full" suppressHydrationWarning>
<body
className={cn("font-sans antialiased flex min-h-full", inter.variable)}
>
@ -29,7 +34,9 @@ export default function RootLayout({
disableTransitionOnChange
enableColorScheme
>
<div className="w-full">{children}</div>
<NextIntlClientProvider messages={messages}>
<div className="w-full">{children}</div>
</NextIntlClientProvider>
</ThemeProvider>
</body>
</html>

12
src/i18n/request.ts Normal file
View File

@ -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,
};
});