feat: implement i18n for product and category, add 5 new locales

This commit is contained in:
Your Name committed 2026-06-14 00:06:16 -04:00
1 parent 96d874233d
commit 2977df0a9d
8 files changed
+25 -25

No files matched your search

@@ -47,14 +47,14 @@ export default function DynamicCategories({ payload, categories, loading }: Dyna
>
<div className="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent z-10 opacity-80 group-hover:opacity-100 transition-opacity" />
<img
src={cat.imageUrl || getCategoryImage(cat.name)}
src={cat.imageUrl || getCategoryImage(typeof cat.name === 'string' ? cat.name : (cat.name as any)?.en || '')}
className="absolute inset-0 w-full h-full object-cover group-hover:scale-105 transition-transform duration-700"
alt={cat.name}
alt={typeof cat.name === 'string' ? cat.name : (cat.name as any)?.en || ''}
onError={(e) => { (e.target as HTMLImageElement).style.display = 'none' }}
/>
<div className="absolute bottom-6 left-6 right-6 z-20 text-white">
<span className="font-semibold text-xl block mb-1">
{cat.name}
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[localStorage.getItem('homaroma_lang') || 'en'] || (cat.name as any)?.en || ''}
</span>
{cat._count && (
<span className="text-sm font-medium text-white/80">
+1 -1
View File
@@ -93,7 +93,7 @@ export default function Footer({ categories = [] }: FooterProps) {
<div className="flex flex-col space-y-2 text-sm text-slate-400">
{categories.map((c) => (
<Link key={c.id} to={`/category/${c.id}`} className="hover:text-white transition-colors">
{c.name}
{typeof c.name === 'string' ? c.name : (c.name as any)?.[localStorage.getItem('homaroma_lang') || 'en'] || (c.name as any)?.en || ''}
</Link>
))}
</div>
+3 -3
View File
@@ -158,7 +158,7 @@ export default function Navbar({ categories = [], topOffsetClassName = 'top-0' }
to={`/category/${cat.id}`}
className="flex items-center justify-between px-4 py-2.5 text-xs uppercase tracking-widest text-spa-stone rounded-lg hover:bg-spa-sage hover:text-spa-forest transition-colors"
>
{cat.name}
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''}
<svg className="w-3 h-3 opacity-30" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
@@ -456,7 +456,7 @@ export default function Navbar({ categories = [], topOffsetClassName = 'top-0' }
onClick={() => setMobileOpen(false)}
className="flex items-center justify-between px-4 py-2.5 rounded-xl text-sm text-spa-stone hover:text-spa-forest hover:bg-spa-sage transition-all"
>
{cat.name}
{typeof cat.name === 'string' ? cat.name : (cat.name as any)?.[i18n.language] || (cat.name as any)?.en || ''}
<svg className="w-3 h-3 text-spa-stone/40" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
@@ -541,7 +541,7 @@ export default function Navbar({ categories = [], topOffsetClassName = 'top-0' }
<p className="text-xs text-spa-stone/60 uppercase tracking-widest mb-3 font-semibold">Quick Links</p>
<div className="flex flex-wrap gap-2">
{[
...categories.map(c => ({ label: c.name, to: `/category/${c.id}` })),
...categories.map(c => ({ label: typeof c.name === 'string' ? c.name : (c.name as any)?.[i18n.language] || (c.name as any)?.en || '', to: `/category/${c.id}` })),
{ label: '✨ Scent Guide', to: '/scent-guide' },
{ label: 'All Products', to: '/shop' },
].map(item => (
+4 -4
View File
@@ -49,7 +49,7 @@ export default function ProductCard({ product, enableQuickShop = false }: Produc
{/* Image Area */}
<div className="h-48 md:h-64 overflow-hidden rounded-xl relative bg-spa-sage/20">
<img
src={product.images?.[0]?.url || getCategoryImage(product.category.name)}
src={product.images?.[0]?.url || getCategoryImage(typeof product.category.name === 'string' ? product.category.name : (product.category.name as any)?.en || '')}
className="w-full h-full object-cover group-hover:scale-105 transition-transform duration-700"
alt={product.scent.name}
onError={(e) => {
@@ -58,7 +58,7 @@ export default function ProductCard({ product, enableQuickShop = false }: Produc
/>
{/* Category badge */}
<div className="absolute top-3 left-3 bg-white/90 backdrop-blur-sm px-2.5 py-1 rounded-md text-[10px] font-bold uppercase tracking-widest text-spa-forest shadow-sm">
{product.category.name}
{typeof product.category.name === 'string' ? product.category.name : (product.category.name as any)?.[i18n.language] || (product.category.name as any)?.en || ''}
</div>
{/* Wishlist Button */}
<button
@@ -79,7 +79,7 @@ export default function ProductCard({ product, enableQuickShop = false }: Produc
{displayName}
</h3>
<p className="text-[10px] md:text-xs text-spa-stone/60 mt-1 uppercase tracking-widest line-clamp-1 font-semibold">
{product.category.name}
{typeof product.category.name === 'string' ? product.category.name : (product.category.name as any)?.[i18n.language] || (product.category.name as any)?.en || ''}
</p>
</div>
@@ -136,7 +136,7 @@ export default function ProductCard({ product, enableQuickShop = false }: Produc
price: selectedVariant.price || 0,
productName: displayName,
variantSize: selectedVariant.size,
productImage: product.images?.[0]?.url || getCategoryImage(product.category.name)
productImage: product.images?.[0]?.url || getCategoryImage(typeof product.category.name === 'string' ? product.category.name : (product.category.name as any)?.en || '')
});
}}
className="w-full py-2.5 bg-spa-forest text-white hover:bg-spa-forest/90 rounded-xl font-bold text-xs uppercase tracking-widest transition-all shadow-sm hover:shadow flex items-center justify-center gap-1.5 cursor-pointer"