fix: add proper locale detection and URL parsing to 404 page
- Add detectLocaleFromURL helper function to extract locale from URL path - Handle both params-based and URL-based locale detection - Make params optional since it's undefined when 404 is triggered - Use regex to extract locale from URL path (e.g., /en/page -> en) - Remove debug logging and clean up imports Note: Currently falling back to default Next.js 404 due to layout component issues
This commit is contained in:
@@ -5,7 +5,6 @@ import {
|
|||||||
getSaleorLocale,
|
getSaleorLocale,
|
||||||
isValidLocale,
|
isValidLocale,
|
||||||
DEFAULT_LOCALE,
|
DEFAULT_LOCALE,
|
||||||
getLocaleFromPath,
|
|
||||||
LOCALE_COOKIE,
|
LOCALE_COOKIE,
|
||||||
type Locale
|
type Locale
|
||||||
} from "@/lib/i18n/locales";
|
} from "@/lib/i18n/locales";
|
||||||
@@ -21,36 +20,35 @@ export const metadata: Metadata = {
|
|||||||
description: "Discover our bestselling natural oils for hair and skin care.",
|
description: "Discover our bestselling natural oils for hair and skin care.",
|
||||||
};
|
};
|
||||||
|
|
||||||
function detectLocale(pathname: string, cookieLocale: string | undefined, acceptLanguage: string): Locale {
|
interface NotFoundProps {
|
||||||
// First, check if URL has a locale prefix
|
params?: Promise<{ locale: string }>;
|
||||||
const localeFromPath = getLocaleFromPath(pathname);
|
}
|
||||||
if (pathname.match(/^\/(sr|en|de|fr)/)) {
|
|
||||||
return localeFromPath as Locale;
|
function detectLocaleFromURL(pathname: string): Locale {
|
||||||
|
const match = pathname.match(/^\/(sr|en|de|fr)(?:\/|$)/);
|
||||||
|
if (match && isValidLocale(match[1])) {
|
||||||
|
return match[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Second, check cookie
|
|
||||||
if (cookieLocale && isValidLocale(cookieLocale)) {
|
|
||||||
return cookieLocale;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Third, check accept-language header
|
|
||||||
if (acceptLanguage.includes("en")) {
|
|
||||||
return "en";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default to Serbian
|
|
||||||
return DEFAULT_LOCALE;
|
return DEFAULT_LOCALE;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function NotFoundPage() {
|
export default async function NotFound({ params }: NotFoundProps) {
|
||||||
const headersList = await headers();
|
const headersList = await headers();
|
||||||
const pathname = headersList.get("x-invoke-path") || headersList.get("x-matched-path") || "/";
|
const pathname = headersList.get("x-invoke-path") || headersList.get("x-matched-path") || "/";
|
||||||
const acceptLanguage = headersList.get("accept-language") || "";
|
|
||||||
|
|
||||||
const cookieStore = await cookies();
|
// Try to get locale from params first, then detect from URL
|
||||||
const cookieLocale = cookieStore.get(LOCALE_COOKIE)?.value;
|
let locale: string;
|
||||||
|
|
||||||
const validLocale = detectLocale(pathname, cookieLocale, acceptLanguage);
|
if (params) {
|
||||||
|
const paramsData = await params;
|
||||||
|
locale = paramsData.locale;
|
||||||
|
} else {
|
||||||
|
// Detect from URL path
|
||||||
|
locale = detectLocaleFromURL(pathname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate locale
|
||||||
|
const validLocale: Locale = isValidLocale(locale) ? locale : DEFAULT_LOCALE;
|
||||||
|
|
||||||
const t = await getTranslations({ locale: validLocale, namespace: "NotFound" });
|
const t = await getTranslations({ locale: validLocale, namespace: "NotFound" });
|
||||||
const productReviewT = await getTranslations({ locale: validLocale, namespace: "ProductReviews" });
|
const productReviewT = await getTranslations({ locale: validLocale, namespace: "ProductReviews" });
|
||||||
@@ -68,7 +66,7 @@ export default async function NotFoundPage() {
|
|||||||
// Get first 4 products as bestsellers
|
// Get first 4 products as bestsellers
|
||||||
const bestsellers = products.slice(0, 4);
|
const bestsellers = products.slice(0, 4);
|
||||||
|
|
||||||
// Get product reviews for rotation
|
// Get product reviews
|
||||||
const productReviews = productReviewT.raw("reviews") as Array<{
|
const productReviews = productReviewT.raw("reviews") as Array<{
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -110,7 +108,7 @@ export default async function NotFoundPage() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
{/* Urgency Messages - Static display of first message */}
|
{/* Urgency Messages */}
|
||||||
<div className="bg-gradient-to-r from-amber-50 to-orange-50 border-y border-amber-100 py-3">
|
<div className="bg-gradient-to-r from-amber-50 to-orange-50 border-y border-amber-100 py-3">
|
||||||
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||||
<p className="text-center text-sm sm:text-base text-amber-800 font-medium">
|
<p className="text-center text-sm sm:text-base text-amber-800 font-medium">
|
||||||
@@ -139,10 +137,7 @@ export default async function NotFoundPage() {
|
|||||||
const isAvailable = product.variants?.[0]?.quantityAvailable > 0;
|
const isAvailable = product.variants?.[0]?.quantityAvailable > 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div key={product.id} className="group">
|
||||||
key={product.id}
|
|
||||||
className="group"
|
|
||||||
>
|
|
||||||
<Link href={`/${validLocale}/products/${product.slug}`} className="block">
|
<Link href={`/${validLocale}/products/${product.slug}`} className="block">
|
||||||
<div className="relative w-full aspect-square bg-[#f8f9fa] overflow-hidden mb-4">
|
<div className="relative w-full aspect-square bg-[#f8f9fa] overflow-hidden mb-4">
|
||||||
{image ? (
|
{image ? (
|
||||||
@@ -209,10 +204,7 @@ export default async function NotFoundPage() {
|
|||||||
|
|
||||||
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
{productReviews.slice(0, 6).map((review) => (
|
{productReviews.slice(0, 6).map((review) => (
|
||||||
<div
|
<div key={review.id} className="bg-white rounded-lg p-6 shadow-sm">
|
||||||
key={review.id}
|
|
||||||
className="bg-white rounded-lg p-6 shadow-sm"
|
|
||||||
>
|
|
||||||
<div className="flex gap-1 mb-4">
|
<div className="flex gap-1 mb-4">
|
||||||
{[...Array(5)].map((_, i) => (
|
{[...Array(5)].map((_, i) => (
|
||||||
<Star
|
<Star
|
||||||
Reference in New Issue
Block a user