Skip to content

Commit e674988

Browse files
authored
[FEAT] - Add translation next-intl
* feat: add translation next-intl * chore: remove props on events page * fix: map link, type, etc * chore: add key
1 parent ab09a10 commit e674988

File tree

26 files changed

+336
-70
lines changed

26 files changed

+336
-70
lines changed

next.config.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import createNextIntlPlugin from "next-intl/plugin";
2+
3+
const withNextIntl = createNextIntlPlugin("./src/lib/i18n.ts");
4+
15
/** @type {import('next').NextConfig} */
26
const nextConfig = {
37
images: {
@@ -10,4 +14,4 @@ const nextConfig = {
1014
},
1115
};
1216

13-
export default nextConfig;
17+
export default withNextIntl(nextConfig);

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
"clsx": "^2.1.1",
2828
"lucide-react": "^0.428.0",
2929
"next": "14.2.5",
30+
"next-intl": "^3.17.6",
3031
"next-themes": "^0.3.0",
3132
"react": "^18",
3233
"react-dom": "^18",
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
import { FC } from "react";
2-
31
import EventsPage from "@/features/events";
42

5-
const Events: FC = () => {
3+
const Events = () => {
64
return <EventsPage />;
75
};
86
export default Events;
File renamed without changes.

src/app/[locale]/layout.tsx

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { Metadata } from "next";
2+
import { NextIntlClientProvider } from "next-intl";
3+
import { getMessages } from "next-intl/server";
4+
import { Sora } from "next/font/google";
5+
import "./globals.css";
6+
import Wrapper from "@/components/layout/wrapper";
7+
const sora = Sora({ subsets: ["latin"] });
8+
9+
export const metadata: Metadata = {
10+
title: "Welcome to Hammercode!",
11+
description: "Hammercode is a community based in Palu, Indonesia",
12+
};
13+
14+
export default async function LocaleRootLayout({
15+
children,
16+
params: { locale },
17+
}: Readonly<{
18+
children: React.ReactNode;
19+
params: { locale: string };
20+
}>) {
21+
const messages = await getMessages();
22+
23+
return (
24+
<html lang={locale}>
25+
<head>
26+
<link rel="icon" href="/assets/icons/ic_hmc-dark.svg" sizes="any" />
27+
</head>
28+
<body className={sora.className}>
29+
<NextIntlClientProvider messages={messages}>
30+
<Wrapper>{children}</Wrapper>
31+
</NextIntlClientProvider>
32+
</body>
33+
</html>
34+
);
35+
}

src/app/[locale]/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import Home from "@/features/home";
2+
3+
export default function HomePage() {
4+
return <Home />;
5+
}

src/app/layout.tsx

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,9 @@
1-
import type { Metadata } from "next";
2-
import { Sora } from "next/font/google";
3-
import "./globals.css";
4-
import Wrapper from "@/components/layout/wrapper";
1+
import { ReactNode } from "react";
52

6-
const sora = Sora({ subsets: ["latin"] });
7-
8-
export const metadata: Metadata = {
9-
title: "Welcome to Hammercode!",
10-
description: "Hammercode is a community based in Palu, Indonesia",
3+
type Props = {
4+
children: ReactNode;
115
};
126

13-
export default function RootLayout({
14-
children,
15-
}: Readonly<{
16-
children: React.ReactNode;
17-
}>) {
18-
return (
19-
<html lang="en">
20-
<head>
21-
<link rel="icon" href="/assets/icons/ic_hmc-dark.svg" sizes="any" />
22-
</head>
23-
<body className={sora.className}>
24-
<Wrapper>{children}</Wrapper>
25-
</body>
26-
</html>
27-
);
7+
export default function RootLayout({ children }: Props) {
8+
return children;
289
}

src/app/not-found.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
1-
const NotFound = () => {
2-
return <div>404</div>;
3-
};
4-
export default NotFound;
1+
"use client";
2+
3+
import Error from "next/error";
4+
5+
export default function NotFound() {
6+
return (
7+
<html lang="en">
8+
<body>
9+
<Error statusCode={404} />
10+
</body>
11+
</html>
12+
);
13+
}

src/app/page.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import Home from "@/features/home";
1+
import { redirect } from "next/navigation";
22

3-
export default function HomePage() {
4-
return <Home />;
3+
export default function RootPage() {
4+
redirect("/en");
55
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useTransition } from "react";
2+
import { useLocale } from "next-intl";
3+
import { useParams } from "next/navigation";
4+
5+
import { usePathname, useRouter } from "@/lib/navigation";
6+
import { Locale } from "@/lib/i18n";
7+
import {
8+
DropdownMenu,
9+
DropdownMenuContent,
10+
DropdownMenuItem,
11+
DropdownMenuTrigger,
12+
} from "@/components/ui/dropdown-menu";
13+
import { Button } from "@/components/ui/button";
14+
15+
const LocaleToggle = () => {
16+
const locale = useLocale();
17+
const router = useRouter();
18+
const [isPending, startTransition] = useTransition();
19+
const pathname = usePathname();
20+
const params = useParams();
21+
22+
const handleSwitch = (value: string) => {
23+
const nextLocale = value as Locale;
24+
startTransition(() => {
25+
router.replace(
26+
// @ts-expect-error -- TypeScript will validate that only known `params`
27+
// are used in combination with a given `pathname`. Since the two will
28+
// always match for the current route, we can skip runtime checks.
29+
{ pathname, params },
30+
{ locale: nextLocale }
31+
);
32+
});
33+
};
34+
return (
35+
<DropdownMenu>
36+
<DropdownMenuTrigger asChild>
37+
<Button size="sm" variant="outline" className={`w-[3rem] font-normal`} disabled={isPending}>
38+
{locale === "id" ? "🇮🇩 ID" : "🇬🇧 EN"}
39+
<span className="sr-only">Toggle locale</span>
40+
</Button>
41+
</DropdownMenuTrigger>
42+
<DropdownMenuContent align="end" className="min-w-[3rem]">
43+
<DropdownMenuItem onClick={() => handleSwitch("id")} className="cursor-pointer">
44+
🇮🇩 ID
45+
</DropdownMenuItem>
46+
<DropdownMenuItem onClick={() => handleSwitch("en")} className="cursor-pointer">
47+
🇬🇧 EN
48+
</DropdownMenuItem>
49+
</DropdownMenuContent>
50+
</DropdownMenu>
51+
);
52+
};
53+
54+
export default LocaleToggle;

0 commit comments

Comments
 (0)