Compare commits
2 Commits
0b81d1a4cb
...
bb7d17001b
| Author | SHA1 | Date | |
|---|---|---|---|
| bb7d17001b | |||
| 920efa0083 |
@@ -2,18 +2,29 @@ import { ImageResponse } from 'next/og';
|
||||
import { getProductBySlug } from '@/lib/mdx';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { OGImageTemplate } from '@/components/OGImageTemplate';
|
||||
import { NextRequest } from 'next/server';
|
||||
|
||||
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];
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: { locale: string } }
|
||||
) {
|
||||
const { searchParams } = new URL(request.url);
|
||||
const slug = searchParams.get('slug');
|
||||
const locale = params.locale || 'en';
|
||||
|
||||
if (!slug) {
|
||||
return new Response('Missing slug', { status: 400 });
|
||||
}
|
||||
|
||||
const t = await getTranslations({ locale, namespace: 'Products' });
|
||||
|
||||
// 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;
|
||||
if (categories.includes(slug)) {
|
||||
const categoryKey = slug.replace(/-cables$/, '').replace(/-([a-z])/g, (g) => g[1].toUpperCase());
|
||||
const categoryTitle = t.has(`categories.${categoryKey}.title`) ? t(`categories.${categoryKey}.title`) : slug;
|
||||
const categoryDesc = t.has(`categories.${categoryKey}.description`) ? t(`categories.${categoryKey}.description`) : '';
|
||||
|
||||
return new ImageResponse(
|
||||
@@ -31,7 +42,7 @@ export default async function Image({ params: { locale, slug } }: { params: { lo
|
||||
);
|
||||
}
|
||||
|
||||
const product = await getProductBySlug(productSlug, locale);
|
||||
const product = await getProductBySlug(slug, locale);
|
||||
|
||||
if (!product) {
|
||||
return new ImageResponse(
|
||||
25
app/[locale]/blog/opengraph-image.tsx
Normal file
25
app/[locale]/blog/opengraph-image.tsx
Normal file
@@ -0,0 +1,25 @@
|
||||
import { ImageResponse } from 'next/og';
|
||||
import { getTranslations } from 'next-intl/server';
|
||||
import { OGImageTemplate } from '@/components/OGImageTemplate';
|
||||
|
||||
export const runtime = 'nodejs';
|
||||
|
||||
export default async function Image({ params: { locale } }: { params: { locale: string } }) {
|
||||
const t = await getTranslations({ locale, namespace: 'Blog.meta' });
|
||||
const title = t('title');
|
||||
const description = t('description');
|
||||
|
||||
return new ImageResponse(
|
||||
(
|
||||
<OGImageTemplate
|
||||
title={title}
|
||||
description={description}
|
||||
label="Blog"
|
||||
/>
|
||||
),
|
||||
{
|
||||
width: 1200,
|
||||
height: 630,
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -51,6 +51,14 @@ export async function generateMetadata({ params }: ProductPageProps): Promise<Me
|
||||
title: `${categoryTitle} | KLZ Cables`,
|
||||
description: categoryDesc,
|
||||
url: `https://klz-cables.com/${locale}/products/${productSlug}`,
|
||||
images: [
|
||||
{
|
||||
url: `/api/og/product?slug=${fileSlug}`,
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: categoryTitle,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
@@ -79,6 +87,14 @@ export async function generateMetadata({ params }: ProductPageProps): Promise<Me
|
||||
description: product.frontmatter.description,
|
||||
type: 'website',
|
||||
url: `https://klz-cables.com/${locale}/products/${slug.join('/')}`,
|
||||
images: [
|
||||
{
|
||||
url: `/api/og/product?slug=${productSlug}`,
|
||||
width: 1200,
|
||||
height: 630,
|
||||
alt: product.frontmatter.title,
|
||||
},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
|
||||
@@ -206,6 +206,7 @@ function technicalFullLabel(args: { key: string; excelKey: string; locale: 'en'
|
||||
.replace(/\bconductor material\b/gi, 'Conductor material')
|
||||
.replace(/\bconductor class\b/gi, 'Conductor class')
|
||||
.replace(/\bcore insulation\b/gi, 'Core insulation')
|
||||
.replace(/\binsulation\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')
|
||||
@@ -221,7 +222,49 @@ function technicalFullLabel(args: { key: string; excelKey: string; locale: 'en'
|
||||
.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');
|
||||
.replace(/\bpartial discharge\b/gi, 'Partial discharge')
|
||||
.replace(/\bcapacitance\b/gi, 'Capacitance')
|
||||
.replace(/\binductance\b/gi, 'Inductance')
|
||||
.replace(/\breactance\b/gi, 'Reactance')
|
||||
.replace(/\btest voltage\b/gi, 'Test voltage')
|
||||
.replace(/\brated voltage\b/gi, 'Rated voltage')
|
||||
.replace(/\boperating temperature range\b/gi, 'Operating temperature range')
|
||||
.replace(/\bminimum sheath thickness\b/gi, 'Sheath thickness (min.)')
|
||||
.replace(/\bsheath thickness\b/gi, 'Sheath thickness')
|
||||
.replace(/\bnominal insulation thickness\b/gi, 'Insulation thickness (nom.)')
|
||||
.replace(/\binsulation thickness\b/gi, 'Insulation thickness')
|
||||
.replace(/\bdc resistance at 20\s*°?c\b/gi, 'DC resistance (20 °C)')
|
||||
.replace(/\bouter diameter(?: of cable)?\b/gi, 'Outer diameter')
|
||||
.replace(/\bbending radius\b/gi, 'Bending radius')
|
||||
.replace(/\bpackaging\b/gi, 'Packaging')
|
||||
.replace(/\bce\s*-?conformity\b/gi, 'CE conformity');
|
||||
}
|
||||
|
||||
function technicalValueTranslation(args: { label: string; value: string; locale: 'en' | 'de' }): string {
|
||||
const v = normalizeValue(args.value);
|
||||
if (!v) return '';
|
||||
|
||||
if (args.locale === 'de') {
|
||||
if (/^yes$/i.test(v)) return 'ja';
|
||||
if (/^no$/i.test(v)) return 'nein';
|
||||
if (/^copper$/i.test(v)) return 'Kupfer';
|
||||
if (/^aluminum$/i.test(v)) return 'Aluminium';
|
||||
if (/^black$/i.test(v)) return 'schwarz';
|
||||
if (/^stranded$/i.test(v)) return 'mehrdrähtig';
|
||||
if (/^(\d+)xD$/i.test(v)) return v.replace(/^(\d+)xD$/i, '$1 facher Durchmesser');
|
||||
if (/^XLPE/i.test(v)) return v.replace(/^XLPE/i, 'VPE');
|
||||
return v;
|
||||
}
|
||||
|
||||
if (/^ja$/i.test(v)) return 'yes';
|
||||
if (/^nein$/i.test(v)) return 'no';
|
||||
if (/^kupfer$/i.test(v)) return 'Copper';
|
||||
if (/^aluminium$/i.test(v)) return 'Aluminum';
|
||||
if (/^schwarz$/i.test(v)) return 'black';
|
||||
if (/^mehrdrähtig$/i.test(v)) return 'stranded';
|
||||
if (/^(\d+)xD$/i.test(v)) return v.replace(/^(\d+)xD$/i, '$1 times diameter');
|
||||
if (/^VPE/i.test(v)) return v.replace(/^VPE/i, 'XLPE');
|
||||
return v;
|
||||
}
|
||||
|
||||
function metaFullLabel(args: { key: string; excelKey: string; locale: 'en' | 'de' }): string {
|
||||
@@ -642,11 +685,66 @@ function buildExcelModel(args: { product: ProductData; locale: 'en' | 'de' }): B
|
||||
const unit = normalizeUnit(units[excelKey] || mapping.unit || '');
|
||||
const labelBase = technicalFullLabel({ key: mapping.key, excelKey, locale: args.locale });
|
||||
const label = formatExcelHeaderLabel(labelBase, unit);
|
||||
const value = compactCellForDenseTable(values[0], unit, args.locale);
|
||||
const rawValue = compactCellForDenseTable(values[0], unit, args.locale);
|
||||
const value = technicalValueTranslation({ label: labelBase, value: rawValue, locale: args.locale });
|
||||
if (!technicalItems.find(t => t.label === label)) technicalItems.push({ label, value, unit });
|
||||
}
|
||||
}
|
||||
technicalItems.sort((a, b) => a.label.localeCompare(b.label));
|
||||
const TECHNICAL_DATA_ORDER_DE = [
|
||||
'Leitermaterial',
|
||||
'Leiterklasse',
|
||||
'Aderisolation',
|
||||
'Feldsteuerung',
|
||||
'Schirm',
|
||||
'Längswasserdichtigkeit',
|
||||
'Querwasserdichtigkeit',
|
||||
'Mantelmaterial',
|
||||
'Mantelfarbe',
|
||||
'Flammwidrigkeit',
|
||||
'UV-bestandig',
|
||||
'Max. zulässige Leitertemperatur',
|
||||
'Zul. Kabelaußentemperatur, fest verlegt',
|
||||
'Zul. Kabelaußentemperatur, in Bewegung',
|
||||
'Maximale Kurzschlußtemperatur',
|
||||
'Min. Biegeradius, fest verlegt',
|
||||
'Mindesttemperatur Verlegung',
|
||||
'Metermarkierung',
|
||||
'Teilentladung',
|
||||
];
|
||||
|
||||
const TECHNICAL_DATA_ORDER_EN = [
|
||||
'Conductor material',
|
||||
'Conductor class',
|
||||
'Core insulation',
|
||||
'Field control',
|
||||
'Screen',
|
||||
'Longitudinal water tightness',
|
||||
'Transverse water tightness',
|
||||
'Sheath material',
|
||||
'Sheath color',
|
||||
'Flame retardancy',
|
||||
'UV resistant',
|
||||
'Max. permissible conductor temperature',
|
||||
'Permissible cable outer temperature, fixed',
|
||||
'Permissible cable outer temperature, in motion',
|
||||
'Maximum short-circuit temperature',
|
||||
'Min. bending radius, fixed',
|
||||
'Minimum laying temperature',
|
||||
'Meter marking',
|
||||
'Partial discharge',
|
||||
];
|
||||
|
||||
const order = args.locale === 'de' ? TECHNICAL_DATA_ORDER_DE : TECHNICAL_DATA_ORDER_EN;
|
||||
|
||||
technicalItems.sort((a, b) => {
|
||||
const indexA = order.findIndex(label => a.label.startsWith(label));
|
||||
const indexB = order.findIndex(label => b.label.startsWith(label));
|
||||
|
||||
if (indexA !== -1 && indexB !== -1) return indexA - indexB;
|
||||
if (indexA !== -1) return -1;
|
||||
if (indexB !== -1) return 1;
|
||||
return a.label.localeCompare(b.label);
|
||||
});
|
||||
|
||||
const voltageTables: VoltageTableModel[] = [];
|
||||
for (const vKey of voltageKeysSorted) {
|
||||
@@ -957,17 +1055,19 @@ export function buildDatasheetModel(args: { product: ProductData; locale: 'en' |
|
||||
labels,
|
||||
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' },
|
||||
]),
|
||||
...(isMediumVoltageProduct(args.product)
|
||||
? 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 || [],
|
||||
|
||||
Reference in New Issue
Block a user