/* ============================================================================ ":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 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 ; }