Merge pull request #134 from ktz-dev/internationalization

feat: Multi-language support
This commit is contained in:
mauro 🤙
2024-08-30 13:59:17 +02:00
committed by GitHub
9 changed files with 196 additions and 17 deletions

View File

@@ -3,6 +3,8 @@ import { Inter } from "next/font/google";
import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider";
import StyledComponentsRegistry from "@/lib/styled-components-registry";
import {NextIntlClientProvider} from 'next-intl';
import {getLocale, getMessages} from 'next-intl/server';
const inter = Inter({ subsets: ["latin"] });
@@ -12,26 +14,32 @@ export const metadata: Metadata = {
keywords: ["Zen", "Browser", "Zen Browser", "Web", "Internet", "Fast"],
};
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" suppressHydrationWarning>
<html lang={locale} suppressHydrationWarning>
<head>
<link rel="me" href="https://fosstodon.org/@zenbrowser"></link>
<link rel="alternate" type="application/rss+xml" title="Zen Browser Release Notes" href="https://www.zen-browser.app/feed.xml" />
</head>
<body className={inter.className}>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</ThemeProvider>
<NextIntlClientProvider messages={messages}>
<ThemeProvider
attribute="class"
defaultTheme="dark"
enableSystem
disableTransitionOnChange
>
<StyledComponentsRegistry>{children}</StyledComponentsRegistry>
</ThemeProvider>
</NextIntlClientProvider>
</body>
</html>
);

View File

@@ -18,6 +18,7 @@ import { ModeToggle } from "./mode-toggle"
import { MobileNav } from "./mobile-nav"
import { HeartIcon } from "lucide-react"
import { HeartFilledIcon } from "@radix-ui/react-icons"
import { useTranslations } from "next-intl";
export const components: { title: string; href: string; description: string }[] = [
{
@@ -48,6 +49,9 @@ export const components: { title: string; href: string; description: string }[]
]
export function Navigation() {
const t = useTranslations('navigation');
return (
<div className="bg-background z-40 top-0 left-0 w-full flex fixed border-b border-grey p-2 items-center justify-center">
<MobileNav />
@@ -59,7 +63,7 @@ export function Navigation() {
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger>Getting started</NavigationMenuTrigger>
<NavigationMenuTrigger>{t('getting-started')}</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid gap-3 p-6 md:w-[400px] lg:w-[500px] lg:grid-cols-[.75fr_1fr]">
<li className="row-span-3">
@@ -94,7 +98,7 @@ export function Navigation() {
<NavigationMenuItem>
<NavigationMenuTrigger>
<HeartFilledIcon className="text-red-500" />
<span className="ml-2">Donate</span>
<span className="ml-2">{t('donate')}</span>
</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
@@ -114,7 +118,7 @@ export function Navigation() {
</NavigationMenuContent>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuTrigger>Useful Links</NavigationMenuTrigger>
<NavigationMenuTrigger>{t('useful-links')}</NavigationMenuTrigger>
<NavigationMenuContent>
<ul className="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-2 lg:w-[600px] ">
{components.map((component) => (

35
src/i18n.ts Normal file
View File

@@ -0,0 +1,35 @@
import { getRequestConfig } from "next-intl/server";
import { headers } from "next/headers";
const SUPPORTED_LANGUAGES = ['en', 'de'];
export default getRequestConfig(async () => {
const headersList = headers();
const acceptLanguage = headersList.get("accept-language") || "en";
const [primaryLanguage] = acceptLanguage
.split(",")
.map((lang) => lang.split(";")[0])
.map((lang) => lang.toLowerCase());
const locale = SUPPORTED_LANGUAGES.includes(primaryLanguage) ? primaryLanguage : 'en';
try {
const messages = (await import(`../messages/${locale}.json`)).default;
return {
locale,
messages,
};
} catch (error) {
console.error(`Failed to load messages for locale: ${locale}`, error);
const fallbackMessages = (await import(`../messages/en.json`)).default;
return {
locale: "en",
messages: fallbackMessages,
};
}
});