-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlayout.tsx
More file actions
123 lines (115 loc) · 3.33 KB
/
Copy pathlayout.tsx
File metadata and controls
123 lines (115 loc) · 3.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import type { Metadata, Viewport } from "next";
import { GeistSans } from "geist/font/sans";
import { GeistMono } from "geist/font/mono";
import { Rubik } from "next/font/google";
import "../globals.css";
import { cn } from "@/lib/utils";
import { ThemeProvider } from "@/components/atom/theme-provider";
import { ImageKitProvider } from "@/components/ui/imagekit-provider";
import { Toaster } from "sonner";
import { getDictionary } from "@/components/internationalization/dictionaries";
import { i18n, type Locale, localeConfig } from "@/components/internationalization/config";
import { SessionProvider } from "next-auth/react";
import { auth } from "@/auth";
function resolveLocale(rawLang: string): Locale {
return (i18n.locales as readonly string[]).includes(rawLang)
? (rawLang as Locale)
: i18n.defaultLocale;
}
// Configure Rubik font for Arabic
const rubik = Rubik({
subsets: ['arabic', 'latin'],
display: 'swap',
variable: '--font-rubik',
});
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
maximumScale: 1,
userScalable: false,
};
export async function generateMetadata({
params,
}: {
params: Promise<{ lang: string }>;
}): Promise<Metadata> {
const { lang: rawLang } = await params;
const lang = resolveLocale(rawLang);
const dict = await getDictionary(lang);
const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'https://databayt.org';
return {
title: dict.metadata.title,
description: dict.metadata.description,
icons: {
icon: '/logo.png',
shortcut: '/logo.png',
apple: '/logo.png',
},
openGraph: {
title: dict.metadata.title,
description: dict.metadata.description,
locale: lang,
alternateLocale: lang === 'en' ? 'ar' : 'en',
images: [
{
url: `${baseUrl}/logo.png`,
width: 512,
height: 512,
alt: 'Databayt',
},
],
},
twitter: {
card: 'summary',
title: dict.metadata.title,
description: dict.metadata.description,
images: [`${baseUrl}/logo.png`],
},
alternates: {
languages: {
en: `${baseUrl}/en`,
ar: `${baseUrl}/ar`,
'x-default': `${baseUrl}/en`,
},
},
};
}
export default async function LocaleLayout({
children,
params,
}: Readonly<{
children: React.ReactNode;
params: Promise<{ lang: string }>;
}>) {
const [{ lang: rawLang }, session] = await Promise.all([params, auth()]);
const lang = resolveLocale(rawLang);
const config = localeConfig[lang];
const isRTL = config.dir === 'rtl';
return (
<html lang={lang} dir={config.dir}>
<body
className={cn(
"font-sans antialiased",
isRTL ? rubik.className : GeistSans.className,
GeistMono.variable,
rubik.variable
)}
>
<SessionProvider session={session}>
<ThemeProvider>
<ImageKitProvider>
<div className="layout-container">
<Toaster position={isRTL ? "bottom-left" : "bottom-right"} />
{children}
</div>
</ImageKitProvider>
</ThemeProvider>
</SessionProvider>
</body>
</html>
);
}
// Generate static params for all supported locales
export function generateStaticParams() {
return Object.keys(localeConfig).map((lang) => ({ lang }));
}