another step just a little remaining
This commit is contained in:
@@ -1,26 +1,61 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import type { Metadata, Viewport } from 'next';
|
||||
import localFont from 'next/font/local';
|
||||
import { setRequestLocale, getMessages } from 'next-intl/server';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { getThemeMode } from '@/lib/cookies/server';
|
||||
import { AppStoreProvider } from '@/store';
|
||||
import { ThemeProvider, getDirection } from '@/theme';
|
||||
import { BRAND } from '@/theme/colors';
|
||||
import { NotistackProvider } from '@/lib/toast';
|
||||
import { QueryProvider } from '@/lib/query/QueryProvider';
|
||||
import { routing } from '@/i18n/routing';
|
||||
import '../globals.css';
|
||||
import '@/theme/tokens.css';
|
||||
|
||||
/*
|
||||
* This layout is the correct place for NextIntlClientProvider because it
|
||||
* receives the locale directly from URL params — no header reads, no caching
|
||||
* surprises. setRequestLocale(locale) is called first so that any server
|
||||
* component deeper in the tree that calls getLocale() / getTranslations()
|
||||
* gets the right locale from React.cache instead of falling through to the
|
||||
* header fallback.
|
||||
* This is the application's ROOT layout — it renders <html> and <body>.
|
||||
*
|
||||
* getMessages({ locale }) passes the locale explicitly so the config
|
||||
* callback in src/i18n/request.ts receives it via requestLocale directly
|
||||
* (Promise.resolve(locale)) rather than reading it from the cache — an
|
||||
* extra layer of defense against cache-ordering races.
|
||||
* Why <html> lives here and NOT in a layout above the [locale] segment:
|
||||
* `lang` and `dir` must track the active locale, and the only layout that
|
||||
* re-renders when the locale changes is the one keyed on the [locale] param.
|
||||
* A layout placed above [locale] is shared between /fa and /en, so it is
|
||||
* statically cached with the defaultLocale and never re-renders on a locale
|
||||
* switch — leaving `dir`/`lang` frozen on the default ('fa'/'rtl'). Sourcing
|
||||
* the locale from URL params here means no header reads, no caching surprises.
|
||||
*
|
||||
* setRequestLocale(locale) is called first so that any server component
|
||||
* deeper in the tree that calls getLocale() / getTranslations() gets the
|
||||
* right locale from React.cache instead of falling through to the header
|
||||
* fallback. getMessages({ locale }) passes the locale explicitly so the
|
||||
* config callback in src/i18n/request.ts receives it via requestLocale
|
||||
* directly (Promise.resolve(locale)) rather than reading it from the cache.
|
||||
*/
|
||||
|
||||
// FA brand font — Mikhak, a free Persian typeface.
|
||||
// preload: false + conditional className (below) ensure the woff2 files are
|
||||
// only fetched on Persian routes, never on /en.
|
||||
const mikhak = localFont({
|
||||
src: [
|
||||
{ path: '../fonts/Mikhak-Regular.woff2', weight: '400', style: 'normal' },
|
||||
{ path: '../fonts/Mikhak-Medium.woff2', weight: '500', style: 'normal' },
|
||||
{ path: '../fonts/Mikhak-Bold.woff2', weight: '700', style: 'normal' },
|
||||
],
|
||||
display: 'swap',
|
||||
variable: '--font-mikhak',
|
||||
preload: false,
|
||||
});
|
||||
|
||||
export const viewport: Viewport = {
|
||||
themeColor: BRAND.teal,
|
||||
};
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'Balinyaar | بالینیار',
|
||||
description: 'Balinyaar web application',
|
||||
manifest: '/site.webmanifest',
|
||||
};
|
||||
|
||||
export default async function LocaleLayout({
|
||||
children,
|
||||
params,
|
||||
@@ -37,21 +72,34 @@ export default async function LocaleLayout({
|
||||
setRequestLocale(safeLocale);
|
||||
|
||||
const messages = await getMessages({ locale: safeLocale });
|
||||
const { defaultMode } = await getThemeMode();
|
||||
const { colorScheme, defaultMode } = await getThemeMode();
|
||||
const dir = getDirection(safeLocale);
|
||||
|
||||
// Only attach the Mikhak font variable on RTL (Persian) routes so the
|
||||
// Persian typeface is not loaded for English pages.
|
||||
const fontClassName = safeLocale === 'fa' ? mikhak.variable : undefined;
|
||||
|
||||
return (
|
||||
<NextIntlClientProvider locale={safeLocale} messages={messages}>
|
||||
<AppStoreProvider>
|
||||
<ThemeProvider dir={dir} defaultMode={defaultMode}>
|
||||
<QueryProvider>
|
||||
<NotistackProvider>
|
||||
{children}
|
||||
</NotistackProvider>
|
||||
</QueryProvider>
|
||||
</ThemeProvider>
|
||||
</AppStoreProvider>
|
||||
</NextIntlClientProvider>
|
||||
<html
|
||||
lang={safeLocale}
|
||||
dir={dir}
|
||||
className={fontClassName}
|
||||
data-mui-color-scheme={colorScheme}
|
||||
>
|
||||
<body>
|
||||
<NextIntlClientProvider locale={safeLocale} messages={messages}>
|
||||
<AppStoreProvider>
|
||||
<ThemeProvider dir={dir} defaultMode={defaultMode}>
|
||||
<QueryProvider>
|
||||
<NotistackProvider>
|
||||
{children}
|
||||
</NotistackProvider>
|
||||
</QueryProvider>
|
||||
</ThemeProvider>
|
||||
</AppStoreProvider>
|
||||
</NextIntlClientProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user