Files
klz-cables.com/lib/seo.ts
2025-12-28 23:28:31 +01:00

130 lines
3.2 KiB
TypeScript

import { Metadata } from 'next';
import { getSiteInfo } from './i18n';
import type { Locale } from './i18n';
export interface SEOParams {
title?: string;
description?: string;
locale?: Locale;
canonical?: string;
ogType?: 'website' | 'article' | 'product';
ogImages?: string[];
publishedTime?: string;
updatedTime?: string;
author?: string;
}
export function generateSEOMetadata({
title,
description,
locale = 'en',
canonical,
ogType = 'website',
ogImages = [],
publishedTime,
updatedTime,
author,
}: SEOParams): Metadata {
const site = getSiteInfo(locale);
const pageTitle = title ? `${title} | ${site.title}` : site.title;
const pageDescription = description || site.description;
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || site.baseUrl;
const path = canonical || '/';
const fullUrl = `${baseUrl}${path}`;
// Generate alternate URLs for both locales
const alternates = {
canonical: fullUrl,
languages: {
'en': `${baseUrl}${path.replace('/de/', '/')}`,
'de': `${baseUrl}${path.startsWith('/de') ? path : `/de${path}`}`,
},
};
const openGraph = {
title: pageTitle,
description: pageDescription,
url: fullUrl,
siteName: site.title,
locale: locale === 'de' ? 'de_DE' : 'en_US',
type: ogType,
...(ogImages.length > 0 && { images: ogImages }),
...(publishedTime && { publishedTime }),
...(updatedTime && { updatedTime }),
...(author && { authors: [author] }),
};
const twitter = {
card: 'summary_large_image',
title: pageTitle,
description: pageDescription,
...(ogImages.length > 0 && { images: ogImages }),
};
return {
title: pageTitle,
description: pageDescription,
alternates,
openGraph,
twitter,
authors: author ? [{ name: author }] : undefined,
metadataBase: new URL(baseUrl),
};
}
// Helper for blog posts
export function getPostSEO(post: any, locale: Locale): Metadata {
return generateSEOMetadata({
title: post.title,
description: post.excerptHtml?.replace(/<[^>]*>/g, '') || '',
canonical: post.path,
locale: locale,
ogType: 'article',
ogImages: post.featuredImage ? [post.featuredImage] : [],
publishedTime: post.datePublished,
updatedTime: post.updatedAt,
author: 'KLZ Cables Team',
});
}
// Helper for products
export function getProductSEO(product: any, locale: Locale): Metadata {
return generateSEOMetadata({
title: product.name,
description: product.shortDescriptionHtml?.replace(/<[^>]*>/g, '') || '',
canonical: product.path,
locale: locale,
ogType: 'product',
ogImages: product.images || [],
});
}
// Helper for categories
export function getCategorySEO(category: any, locale: Locale): Metadata {
return generateSEOMetadata({
title: category.name,
description: category.description || `Products in ${category.name}`,
canonical: category.path,
locale: locale,
ogType: 'website',
});
}
export function generateSitemapItem({
path,
lastmod,
priority = 0.7,
}: {
path: string;
lastmod?: string;
priority?: number;
}) {
return {
url: path,
lastmod: lastmod || new Date().toISOString().split('T')[0],
changefreq: 'weekly',
priority,
};
}