feat: implement locale-aware routing with [locale] dynamic segments
Some checks failed
Build and Deploy / build (push) Has been cancelled
Some checks failed
Build and Deploy / build (push) Has been cancelled
WARNING: This change breaks existing SEO URLs for Serbian locale. Changes: - Migrated from separate locale folders (src/app/en/, src/app/de/, etc.) to [locale] dynamic segments (src/app/[locale]/) - Serbian is now at /sr/ instead of / (root) - English at /en/, German at /de/, French at /fr/ - All components updated to generate locale-aware links - Root / now redirects to /sr (307 temporary redirect) SEO Impact: - Previously indexed Serbian URLs (/, /products, /about, /contact) will now return 404 or redirect to /sr/* URLs - This is a breaking change for SEO - Serbian pages should ideally remain at root (/) with only non-default locales getting prefix - Consider implementing 301 redirects from old URLs to maintain search engine rankings Technical Notes: - next-intl v4 with [locale] structure requires ALL locales to have the prefix (cannot have default locale at root) - Alternative approach would be separate folder structure per locale
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
import { motion } from "framer-motion";
|
||||
import Image from "next/image";
|
||||
import Link from "next/link";
|
||||
import { useTranslations } from "next-intl";
|
||||
import type { Product } from "@/types/saleor";
|
||||
import { getProductPrice, getProductImage, getLocalizedProduct } from "@/lib/saleor";
|
||||
|
||||
@@ -13,10 +14,12 @@ interface ProductCardProps {
|
||||
}
|
||||
|
||||
export default function ProductCard({ product, index = 0, locale = "SR" }: ProductCardProps) {
|
||||
const t = useTranslations("ProductCard");
|
||||
const image = getProductImage(product);
|
||||
const price = getProductPrice(product);
|
||||
const localized = getLocalizedProduct(product, locale);
|
||||
const isAvailable = product.variants?.[0]?.quantityAvailable > 0;
|
||||
const urlLocale = locale === "SR" ? "sr" : "en";
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
@@ -25,8 +28,7 @@ export default function ProductCard({ product, index = 0, locale = "SR" }: Produ
|
||||
viewport={{ once: true }}
|
||||
transition={{ duration: 0.5, delay: index * 0.1 }}
|
||||
>
|
||||
<Link href={`/products/${localized.slug}`} className="group block">
|
||||
{/* Image Container */}
|
||||
<Link href={`/${urlLocale}/products/${localized.slug}`} className="group block">
|
||||
<div className="relative w-full aspect-square bg-[#f8f9fa] overflow-hidden mb-4">
|
||||
{image ? (
|
||||
<img
|
||||
@@ -37,44 +39,40 @@ export default function ProductCard({ product, index = 0, locale = "SR" }: Produ
|
||||
/>
|
||||
) : (
|
||||
<div className="absolute inset-0 flex items-center justify-center text-[#999999]">
|
||||
<span className="text-sm">No image</span>
|
||||
<span className="text-sm">{t("noImage")}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Out of Stock Overlay */}
|
||||
|
||||
{!isAvailable && (
|
||||
<div className="absolute inset-0 bg-white/80 flex items-center justify-center">
|
||||
<span className="text-sm uppercase tracking-[0.1em] text-[#666666]">
|
||||
{locale === "EN" ? "Out of Stock" : "Nema na stanju"}
|
||||
{t("outOfStock")}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Hover Quick Add (optional) */}
|
||||
<div className="absolute inset-x-0 bottom-0 p-4 translate-y-full group-hover:translate-y-0 transition-transform duration-300">
|
||||
<button
|
||||
<button
|
||||
className="w-full py-3 bg-black text-white text-xs uppercase tracking-[0.1em] hover:bg-[#333333] transition-colors"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
// Quick add functionality can be added here
|
||||
}}
|
||||
>
|
||||
{locale === "EN" ? "Quick Add" : "Dodaj u korpu"}
|
||||
{t("quickAdd")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Product Info */}
|
||||
|
||||
<div className="text-center">
|
||||
<h3 className="text-[15px] font-medium text-[#1a1a1a] mb-1 group-hover:text-[#666666] transition-colors line-clamp-1">
|
||||
{localized.name}
|
||||
</h3>
|
||||
|
||||
|
||||
<p className="text-[14px] text-[#666666]">
|
||||
{price || (locale === "EN" ? "Contact for price" : "Kontaktirajte za cenu")}
|
||||
{price || t("contactForPrice")}
|
||||
</p>
|
||||
</div>
|
||||
</Link>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user