initial commit
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/* ============================================================================
|
||||
":lang" LAYOUT
|
||||
----------------------------------------------------------------------------
|
||||
Owned by the app shell, not by a page agent.
|
||||
|
||||
One route tree serves both languages: every page module below this layout is
|
||||
rendered for /en/... and /ar/... alike, and reads its locale from
|
||||
`useLocale()` (or from this route's loader data via
|
||||
`useRouteLoaderData("locale")`).
|
||||
|
||||
The layout itself renders nothing but the outlet - the header, the footer
|
||||
and <html lang/dir> live in the root route, above it - so its whole job is
|
||||
validating the segment:
|
||||
/en, /ar -> render
|
||||
/EN, /Ar -> 301 to the lower-case canonical URL
|
||||
/fr, /xx -> 404 through the root ErrorBoundary
|
||||
========================================================================= */
|
||||
|
||||
import { data, Outlet, redirect } from "react-router";
|
||||
|
||||
import { dirFor, isLocale } from "~/i18n/config";
|
||||
|
||||
import type { Route } from "./+types/locale-layout";
|
||||
|
||||
export function loader({ params, request }: Route.LoaderArgs) {
|
||||
const segment = params.lang;
|
||||
const normalized = segment?.toLowerCase();
|
||||
|
||||
if (!isLocale(normalized)) {
|
||||
throw data("Not Found", { status: 404, statusText: "Not Found" });
|
||||
}
|
||||
|
||||
if (normalized !== segment) {
|
||||
const url = new URL(request.url);
|
||||
url.pathname = url.pathname.replace(
|
||||
/^\/[^/]+/,
|
||||
`/${normalized}`,
|
||||
);
|
||||
throw redirect(`${url.pathname}${url.search}`, 301);
|
||||
}
|
||||
|
||||
return { locale: normalized, dir: dirFor(normalized) };
|
||||
}
|
||||
|
||||
export default function LocaleLayout() {
|
||||
return <Outlet />;
|
||||
}
|
||||
Reference in New Issue
Block a user