This commit is contained in:
@@ -2,11 +2,15 @@ import Footer from '@/components/Footer';
|
||||
import Header from '@/components/Header';
|
||||
import JsonLd from '@/components/JsonLd';
|
||||
import AnalyticsProvider from '@/components/analytics/AnalyticsProvider';
|
||||
import { Viewport } from 'next';
|
||||
import { Metadata, Viewport } from 'next';
|
||||
import { NextIntlClientProvider } from 'next-intl';
|
||||
import { getMessages } from 'next-intl/server';
|
||||
import '../../styles/globals.css';
|
||||
import { SITE_URL } from '@/lib/schema';
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(SITE_URL),
|
||||
};
|
||||
|
||||
export const viewport: Viewport = {
|
||||
width: 'device-width',
|
||||
|
||||
62
app/[locale]/products/[...slug]/opengraph-image.tsx
Normal file
62
app/[locale]/products/[...slug]/opengraph-image.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { ImageResponse } from 'next/og';
|
||||
import { getProductBySlug } from '@/lib/mdx';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { OGImageTemplate } from '@/components/OGImageTemplate';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
|
||||
export default async function Image({ params: { locale, slug } }: { params: { locale: string, slug: string[] } }) {
|
||||
const t = await getTranslations('Products');
|
||||
const productSlug = slug[slug.length - 1];
|
||||
|
||||
// Check if it's a category page
|
||||
const categories = ['low-voltage-cables', 'medium-voltage-cables', 'high-voltage-cables', 'solar-cables'];
|
||||
if (categories.includes(productSlug)) {
|
||||
const categoryKey = productSlug.replace(/-cables$/, '').replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
||||
const categoryTitle = t.has(`categories.${categoryKey}.title`) ? t(`categories.${categoryKey}.title`) : productSlug;
|
||||
const categoryDesc = t.has(`categories.${categoryKey}.description`) ? t(`categories.${categoryKey}.description`) : '';
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<OGImageTemplate
|
||||
title={categoryTitle}
|
||||
description={categoryDesc}
|
||||
label="Product Category"
|
||||
/>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const product = await getProductBySlug(productSlug, locale);
|
||||
|
||||
if (!product) {
|
||||
return new ImageResponse(
|
||||
<div style={{ display: 'flex', width: '100%', height: '100%', backgroundColor: '#001a4d' }} />
|
||||
);
|
||||
}
|
||||
|
||||
const featuredImage = product.frontmatter.images?.[0]
|
||||
? (product.frontmatter.images[0].startsWith('http')
|
||||
? product.frontmatter.images[0]
|
||||
: `https://klz-cables.com${product.frontmatter.images[0]}`)
|
||||
: undefined;
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<OGImageTemplate
|
||||
title={product.frontmatter.title}
|
||||
description={product.frontmatter.description}
|
||||
label={product.frontmatter.categories?.[0] || 'Product'}
|
||||
image={featuredImage}
|
||||
/>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -5,10 +5,31 @@ import { OGImageTemplate } from '@/components/OGImageTemplate';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
|
||||
export default async function Image({ params: { locale, slug } }: { params: { locale: string, slug: string[] } }) {
|
||||
const productSlug = slug[slug.length - 1];
|
||||
export default async function Image({ params: { locale, slug } }: { params: { locale: string, slug?: string[] } }) {
|
||||
const t = await getTranslations('Products');
|
||||
|
||||
// If no slug, it's the main products page
|
||||
if (!slug || slug.length === 0) {
|
||||
const title = t('meta.title') || t('title');
|
||||
const description = t('meta.description') || t('subtitle');
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<OGImageTemplate
|
||||
title={title}
|
||||
description={description}
|
||||
label="Products"
|
||||
/>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const productSlug = slug[slug.length - 1];
|
||||
|
||||
// Check if it's a category page
|
||||
const categories = ['low-voltage-cables', 'medium-voltage-cables', 'high-voltage-cables', 'solar-cables'];
|
||||
if (categories.includes(productSlug)) {
|
||||
|
||||
@@ -159,26 +159,69 @@ function guessColumnKey(row: ExcelRow, patterns: RegExp[]): string | null {
|
||||
}
|
||||
|
||||
function technicalFullLabel(args: { key: string; excelKey: string; locale: 'en' | 'de' }): string {
|
||||
if (args.locale === 'en') return normalizeValue(args.excelKey);
|
||||
const raw = normalizeValue(args.excelKey);
|
||||
if (!raw) return '';
|
||||
|
||||
if (args.locale === 'de') {
|
||||
return raw
|
||||
.replace(/\(approx\.?\)/gi, '(ca.)')
|
||||
.replace(/\bconductor material\b/gi, 'Leitermaterial')
|
||||
.replace(/\bconductor class\b/gi, 'Leiterklasse')
|
||||
.replace(/\bcore insulation\b/gi, 'Aderisolation')
|
||||
.replace(/\binsulation\b/gi, 'Aderisolation')
|
||||
.replace(/\bfield control\b/gi, 'Feldsteuerung')
|
||||
.replace(/\bscreen\b/gi, 'Schirm')
|
||||
.replace(/\blongitudinal water tightness\b/gi, 'Längswasserdichtigkeit')
|
||||
.replace(/\btransverse water tightness\b/gi, 'Querwasserdichtigkeit')
|
||||
.replace(/\bsheath material\b/gi, 'Mantelmaterial')
|
||||
.replace(/\bsheath color\b/gi, 'Mantelfarbe')
|
||||
.replace(/\bflame retardancy\b/gi, 'Flammwidrigkeit')
|
||||
.replace(/\buv resistant\b/gi, 'UV-bestandig')
|
||||
.replace(/\bmax\.? permissible conductor temperature\b/gi, 'Max. zulässige Leitertemperatur')
|
||||
.replace(/\bpermissible cable outer temperature, fixed\b/gi, 'Zul. Kabelaußentemperatur, fest verlegt')
|
||||
.replace(/\bpermissible cable outer temperature, in motion\b/gi, 'Zul. Kabelaußentemperatur, in Bewegung')
|
||||
.replace(/\bmaximum short-circuit temperature\b/gi, 'Maximale Kurzschlußtemperatur')
|
||||
.replace(/\bmin\.? bending radius, fixed\b/gi, 'Min. Biegeradius, fest verlegt')
|
||||
.replace(/\bminimum laying temperature\b/gi, 'Mindesttemperatur Verlegung')
|
||||
.replace(/\bmeter marking\b/gi, 'Metermarkierung')
|
||||
.replace(/\bpartial discharge\b/gi, 'Teilentladung')
|
||||
.replace(/\bcapacitance\b/gi, 'Kapazität')
|
||||
.replace(/\binductance\b/gi, 'Induktivität')
|
||||
.replace(/\breactance\b/gi, 'Reaktanz')
|
||||
.replace(/\btest voltage\b/gi, 'Prüfspannung')
|
||||
.replace(/\brated voltage\b/gi, 'Nennspannung')
|
||||
.replace(/\boperating temperature range\b/gi, 'Temperaturbereich')
|
||||
.replace(/\bminimum sheath thickness\b/gi, 'Manteldicke (min.)')
|
||||
.replace(/\bsheath thickness\b/gi, 'Manteldicke')
|
||||
.replace(/\bnominal insulation thickness\b/gi, 'Isolationsdicke (nom.)')
|
||||
.replace(/\binsulation thickness\b/gi, 'Isolationsdicke')
|
||||
.replace(/\bdc resistance at 20\s*°?c\b/gi, 'DC-Leiterwiderstand (20 °C)')
|
||||
.replace(/\bouter diameter(?: of cable)?\b/gi, 'Außen-Ø')
|
||||
.replace(/\bbending radius\b/gi, 'Biegeradius')
|
||||
.replace(/\bpackaging\b/gi, 'Verpackung')
|
||||
.replace(/\bce\s*-?conformity\b/gi, 'CE-Konformität');
|
||||
}
|
||||
|
||||
return raw
|
||||
.replace(/\(approx\.?\)/gi, '(ca.)')
|
||||
.replace(/\bcapacitance\b/gi, 'Kapazität')
|
||||
.replace(/\binductance\b/gi, 'Induktivität')
|
||||
.replace(/\breactance\b/gi, 'Reaktanz')
|
||||
.replace(/\btest voltage\b/gi, 'Prüfspannung')
|
||||
.replace(/\brated voltage\b/gi, 'Nennspannung')
|
||||
.replace(/\boperating temperature range\b/gi, 'Temperaturbereich')
|
||||
.replace(/\bminimum sheath thickness\b/gi, 'Manteldicke (min.)')
|
||||
.replace(/\bsheath thickness\b/gi, 'Manteldicke')
|
||||
.replace(/\bnominal insulation thickness\b/gi, 'Isolationsdicke (nom.)')
|
||||
.replace(/\binsulation thickness\b/gi, 'Isolationsdicke')
|
||||
.replace(/\bdc resistance at 20\s*°?c\b/gi, 'DC-Leiterwiderstand (20 °C)')
|
||||
.replace(/\bouter diameter(?: of cable)?\b/gi, 'Außen-Ø')
|
||||
.replace(/\bbending radius\b/gi, 'Biegeradius')
|
||||
.replace(/\bpackaging\b/gi, 'Verpackung')
|
||||
.replace(/\bce\s*-?conformity\b/gi, 'CE-Konformität');
|
||||
.replace(/\bconductor material\b/gi, 'Conductor material')
|
||||
.replace(/\bconductor class\b/gi, 'Conductor class')
|
||||
.replace(/\bcore insulation\b/gi, 'Core insulation')
|
||||
.replace(/\bfield control\b/gi, 'Field control')
|
||||
.replace(/\bscreen\b/gi, 'Screen')
|
||||
.replace(/\blongitudinal water tightness\b/gi, 'Longitudinal water tightness')
|
||||
.replace(/\btransverse water tightness\b/gi, 'Transverse water tightness')
|
||||
.replace(/\bsheath material\b/gi, 'Sheath material')
|
||||
.replace(/\bsheath color\b/gi, 'Sheath color')
|
||||
.replace(/\bflame retardancy\b/gi, 'Flame retardancy')
|
||||
.replace(/\buv resistant\b/gi, 'UV resistant')
|
||||
.replace(/\bmax\.? permissible conductor temperature\b/gi, 'Max. permissible conductor temperature')
|
||||
.replace(/\bpermissible cable outer temperature, fixed\b/gi, 'Permissible cable outer temperature, fixed')
|
||||
.replace(/\bpermissible cable outer temperature, in motion\b/gi, 'Permissible cable outer temperature, in motion')
|
||||
.replace(/\bmaximum short-circuit temperature\b/gi, 'Maximum short-circuit temperature')
|
||||
.replace(/\bmin\.? bending radius, fixed\b/gi, 'Min. bending radius, fixed')
|
||||
.replace(/\bminimum laying temperature\b/gi, 'Minimum laying temperature')
|
||||
.replace(/\bmeter marking\b/gi, 'Meter marking')
|
||||
.replace(/\bpartial discharge\b/gi, 'Partial discharge');
|
||||
}
|
||||
|
||||
function metaFullLabel(args: { key: string; excelKey: string; locale: 'en' | 'de' }): string {
|
||||
@@ -507,6 +550,26 @@ function buildExcelModel(args: { product: ProductData; locale: 'en' | 'de' }): B
|
||||
'flame retardant': { header: 'Flame retardant', unit: '', key: 'flame' },
|
||||
'self-extinguishing of single cable': { header: 'Flame retardant', unit: '', key: 'flame' },
|
||||
|
||||
'conductor material': { header: 'Conductor material', unit: '', key: 'cond_mat' },
|
||||
'conductor class': { header: 'Conductor class', unit: '', key: 'cond_class' },
|
||||
'core insulation': { header: 'Core insulation', unit: '', key: 'core_ins' },
|
||||
'field control': { header: 'Field control', unit: '', key: 'field_ctrl' },
|
||||
'screen': { header: 'Screen', unit: '', key: 'screen' },
|
||||
'longitudinal water tightness': { header: 'Longitudinal water tightness', unit: '', key: 'long_water' },
|
||||
'transverse water tightness': { header: 'Transverse water tightness', unit: '', key: 'trans_water' },
|
||||
'sheath material': { header: 'Sheath material', unit: '', key: 'sheath_mat' },
|
||||
'sheath color': { header: 'Sheath color', unit: '', key: 'sheath_color' },
|
||||
'flame retardancy': { header: 'Flame retardancy', unit: '', key: 'flame_ret' },
|
||||
'uv resistant': { header: 'UV resistant', unit: '', key: 'uv_res' },
|
||||
'max. permissible conductor temperature': { header: 'Max. permissible conductor temperature', unit: '°C', key: 'max_cond_temp' },
|
||||
'permissible cable outer temperature, fixed': { header: 'Permissible cable outer temperature, fixed', unit: '°C', key: 'out_temp_fixed' },
|
||||
'permissible cable outer temperature, in motion': { header: 'Permissible cable outer temperature, in motion', unit: '°C', key: 'out_temp_motion' },
|
||||
'maximum short-circuit temperature': { header: 'Maximum short-circuit temperature', unit: '°C', key: 'max_sc_temp_val' },
|
||||
'min. bending radius, fixed': { header: 'Min. bending radius, fixed', unit: '', key: 'min_bend_fixed' },
|
||||
'minimum laying temperature': { header: 'Minimum laying temperature', unit: '°C', key: 'min_lay_temp_val' },
|
||||
'meter marking': { header: 'Meter marking', unit: '', key: 'meter_mark' },
|
||||
'partial discharge': { header: 'Partial discharge', unit: 'pC', key: 'partial_dis' },
|
||||
|
||||
// High-value electrical/screen columns
|
||||
'capacitance (approx.)': { header: 'Capacitance', unit: 'uF/km', key: 'cap' },
|
||||
'capacitance': { header: 'Capacitance', unit: 'uF/km', key: 'cap' },
|
||||
@@ -892,7 +955,20 @@ export function buildDatasheetModel(args: { product: ProductData; locale: 'en' |
|
||||
productUrl,
|
||||
},
|
||||
labels,
|
||||
technicalItems: excelModel.ok ? excelModel.technicalItems : [],
|
||||
technicalItems: [
|
||||
...(excelModel.ok ? excelModel.technicalItems : []),
|
||||
...(args.locale === 'de'
|
||||
? [
|
||||
{ label: 'Prüfspannung 6/10 kV', value: '21 kV' },
|
||||
{ label: 'Prüfspannung 12/20 kV', value: '42 kV' },
|
||||
{ label: 'Prüfspannung 18/30 kV', value: '63 kV' },
|
||||
]
|
||||
: [
|
||||
{ label: 'Test voltage 6/10 kV', value: '21 kV' },
|
||||
{ label: 'Test voltage 12/20 kV', value: '42 kV' },
|
||||
{ label: 'Test voltage 18/30 kV', value: '63 kV' },
|
||||
]),
|
||||
],
|
||||
voltageTables,
|
||||
legendItems: crossSectionModel.legendItems || [],
|
||||
};
|
||||
|
||||
@@ -53,18 +53,18 @@ export function generateFileName(product: ProductData, locale: 'en' | 'de'): str
|
||||
export function getLabels(locale: 'en' | 'de') {
|
||||
return {
|
||||
en: {
|
||||
datasheet: 'PRODUCT DATASHEET',
|
||||
datasheet: 'Technical Datasheet',
|
||||
description: 'DESCRIPTION',
|
||||
technicalData: 'TECHNICAL DATA',
|
||||
crossSection: 'CROSS-SECTION DATA',
|
||||
crossSection: 'Cross-sections/Voltage',
|
||||
sku: 'SKU',
|
||||
noImage: 'No image available',
|
||||
},
|
||||
de: {
|
||||
datasheet: 'PRODUKTDATENBLATT',
|
||||
datasheet: 'Technisches Datenblatt',
|
||||
description: 'BESCHREIBUNG',
|
||||
technicalData: 'TECHNISCHE DATEN',
|
||||
crossSection: 'QUERSCHNITTSDATEN',
|
||||
crossSection: 'Querschnitte/Spannung',
|
||||
sku: 'ARTIKELNUMMER',
|
||||
noImage: 'Kein Bild verfügbar',
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user