slug i18n

This commit is contained in:
2026-01-20 23:43:01 +01:00
parent f62485a67d
commit abf283c9ab
9 changed files with 267 additions and 42 deletions

View File

@@ -6,6 +6,7 @@ import RelatedProducts from '@/components/RelatedProducts';
import { Badge, Container, Section } from '@/components/ui';
import { getDatasheetPath } from '@/lib/datasheets';
import { getAllProducts, getProductBySlug } from '@/lib/mdx';
import { mapFileSlugToTranslated } from '@/lib/slugs';
import { Metadata } from 'next';
import { getTranslations } from 'next-intl/server';
import { MDXRemote } from 'next-mdx-remote/rsc';
@@ -38,9 +39,9 @@ export async function generateMetadata({ params }: ProductPageProps): Promise<Me
alternates: {
canonical: `/${locale}/products/${productSlug}`,
languages: {
'de': `/de/products/${productSlug}`,
'en': `/en/products/${productSlug}`,
'x-default': `/en/products/${productSlug}`,
'de': `/de/products/${await mapFileSlugToTranslated(productSlug, 'de')}`,
'en': `/en/products/${await mapFileSlugToTranslated(productSlug, 'en')}`,
'x-default': `/en/products/${await mapFileSlugToTranslated(productSlug, 'en')}`,
},
},
openGraph: {
@@ -65,9 +66,9 @@ export async function generateMetadata({ params }: ProductPageProps): Promise<Me
alternates: {
canonical: `/${locale}/products/${slug.join('/')}`,
languages: {
'de': `/de/products/${slug.join('/')}`,
'en': `/en/products/${slug.join('/')}`,
'x-default': `/en/products/${slug.join('/')}`,
'de': `/de/products/${await mapFileSlugToTranslated(slug[0], 'de')}/${await mapFileSlugToTranslated(productSlug, 'de')}`,
'en': `/en/products/${await mapFileSlugToTranslated(slug[0], 'en')}/${await mapFileSlugToTranslated(productSlug, 'en')}`,
'x-default': `/en/products/${await mapFileSlugToTranslated(slug[0], 'en')}/${await mapFileSlugToTranslated(productSlug, 'en')}`,
},
},
openGraph: {
@@ -133,13 +134,21 @@ export default async function ProductPage({ params }: ProductPageProps) {
const categoryTitle = t(`categories.${categoryKey}.title`);
// Filter products for this category
const filteredProducts = allProducts.filter(p =>
p.frontmatter.categories.some(cat =>
cat.toLowerCase().replace(/\s+/g, '-') === productSlug ||
const filteredProducts = allProducts.filter(p =>
p.frontmatter.categories.some(cat =>
cat.toLowerCase().replace(/\s+/g, '-') === productSlug ||
cat === categoryTitle
)
);
// Get translated product slugs
const productsWithTranslatedSlugs = await Promise.all(
filteredProducts.map(async (p) => ({
...p,
translatedSlug: await mapFileSlugToTranslated(p.slug, locale)
}))
);
return (
<div className="flex flex-col min-h-screen bg-white">
<section className="relative min-h-[50vh] flex items-center pt-32 pb-20 overflow-hidden bg-primary-dark">
@@ -161,10 +170,10 @@ export default async function ProductPage({ params }: ProductPageProps) {
<Section className="bg-neutral-light relative">
<Container>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
{filteredProducts.map((product) => (
<Link
key={product.slug}
href={`/${locale}/products/${productSlug}/${product.slug}`}
{productsWithTranslatedSlugs.map((product) => (
<Link
key={product.slug}
href={`/${locale}/products/${productSlug}/${product.translatedSlug}`}
className="group block bg-white rounded-[32px] overflow-hidden shadow-sm hover:shadow-2xl transition-all duration-500 border border-neutral-dark/5"
>
<div className="aspect-[4/3] relative bg-neutral-light/30 p-12 overflow-hidden">