Add i18n foundation (fa-IR/en-US) and localize landing + auth.

Introduce path-prefixed locale routing under app/[lang] with a middleware
that detects locale from cookie/Accept-Language (default fa-IR) and
redirects. Add fa-IR (source of truth) and en-US dictionaries, a server
getDictionary, a client I18nProvider/useT, locale-aware Link + router
helpers, and a language switcher. The root [lang] layout sets html
lang/dir and the per-locale font (Peyda for fa, Inter for en).

Landing sections and the login/register/auth shell now read all copy from
the dictionaries; dashboard localization follows in a later commit.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
keyhan
2026-06-11 12:05:03 +03:30
parent 2b16846f67
commit 34993d417f
48 changed files with 785 additions and 200 deletions
+49
View File
@@ -0,0 +1,49 @@
import type { Metadata } from 'next';
import { Inter } from 'next/font/google';
import { notFound } from 'next/navigation';
import { peyda } from '../fonts';
import '../globals.css';
import { Providers } from '@/components/providers';
import { I18nProvider } from '@/i18n/I18nProvider';
import { getDictionary } from '@/i18n/dictionaries';
import { isLocale, dirFor, locales, type Locale } from '@/i18n/config';
const inter = Inter({ subsets: ['latin'], variable: '--font-inter' });
export function generateStaticParams() {
return locales.map((lang) => ({ lang }));
}
export async function generateMetadata({
params,
}: {
params: { lang: string };
}): Promise<Metadata> {
if (!isLocale(params.lang)) return {};
const dict = await getDictionary(params.lang);
return { title: dict.meta.title, description: dict.meta.description };
}
export default async function RootLayout({
children,
params,
}: {
children: React.ReactNode;
params: { lang: string };
}) {
if (!isLocale(params.lang)) notFound();
const locale: Locale = params.lang;
const dict = await getDictionary(locale);
const dir = dirFor(locale);
const fontClass = locale === 'fa-IR' ? 'font-peyda' : 'font-sans';
return (
<html lang={locale} dir={dir}>
<body className={`${peyda.variable} ${inter.variable} ${fontClass}`}>
<I18nProvider locale={locale} dict={dict}>
<Providers>{children}</Providers>
</I18nProvider>
</body>
</html>
);
}