Fix dynamic default locale routing
This commit is contained in:
@@ -5,7 +5,7 @@ import { isRedirectError } from "next/dist/client/components/redirect-error";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { enforceContactRateLimit, verifyTurnstileToken } from "@/lib/contact-guard";
|
import { enforceContactRateLimit, verifyTurnstileToken } from "@/lib/contact-guard";
|
||||||
import { getContactProtectionSettings } from "@/lib/app-config";
|
import { getContactProtectionSettings, getSiteSettings } from "@/lib/app-config";
|
||||||
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
||||||
import { sendContactMessage } from "@/lib/mail";
|
import { sendContactMessage } from "@/lib/mail";
|
||||||
|
|
||||||
@@ -60,7 +60,8 @@ function getStringValue(formData: FormData, key: string) {
|
|||||||
|
|
||||||
export async function submitContactFormAction(formData: FormData) {
|
export async function submitContactFormAction(formData: FormData) {
|
||||||
const locale = resolveLocale(String(formData.get("locale") ?? ""));
|
const locale = resolveLocale(String(formData.get("locale") ?? ""));
|
||||||
const contactPath = getLocalizedPath(locale, "/contact");
|
const siteSettings = await getSiteSettings();
|
||||||
|
const contactPath = getLocalizedPath(locale, "/contact", siteSettings.defaultLocale);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const protectionSettings = await getContactProtectionSettings();
|
const protectionSettings = await getContactProtectionSettings();
|
||||||
@@ -86,7 +87,13 @@ export async function submitContactFormAction(formData: FormData) {
|
|||||||
message: values.message,
|
message: values.message,
|
||||||
});
|
});
|
||||||
|
|
||||||
redirect(withMessage(getLocalizedPath(locale, "/success"), "success", contactSuccessMessages[locale]));
|
redirect(
|
||||||
|
withMessage(
|
||||||
|
getLocalizedPath(locale, "/success", siteSettings.defaultLocale),
|
||||||
|
"success",
|
||||||
|
contactSuccessMessages[locale],
|
||||||
|
),
|
||||||
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (isRedirectError(error)) {
|
if (isRedirectError(error)) {
|
||||||
throw error;
|
throw error;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { PageHero } from "@/components/layout/page-hero";
|
|||||||
import { MotionFade } from "@/components/motion-fade";
|
import { MotionFade } from "@/components/motion-fade";
|
||||||
import { ContactForm } from "@/components/site/contact-form";
|
import { ContactForm } from "@/components/site/contact-form";
|
||||||
import { buildLocalizedMetadata } from "@/lib/metadata";
|
import { buildLocalizedMetadata } from "@/lib/metadata";
|
||||||
import { getPublicContactProtectionSettings } from "@/lib/app-config";
|
import { getPublicContactProtectionSettings, getSiteSettings } from "@/lib/app-config";
|
||||||
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
||||||
import { AppCard } from "@/components/ui/app-card";
|
import { AppCard } from "@/components/ui/app-card";
|
||||||
import { CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
import { CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
@@ -36,9 +36,10 @@ export async function generateMetadata({ params }: ContactPageProps): Promise<Me
|
|||||||
export default async function ContactPage({ params }: ContactPageProps) {
|
export default async function ContactPage({ params }: ContactPageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
const localeKey = resolveLocale(locale);
|
const localeKey = resolveLocale(locale);
|
||||||
const [t, protection] = await Promise.all([
|
const [t, protection, siteSettings] = await Promise.all([
|
||||||
getTranslations({ locale: localeKey, namespace: "contactPage" }),
|
getTranslations({ locale: localeKey, namespace: "contactPage" }),
|
||||||
getPublicContactProtectionSettings(),
|
getPublicContactProtectionSettings(),
|
||||||
|
getSiteSettings(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -82,7 +83,7 @@ export default async function ContactPage({ params }: ContactPageProps) {
|
|||||||
<ContactForm
|
<ContactForm
|
||||||
action={submitContactFormAction}
|
action={submitContactFormAction}
|
||||||
locale={localeKey}
|
locale={localeKey}
|
||||||
previewHref={getLocalizedPath(localeKey, "/success")}
|
previewHref={getLocalizedPath(localeKey, "/success", siteSettings.defaultLocale)}
|
||||||
protection={protection}
|
protection={protection}
|
||||||
copy={{
|
copy={{
|
||||||
name: t("name"),
|
name: t("name"),
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { SiteAmbientBackdrop } from "@/components/layout/site-ambient-backdrop";
|
|||||||
import { SiteFooter } from "@/components/layout/site-footer";
|
import { SiteFooter } from "@/components/layout/site-footer";
|
||||||
import { SiteHeader } from "@/components/layout/site-header";
|
import { SiteHeader } from "@/components/layout/site-header";
|
||||||
import { isAdminAuthenticated } from "@/lib/admin-auth";
|
import { isAdminAuthenticated } from "@/lib/admin-auth";
|
||||||
import { getMaintenanceMode, getSiteSettingsMediaBindings } from "@/lib/app-config";
|
import { getMaintenanceMode, getSiteSettings, getSiteSettingsMediaBindings } from "@/lib/app-config";
|
||||||
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
||||||
|
|
||||||
type SiteLayoutProps = {
|
type SiteLayoutProps = {
|
||||||
@@ -24,14 +24,15 @@ export default async function SiteLayout({ children, params }: SiteLayoutProps)
|
|||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
|
|
||||||
const localeKey = resolveLocale(locale);
|
const localeKey = resolveLocale(locale);
|
||||||
const [maintenanceEnabled, mediaBindings] = await Promise.all([
|
const [maintenanceEnabled, mediaBindings, siteSettings] = await Promise.all([
|
||||||
getMaintenanceMode(),
|
getMaintenanceMode(),
|
||||||
getSiteSettingsMediaBindings(),
|
getSiteSettingsMediaBindings(),
|
||||||
|
getSiteSettings(),
|
||||||
]);
|
]);
|
||||||
const authenticated = await isAdminAuthenticated();
|
const authenticated = await isAdminAuthenticated();
|
||||||
|
|
||||||
if (maintenanceEnabled && !authenticated) {
|
if (maintenanceEnabled && !authenticated) {
|
||||||
redirect(getLocalizedPath(localeKey, "/coming-soon"));
|
redirect(getLocalizedPath(localeKey, "/coming-soon", siteSettings.defaultLocale));
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -40,9 +41,10 @@ export default async function SiteLayout({ children, params }: SiteLayoutProps)
|
|||||||
<SiteHeader
|
<SiteHeader
|
||||||
lightLogoUrl={mediaBindings.siteLogoLight?.url}
|
lightLogoUrl={mediaBindings.siteLogoLight?.url}
|
||||||
darkLogoUrl={mediaBindings.siteLogoDark?.url}
|
darkLogoUrl={mediaBindings.siteLogoDark?.url}
|
||||||
|
defaultLocale={siteSettings.defaultLocale}
|
||||||
/>
|
/>
|
||||||
<main className="flex-1">{children}</main>
|
<main className="flex-1">{children}</main>
|
||||||
<SiteFooter />
|
<SiteFooter defaultLocale={siteSettings.defaultLocale} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,10 @@ export async function generateMetadata({ params }: HomePageProps): Promise<Metad
|
|||||||
export default async function HomePage({ params }: HomePageProps) {
|
export default async function HomePage({ params }: HomePageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
const localeKey = resolveLocale(locale);
|
const localeKey = resolveLocale(locale);
|
||||||
const [t, marqueeSettings] = await Promise.all([
|
const [t, marqueeSettings, siteSettings] = await Promise.all([
|
||||||
getTranslations({ locale: localeKey, namespace: "homepage" }),
|
getTranslations({ locale: localeKey, namespace: "homepage" }),
|
||||||
getMarqueeSettings(),
|
getMarqueeSettings(),
|
||||||
|
getSiteSettings(),
|
||||||
]);
|
]);
|
||||||
const serviceItems = [
|
const serviceItems = [
|
||||||
t("serviceBrand"),
|
t("serviceBrand"),
|
||||||
@@ -108,7 +109,7 @@ export default async function HomePage({ params }: HomePageProps) {
|
|||||||
</p>
|
</p>
|
||||||
<div className="mt-8 flex flex-wrap gap-3">
|
<div className="mt-8 flex flex-wrap gap-3">
|
||||||
<Button asChild size="lg" className="min-w-[11rem]">
|
<Button asChild size="lg" className="min-w-[11rem]">
|
||||||
<Link href={getLocalizedPath(localeKey, "/contact")}>
|
<Link href={getLocalizedPath(localeKey, "/contact", siteSettings.defaultLocale)}>
|
||||||
{t("servicesPrimaryCta")}
|
{t("servicesPrimaryCta")}
|
||||||
<ArrowRight className="h-4 w-4" />
|
<ArrowRight className="h-4 w-4" />
|
||||||
</Link>
|
</Link>
|
||||||
@@ -119,7 +120,7 @@ export default async function HomePage({ params }: HomePageProps) {
|
|||||||
variant="outline"
|
variant="outline"
|
||||||
className="min-w-[11rem] border-border/80 bg-background/70 hover:bg-background"
|
className="min-w-[11rem] border-border/80 bg-background/70 hover:bg-background"
|
||||||
>
|
>
|
||||||
<Link href={getLocalizedPath(localeKey, "/portfolio")}>
|
<Link href={getLocalizedPath(localeKey, "/portfolio", siteSettings.defaultLocale)}>
|
||||||
{t("servicesSecondaryCta")}
|
{t("servicesSecondaryCta")}
|
||||||
</Link>
|
</Link>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { getTranslations } from "next-intl/server";
|
|||||||
import { Container } from "@/components/layout/container";
|
import { Container } from "@/components/layout/container";
|
||||||
import { MotionFade } from "@/components/motion-fade";
|
import { MotionFade } from "@/components/motion-fade";
|
||||||
import { HeroShell, HeroTitle } from "@/components/layout/site-hero";
|
import { HeroShell, HeroTitle } from "@/components/layout/site-hero";
|
||||||
|
import { getSiteSettings } from "@/lib/app-config";
|
||||||
import { buildLocalizedMetadata } from "@/lib/metadata";
|
import { buildLocalizedMetadata } from "@/lib/metadata";
|
||||||
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
import { getLocalizedPath, resolveLocale } from "@/lib/locale";
|
||||||
import { AppCard } from "@/components/ui/app-card";
|
import { AppCard } from "@/components/ui/app-card";
|
||||||
@@ -34,7 +35,10 @@ export async function generateMetadata({ params }: SuccessPageProps): Promise<Me
|
|||||||
export default async function SuccessPage({ params }: SuccessPageProps) {
|
export default async function SuccessPage({ params }: SuccessPageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
const localeKey = resolveLocale(locale);
|
const localeKey = resolveLocale(locale);
|
||||||
const t = await getTranslations({ locale: localeKey, namespace: "successPage" });
|
const [t, siteSettings] = await Promise.all([
|
||||||
|
getTranslations({ locale: localeKey, namespace: "successPage" }),
|
||||||
|
getSiteSettings(),
|
||||||
|
]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -51,10 +55,10 @@ export default async function SuccessPage({ params }: SuccessPageProps) {
|
|||||||
</p>
|
</p>
|
||||||
<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
|
<div className="mt-8 flex flex-wrap items-center justify-center gap-3">
|
||||||
<Button asChild>
|
<Button asChild>
|
||||||
<Link href={getLocalizedPath(localeKey)}>{t("home")}</Link>
|
<Link href={getLocalizedPath(localeKey, "/", siteSettings.defaultLocale)}>{t("home")}</Link>
|
||||||
</Button>
|
</Button>
|
||||||
<Button asChild variant="outline">
|
<Button asChild variant="outline">
|
||||||
<Link href={getLocalizedPath(localeKey, "/contact")}>{t("contact")}</Link>
|
<Link href={getLocalizedPath(localeKey, "/contact", siteSettings.defaultLocale)}>{t("contact")}</Link>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ export default async function ComingSoonPage({
|
|||||||
}: ComingSoonPageProps) {
|
}: ComingSoonPageProps) {
|
||||||
const { locale } = await params;
|
const { locale } = await params;
|
||||||
const localeKey = resolveLocale(locale);
|
const localeKey = resolveLocale(locale);
|
||||||
const t = await getTranslations({ locale: localeKey, namespace: "comingSoon" });
|
const [t, siteSettings] = await Promise.all([
|
||||||
|
getTranslations({ locale: localeKey, namespace: "comingSoon" }),
|
||||||
|
getSiteSettings(),
|
||||||
|
]);
|
||||||
const isArabic = localeKey === "ar";
|
const isArabic = localeKey === "ar";
|
||||||
const lines = [
|
const lines = [
|
||||||
{
|
{
|
||||||
@@ -57,7 +60,7 @@ export default async function ComingSoonPage({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative min-h-screen overflow-hidden">
|
<div className="relative min-h-screen overflow-hidden">
|
||||||
<FloatingPreferences locale={localeKey} />
|
<FloatingPreferences locale={localeKey} defaultLocale={siteSettings.defaultLocale} />
|
||||||
|
|
||||||
<HeroShell className="min-h-screen" showBridges>
|
<HeroShell className="min-h-screen" showBridges>
|
||||||
<MotionFade className="relative z-10 w-full">
|
<MotionFade className="relative z-10 w-full">
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ export default async function LocaleLayout({
|
|||||||
const localeClassName = locale === "ar" ? "font-arabic" : "font-latin";
|
const localeClassName = locale === "ar" ? "font-arabic" : "font-latin";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<NextIntlClientProvider messages={messages}>
|
<NextIntlClientProvider locale={locale} messages={messages}>
|
||||||
<div lang={locale} dir={getDirection(locale)} className={localeClassName}>
|
<div lang={locale} dir={getDirection(locale)} className={localeClassName}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ import { cn } from "@/lib/utils";
|
|||||||
|
|
||||||
type FloatingPreferencesProps = {
|
type FloatingPreferencesProps = {
|
||||||
locale: string;
|
locale: string;
|
||||||
|
defaultLocale: "de" | "en" | "ar";
|
||||||
className?: string;
|
className?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function FloatingPreferences({
|
export function FloatingPreferences({
|
||||||
locale,
|
locale,
|
||||||
|
defaultLocale,
|
||||||
className,
|
className,
|
||||||
}: FloatingPreferencesProps) {
|
}: FloatingPreferencesProps) {
|
||||||
const t = useTranslations("navigation");
|
const t = useTranslations("navigation");
|
||||||
@@ -39,6 +41,7 @@ export function FloatingPreferences({
|
|||||||
/>
|
/>
|
||||||
<LocaleToggle
|
<LocaleToggle
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
defaultLocale={defaultLocale}
|
||||||
className="h-9 w-9 rounded-pill border border-transparent bg-transparent p-0 text-foreground/80 hover:bg-accent hover:text-foreground"
|
className="h-9 w-9 rounded-pill border border-transparent bg-transparent p-0 text-foreground/80 hover:bg-accent hover:text-foreground"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const PENDING_TOAST_STORAGE_KEY = "mohfarawati-pending-toast";
|
|||||||
|
|
||||||
type LocaleToggleProps = {
|
type LocaleToggleProps = {
|
||||||
locale: string;
|
locale: string;
|
||||||
|
defaultLocale?: AppLocale;
|
||||||
className?: string;
|
className?: string;
|
||||||
showLabel?: boolean;
|
showLabel?: boolean;
|
||||||
};
|
};
|
||||||
@@ -29,6 +30,7 @@ const localeChangedMessages: Record<AppLocale, string> = {
|
|||||||
|
|
||||||
export function LocaleToggle({
|
export function LocaleToggle({
|
||||||
locale,
|
locale,
|
||||||
|
defaultLocale = "de",
|
||||||
className,
|
className,
|
||||||
showLabel = false,
|
showLabel = false,
|
||||||
}: LocaleToggleProps) {
|
}: LocaleToggleProps) {
|
||||||
@@ -82,7 +84,7 @@ export function LocaleToggle({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href={getLocalizedPath(targetLocale, currentPath)}
|
href={getLocalizedPath(targetLocale, currentPath, defaultLocale)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const message = localeChangedMessages[targetLocale];
|
const message = localeChangedMessages[targetLocale];
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Link from "next/link";
|
|||||||
import { useLocale, useTranslations } from "next-intl";
|
import { useLocale, useTranslations } from "next-intl";
|
||||||
|
|
||||||
import { Container } from "@/components/layout/container";
|
import { Container } from "@/components/layout/container";
|
||||||
import { getLocalizedPath } from "@/lib/locale";
|
import { AppLocale, getLocalizedPath } from "@/lib/locale";
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ key: "home", path: "" },
|
{ key: "home", path: "" },
|
||||||
@@ -11,7 +11,11 @@ const navItems = [
|
|||||||
{ key: "contact", path: "/contact" },
|
{ key: "contact", path: "/contact" },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function SiteFooter() {
|
type SiteFooterProps = {
|
||||||
|
defaultLocale: AppLocale;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function SiteFooter({ defaultLocale }: SiteFooterProps) {
|
||||||
const locale = useLocale();
|
const locale = useLocale();
|
||||||
const tNav = useTranslations("navigation");
|
const tNav = useTranslations("navigation");
|
||||||
const tFooter = useTranslations("footer");
|
const tFooter = useTranslations("footer");
|
||||||
@@ -23,7 +27,7 @@ export function SiteFooter() {
|
|||||||
{navItems.map((item) => (
|
{navItems.map((item) => (
|
||||||
<Link
|
<Link
|
||||||
key={item.key}
|
key={item.key}
|
||||||
href={getLocalizedPath(locale, item.path || "/")}
|
href={getLocalizedPath(locale, item.path || "/", defaultLocale)}
|
||||||
className="text-muted-foreground hover:text-foreground"
|
className="text-muted-foreground hover:text-foreground"
|
||||||
>
|
>
|
||||||
{tNav(item.key)}
|
{tNav(item.key)}
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ const disabledMobileNavItemClassName =
|
|||||||
type SiteHeaderProps = {
|
type SiteHeaderProps = {
|
||||||
lightLogoUrl?: string | null;
|
lightLogoUrl?: string | null;
|
||||||
darkLogoUrl?: string | null;
|
darkLogoUrl?: string | null;
|
||||||
|
defaultLocale: "de" | "en" | "ar";
|
||||||
};
|
};
|
||||||
|
|
||||||
function getDirectionalReveal(direction: "rtl" | "ltr") {
|
function getDirectionalReveal(direction: "rtl" | "ltr") {
|
||||||
@@ -57,9 +58,11 @@ function isNavItemActive(currentPath: string, itemPath: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function NavLinks({
|
function NavLinks({
|
||||||
|
defaultLocale,
|
||||||
onNavigate,
|
onNavigate,
|
||||||
mobile = false,
|
mobile = false,
|
||||||
}: {
|
}: {
|
||||||
|
defaultLocale: "de" | "en" | "ar";
|
||||||
onNavigate?: () => void;
|
onNavigate?: () => void;
|
||||||
mobile?: boolean;
|
mobile?: boolean;
|
||||||
}) {
|
}) {
|
||||||
@@ -113,7 +116,7 @@ function NavLinks({
|
|||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
key={item.key}
|
key={item.key}
|
||||||
href={getLocalizedPath(locale, itemPath)}
|
href={getLocalizedPath(locale, itemPath, defaultLocale)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"relative z-10 rounded-pill transition-colors",
|
"relative z-10 rounded-pill transition-colors",
|
||||||
mobile ? "px-4 py-3 text-sm font-medium" : "px-3.5 py-2 text-sm font-medium xl:px-4",
|
mobile ? "px-4 py-3 text-sm font-medium" : "px-3.5 py-2 text-sm font-medium xl:px-4",
|
||||||
@@ -142,6 +145,7 @@ function NavLinks({
|
|||||||
export function SiteHeader({
|
export function SiteHeader({
|
||||||
lightLogoUrl,
|
lightLogoUrl,
|
||||||
darkLogoUrl,
|
darkLogoUrl,
|
||||||
|
defaultLocale,
|
||||||
}: SiteHeaderProps) {
|
}: SiteHeaderProps) {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [isScrolled, setIsScrolled] = useState(false);
|
const [isScrolled, setIsScrolled] = useState(false);
|
||||||
@@ -210,7 +214,7 @@ export function SiteHeader({
|
|||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Link
|
<Link
|
||||||
href={getLocalizedPath(locale)}
|
href={getLocalizedPath(locale, "/", defaultLocale)}
|
||||||
className="inline-flex items-center gap-2.5 rounded-pill px-1 py-1 sm:gap-3 lg:py-2"
|
className="inline-flex items-center gap-2.5 rounded-pill px-1 py-1 sm:gap-3 lg:py-2"
|
||||||
onClick={handleLogoClick}
|
onClick={handleLogoClick}
|
||||||
>
|
>
|
||||||
@@ -277,7 +281,7 @@ export function SiteHeader({
|
|||||||
isArabic ? "w-auto max-w-none" : "min-w-[27rem] max-w-[42rem]",
|
isArabic ? "w-auto max-w-none" : "min-w-[27rem] max-w-[42rem]",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<NavLinks />
|
<NavLinks defaultLocale={defaultLocale} />
|
||||||
</motion.nav>
|
</motion.nav>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -293,6 +297,7 @@ export function SiteHeader({
|
|||||||
<div className={desktopControlRailClassName}>
|
<div className={desktopControlRailClassName}>
|
||||||
<LocaleToggle
|
<LocaleToggle
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
defaultLocale={defaultLocale}
|
||||||
className={desktopControlButtonClassName}
|
className={desktopControlButtonClassName}
|
||||||
/>
|
/>
|
||||||
<SoundToggle
|
<SoundToggle
|
||||||
@@ -405,7 +410,7 @@ export function SiteHeader({
|
|||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Link
|
<Link
|
||||||
href={getLocalizedPath(locale, itemPath)}
|
href={getLocalizedPath(locale, itemPath, defaultLocale)}
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex items-center justify-between rounded-nested px-4 py-3 text-sm font-medium transition-colors",
|
"flex items-center justify-between rounded-nested px-4 py-3 text-sm font-medium transition-colors",
|
||||||
isActive
|
isActive
|
||||||
@@ -435,6 +440,7 @@ export function SiteHeader({
|
|||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-2">
|
||||||
<LocaleToggle
|
<LocaleToggle
|
||||||
locale={locale}
|
locale={locale}
|
||||||
|
defaultLocale={defaultLocale}
|
||||||
className={mobileControlButtonClassName}
|
className={mobileControlButtonClassName}
|
||||||
/>
|
/>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
|
|||||||
+6
-2
@@ -28,8 +28,12 @@ export function stripLocalePrefix(pathname: string): string {
|
|||||||
return pathname || "/";
|
return pathname || "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLocalizedPath(locale: string, pathname = "/"): string {
|
export function getLocalizedPath(
|
||||||
return getLocalizedPathWithDefault(locale, pathname, routing.defaultLocale);
|
locale: string,
|
||||||
|
pathname = "/",
|
||||||
|
defaultLocale: AppLocale = routing.defaultLocale,
|
||||||
|
): string {
|
||||||
|
return getLocalizedPathWithDefault(locale, pathname, defaultLocale);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getLocalizedPathWithDefault(
|
export function getLocalizedPathWithDefault(
|
||||||
|
|||||||
+7
-3
@@ -196,9 +196,13 @@ export default async function middleware(request: NextRequest) {
|
|||||||
configuredDefaultLocale !== routing.defaultLocale &&
|
configuredDefaultLocale !== routing.defaultLocale &&
|
||||||
!hasLocalePrefix(pathname)
|
!hasLocalePrefix(pathname)
|
||||||
) {
|
) {
|
||||||
const redirectUrl = request.nextUrl.clone();
|
const rewriteUrl = request.nextUrl.clone();
|
||||||
redirectUrl.pathname = getLocalizedPathWithDefault(configuredDefaultLocale, pathname, routing.defaultLocale);
|
rewriteUrl.pathname = getLocalizedPathWithDefault(
|
||||||
return NextResponse.redirect(redirectUrl, 307);
|
configuredDefaultLocale,
|
||||||
|
pathname,
|
||||||
|
routing.defaultLocale,
|
||||||
|
);
|
||||||
|
return NextResponse.rewrite(rewriteUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
Reference in New Issue
Block a user