Compare commits

...
Author SHA1 Message Date
mmintel a9f16b49cc fix(performance): disable inlineCss to reduce HTML size from 557KB to 162KB and fix FCP fluctuations
Build & Deploy / 🔍 Prepare (push) Successful in 57s
Build & Deploy / 🧪 QA (push) Successful in 1m18s
Build & Deploy / 🏗️ Build (push) Successful in 2m41s
Build & Deploy / 🚀 Deploy (push) Successful in 27s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-02 12:26:05 +02:00
mmintel 21cf0725ab release: v2.4.5
Build & Deploy / 🔍 Prepare (push) Successful in 22s
Build & Deploy / 🚀 Deploy (push) Successful in 25s
Build & Deploy / 🧪 QA (push) Successful in 1m21s
Build & Deploy / 🏗️ Build (push) Successful in 2m33s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 53s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-02 10:29:32 +02:00
mmintel 2c162f5314 perf: completely fix non-composited animations, eliminate shutter unused JS, and aggressively compress images 2026-07-02 10:29:31 +02:00
mmintel be3b2e6a7b release: v2.4.4
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 50s
Build & Deploy / 🧪 QA (push) Successful in 1m18s
Build & Deploy / 🏗️ Build (push) Successful in 2m31s
Build & Deploy / 🚀 Deploy (push) Successful in 25s
Build & Deploy / 🔔 Notify (push) Successful in 4s
2026-07-01 18:23:50 +02:00
mmintel f2e59fa52f perf: fix sizes attribute scaling bug to prevent mobile devices from downloading 1920w desktop images 2026-07-01 18:23:50 +02:00
mmintel 16d494689f release: v2.4.3
Build & Deploy / 🔍 Prepare (push) Successful in 20s
Build & Deploy / 🧪 QA (push) Successful in 1m15s
Build & Deploy / 🏗️ Build (push) Successful in 2m26s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 52s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-01 18:21:25 +02:00
mmintel d24b8a8694 perf: prevent bandwidth theft from non-critical preloads and strip InitialLoader chunk 2026-07-01 18:21:25 +02:00
mmintel 8d42946711 release: v2.4.2
Build & Deploy / 🔍 Prepare (push) Successful in 22s
Build & Deploy / 🚀 Deploy (push) Successful in 28s
Build & Deploy / 🧪 QA (push) Successful in 1m17s
Build & Deploy / 🏗️ Build (push) Successful in 2m44s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 50s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-01 18:11:33 +02:00
mmintel b15217b9be content: update Hochspannung wording per WhatsApp screenshot 2026-07-01 18:11:33 +02:00
mmintel b138025380 release: v2.4.1
Build & Deploy / 🔍 Prepare (push) Successful in 22s
Build & Deploy / 🧪 QA (push) Successful in 1m16s
Build & Deploy / 🏗️ Build (push) Successful in 2m11s
Build & Deploy / 🚀 Deploy (push) Successful in 38s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 48s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-01 17:19:41 +02:00
mmintel 18d2ace03b perf: compress hero image and defer page transition shutter
Build & Deploy / 🔍 Prepare (push) Has been cancelled
Build & Deploy / 🧪 QA (push) Has been cancelled
Build & Deploy / 🏗️ Build (push) Has been cancelled
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
2026-07-01 17:19:35 +02:00
mmintel 89ed1faa6b release: v2.4.0
Build & Deploy / 🔍 Prepare (push) Successful in 21s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 48s
Build & Deploy / 🧪 QA (push) Successful in 1m15s
Build & Deploy / 🏗️ Build (push) Successful in 2m7s
Build & Deploy / 🚀 Deploy (push) Successful in 24s
Build & Deploy / 🔔 Notify (push) Successful in 2s
2026-07-01 15:30:55 +02:00
mmintel 7307e812a4 release: v2.2.96 2026-07-01 15:30:49 +02:00
mmintel 20d6194a7e perf: fix massive LCP render delay and TTFB on Home page
Build & Deploy / 🧪 QA (push) Has been cancelled
Build & Deploy / 🏗️ Build (push) Has been cancelled
Build & Deploy / 🚀 Deploy (push) Has been cancelled
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been cancelled
Build & Deploy / 🔔 Notify (push) Has been cancelled
Build & Deploy / 🔍 Prepare (push) Has been cancelled
2026-07-01 15:30:28 +02:00
mmintel 86e2fd7097 2.2.95
Build & Deploy / 🔍 Prepare (push) Successful in 21s
Build & Deploy / 🧪 QA (push) Successful in 1m13s
Build & Deploy / 🏗️ Build (push) Successful in 2m14s
Build & Deploy / 🚀 Deploy (push) Successful in 25s
Build & Deploy / 🧪 Post-Deploy Verification (push) Successful in 49s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-01 13:35:58 +02:00
mmintel bf8073f5bf perf: optimize LCP images and enable AVIF
Build & Deploy / 🔍 Prepare (push) Successful in 1m10s
Build & Deploy / 🧪 QA (push) Successful in 1m17s
Build & Deploy / 🏗️ Build (push) Successful in 2m2s
Build & Deploy / 🚀 Deploy (push) Successful in 26s
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-01 13:35:50 +02:00
mmintel e8adb87b02 fix(lcp): revert DynamicFramerMotion wrapper to prevent React 18 Suspense DOM deletion during hydration
Build & Deploy / 🔍 Prepare (push) Successful in 30s
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🧪 Post-Deploy Verification (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 3s
Build & Deploy / 🧪 QA (push) Failing after 48s
2026-07-01 12:10:15 +02:00
mmintel 067e34c19b fix(lcp): revert unoptimized=true on HeroVideo to restore Next.js image optimization for massive CMS images
Build & Deploy / 🔍 Prepare (push) Successful in 28s
Build & Deploy / 🧪 QA (push) Successful in 1m47s
Build & Deploy / 🏗️ Build (push) Successful in 3m16s
Build & Deploy / 🚀 Deploy (push) Successful in 33s
Build & Deploy / 🧪 Post-Deploy Verification (push) Failing after 42s
Build & Deploy / 🔔 Notify (push) Successful in 3s
2026-07-01 12:07:18 +02:00
20 changed files with 14759 additions and 68 deletions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+18 -21
View File
@@ -21,8 +21,7 @@ import { DynamicInitialLoader as InitialLoader } from '@/components/providers/Dy
import { DynamicMobileBottomNav as MobileBottomNav } from '@/components/layout/DynamicMobileBottomNav'; import { DynamicMobileBottomNav as MobileBottomNav } from '@/components/layout/DynamicMobileBottomNav';
import { DynamicCorporateBackground as CorporateBackground } from '@/components/decorations/DynamicCorporateBackground'; import { DynamicCorporateBackground as CorporateBackground } from '@/components/decorations/DynamicCorporateBackground';
import { DynamicPageTransitionShutter as PageTransitionShutter } from '@/components/providers/DynamicPageTransitionShutter'; const corporateBackground = null; // Removed to prevent line shifting
import { DynamicFramerMotion as FramerMotionProvider } from '@/components/providers/DynamicFramerMotion';
const inter = Inter({ const inter = Inter({
subsets: ['latin'], subsets: ['latin'],
@@ -191,28 +190,26 @@ export default async function Layout(props: {
<body className="relative flex flex-col min-h-screen font-sans antialiased overflow-x-hidden selection:bg-primary/90 selection:text-white" suppressHydrationWarning> <body className="relative flex flex-col min-h-screen font-sans antialiased overflow-x-hidden selection:bg-primary/90 selection:text-white" suppressHydrationWarning>
<NextIntlClientProvider messages={clientMessages} locale={safeLocale}> <NextIntlClientProvider messages={clientMessages} locale={safeLocale}>
<TransitionProvider> <TransitionProvider>
<FramerMotionProvider> <CorporateBackground />
<CorporateBackground /> {!hasSeenLoader && <InitialLoader shouldShowLoader={!hasSeenLoader} />}
<InitialLoader shouldShowLoader={!hasSeenLoader} /> {/* PageTransitionShutter loaded dynamically in TransitionProvider */}
<PageTransitionShutter /> <SkipLink />
<SkipLink /> <Header navLinks={navLinks} />
<Header navLinks={navLinks} /> <MobileBottomNav navLinks={navLinks} currentLocale={safeLocale} />
<MobileBottomNav navLinks={navLinks} currentLocale={safeLocale} />
<main <main
id="main-content" id="main-content"
className="flex-grow overflow-visible" className="flex-grow overflow-visible"
tabIndex={-1} tabIndex={-1}
> >
{children} {children}
</main> </main>
<Footer companyInfo={companyInfo} /> <Footer companyInfo={companyInfo} />
<JsonLd /> <JsonLd />
<AnalyticsShell /> <AnalyticsShell />
<FeedbackClientWrapper /> <FeedbackClientWrapper />
</FramerMotionProvider>
</TransitionProvider> </TransitionProvider>
</NextIntlClientProvider> </NextIntlClientProvider>
</body> </body>
+6 -1
View File
@@ -132,7 +132,12 @@ export default async function Home(props: { params: Promise<{ locale: string }>
} }
setRequestLocale(locale); setRequestLocale(locale);
preload('/germany-map.svg', { as: 'image', fetchPriority: 'high' }); preload('/assets/videos/web/hero-kabelpflug-poster.webp', {
as: 'image',
fetchPriority: 'high',
imageSrcSet: '/assets/videos/web/hero-kabelpflug-poster-mobile.webp 800w, /assets/videos/web/hero-kabelpflug-poster.webp 1920w',
imageSizes: '100vw'
});
const mdx = await getMdxContent(locale, 'home'); const mdx = await getMdxContent(locale, 'home');
const allReferences = await getAllReferences(locale); const allReferences = await getAllReferences(locale);
+1
View File
@@ -41,6 +41,7 @@ export const HeroSection: React.FC<HeroSectionProps> = (props) => {
objectPosition: `${backgroundImage?.focalX ?? 50}% ${backgroundImage?.focalY ?? 50}%`, objectPosition: `${backgroundImage?.focalX ?? 50}% ${backgroundImage?.focalY ?? 50}%`,
}} }}
sizes="100vw" sizes="100vw"
quality={50}
priority priority
/> />
{/* Cinematic Color Grading Overlay */} {/* Cinematic Color Grading Overlay */}
+5 -7
View File
@@ -80,16 +80,14 @@ export function HeroVideo(props: HeroVideoProps) {
{/* Background color while video loads */} {/* Background color while video loads */}
<div className="absolute inset-0 z-0 bg-neutral-dark" /> <div className="absolute inset-0 z-0 bg-neutral-dark" />
{/* ALWAYS render the Next.js optimized Image as the LCP element */} <img
<Image
key={`img-${pathname}-${posterSrc}`} key={`img-${pathname}-${posterSrc}`}
src={posterSrc} src={posterSrc}
srcSet={posterSrc.includes('-poster.webp') ? `${posterSrc.replace('-poster.webp', '-poster-mobile.webp')} 800w, ${posterSrc} 1920w` : undefined}
sizes={posterSrc.includes('-poster.webp') ? "100vw" : undefined}
alt={posterAlt} alt={posterAlt}
fill className="absolute inset-0 w-full h-full object-cover z-[1] pointer-events-none"
className="object-cover z-[1] pointer-events-none" decoding="sync"
sizes="100vw"
unoptimized={true}
priority
fetchPriority="high" fetchPriority="high"
/> />
{/* Fast compositing layer to replace the heavy CSS filters on the image */} {/* Fast compositing layer to replace the heavy CSS filters on the image */}
+1 -1
View File
@@ -23,7 +23,7 @@ export function EUFundingBadge() {
alt="European Union Background" alt="European Union Background"
fill fill
className="object-cover object-top" className="object-cover object-top"
priority loading="lazy"
/> />
</div> </div>
@@ -1,7 +0,0 @@
'use client';
import dynamic from 'next/dynamic';
export const DynamicFramerMotion = dynamic(
() => import('./FramerMotionProvider').then((mod) => mod.FramerMotionProvider),
{ ssr: true }
);
@@ -1,11 +0,0 @@
'use client';
import { LazyMotion } from 'framer-motion';
const loadFeatures = () => import('@/lib/framer-features').then(res => res.default);
export function FramerMotionProvider({ children }: { children: React.ReactNode }) {
return (
<LazyMotion features={loadFeatures} strict>
{children}
</LazyMotion>
);
}
+5 -5
View File
@@ -72,8 +72,8 @@ export function InitialLoader({ shouldShowLoader = true }: { shouldShowLoader?:
{/* Sweeping intense white light */} {/* Sweeping intense white light */}
<m.div <m.div
className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]" className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]"
initial={{ left: '-150%' }} initial={{ x: '-150%' }}
animate={{ left: '250%' }} animate={{ x: '250%' }}
transition={{ duration: 2.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.5 }} transition={{ duration: 2.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.5 }}
/> />
</div> </div>
@@ -91,9 +91,9 @@ export function InitialLoader({ shouldShowLoader = true }: { shouldShowLoader?:
className="h-[2px] w-full bg-white/5 overflow-hidden relative rounded-full" className="h-[2px] w-full bg-white/5 overflow-hidden relative rounded-full"
> >
<m.div <m.div
className="absolute inset-y-0 left-0 bg-gradient-to-r from-primary-dark via-primary to-primary-light" className="absolute inset-y-0 left-0 w-full bg-gradient-to-r from-primary-dark via-primary to-primary-light origin-left"
initial={{ width: "0%" }} initial={{ scaleX: 0 }}
animate={{ width: "100%" }} animate={{ scaleX: 1 }}
transition={{ duration: 3.8, ease: [0.16, 1, 0.3, 1] }} transition={{ duration: 3.8, ease: [0.16, 1, 0.3, 1] }}
/> />
</m.div> </m.div>
@@ -12,12 +12,12 @@ export function PageTransitionShutter() {
<AnimatePresence> <AnimatePresence>
{isTransitioning && ( {isTransitioning && (
<m.div <m.div
key="shutter" key="page-transition-shutter"
initial={{ y: '-100%' }} initial={{ y: '-100%' }}
animate={{ y: '0%' }} animate={{ y: 0 }}
exit={{ y: '100%' }} exit={{ y: '100%' }}
transition={{ duration: 0.9, ease: [0.16, 1, 0.3, 1] }} transition={{ duration: 0.65, ease: [0.76, 0, 0.24, 1] }}
className="fixed left-0 w-full z-[9998] bg-[#050B14] pointer-events-none flex flex-col items-center justify-center overflow-visible" className="fixed left-0 right-0 z-[9998] bg-[#050B14] flex flex-col items-center justify-center overflow-hidden"
style={{ style={{
height: '100vh', height: '100vh',
top: '0', top: '0',
@@ -56,8 +56,8 @@ export function PageTransitionShutter() {
{/* Sweeping intense white light */} {/* Sweeping intense white light */}
<m.div <m.div
className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]" className="absolute inset-0 bg-gradient-to-r from-transparent via-white to-transparent skew-x-[-25deg]"
initial={{ left: '-150%' }} initial={{ x: '-150%' }}
animate={{ left: '250%' }} animate={{ x: '250%' }}
transition={{ duration: 1.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.2 }} transition={{ duration: 1.5, ease: "easeInOut", repeat: Infinity, repeatDelay: 0.2 }}
/> />
</div> </div>
+19 -1
View File
@@ -2,6 +2,16 @@
import React, { createContext, useContext, useState, useCallback, ReactNode, useEffect } from 'react'; import React, { createContext, useContext, useState, useCallback, ReactNode, useEffect } from 'react';
import { useRouter, usePathname, useSearchParams } from 'next/navigation'; import { useRouter, usePathname, useSearchParams } from 'next/navigation';
import { LazyMotion } from 'framer-motion';
import dynamic from 'next/dynamic';
const loadFeatures = () => import('@/lib/framer-features').then(res => res.default);
// Defer loading the shutter to eliminate AnimatePresence from the initial bundle
const DynamicPageTransitionShutter = dynamic(
() => import('./PageTransitionShutter').then(mod => mod.PageTransitionShutter),
{ ssr: false }
);
interface TransitionContextType { interface TransitionContextType {
isTransitioning: boolean; isTransitioning: boolean;
@@ -14,8 +24,12 @@ const TransitionContext = createContext<TransitionContextType | undefined>(undef
export function TransitionProvider({ children }: { children: ReactNode }) { export function TransitionProvider({ children }: { children: ReactNode }) {
const [isTransitioning, setIsTransitioning] = useState(false); const [isTransitioning, setIsTransitioning] = useState(false);
const [transitionMessage, setTransitionMessage] = useState<string | null>(null); const [transitionMessage, setTransitionMessage] = useState<string | null>(null);
const [hasMountedShutter, setHasMountedShutter] = useState(false);
const router = useRouter(); const router = useRouter();
// We no longer eagerly load the shutter in the background.
// It will be loaded precisely when the user initiates a transition.
// We use a ref to track transition state without triggering the route change effect when it turns true // We use a ref to track transition state without triggering the route change effect when it turns true
const isTransitioningRef = React.useRef(isTransitioning); const isTransitioningRef = React.useRef(isTransitioning);
useEffect(() => { useEffect(() => {
@@ -41,6 +55,7 @@ export function TransitionProvider({ children }: { children: ReactNode }) {
setTransitionMessage(message); setTransitionMessage(message);
setIsTransitioning(true); setIsTransitioning(true);
setHasMountedShutter(true);
// Die Animation des Shutters abwarten (ca. 700ms), dann pushen // Die Animation des Shutters abwarten (ca. 700ms), dann pushen
setTimeout(() => { setTimeout(() => {
@@ -68,7 +83,10 @@ export function TransitionProvider({ children }: { children: ReactNode }) {
setTransitionMessage={setTransitionMessage} setTransitionMessage={setTransitionMessage}
/> />
</React.Suspense> </React.Suspense>
{children} <LazyMotion features={loadFeatures}>
{hasMountedShutter && <DynamicPageTransitionShutter />}
{children}
</LazyMotion>
</TransitionContext.Provider> </TransitionContext.Provider>
); );
} }
+1 -1
View File
@@ -118,7 +118,7 @@ description: "Die E-TIB GmbH ist Ihr zuverlässiger Partner für komplexe Kabelt
items={[ items={[
{ {
title: "Kabelleitungsnetzbau", title: "Kabelleitungsnetzbau",
description: "Kabelleitungsnetzbau (Hoch-/Mittel- und Niederspannung) sowie Kabelmontagen bis 110 kV", description: "Kabelleitungsnetzbau (Nieder-/Mittel- und Hochspannung bis 110 kV)",
tag: "Energie", tag: "Energie",
size: "large", size: "large",
href: "/de/kabeltiefbau", href: "/de/kabeltiefbau",
+1 -1
View File
@@ -8,7 +8,7 @@ layout: "fullBleed"
<HeroSection <HeroSection
badge="Kernkompetenz" badge="Kernkompetenz"
title="Kabelleitungsnetzbau" title="Kabelleitungsnetzbau"
subtitle="Komplette Infrastruktur-Lösungen für Hoch-, Mittel- und Niederspannungsnetze sowie Kabelmontagen bis 110 kV" subtitle="Komplette Infrastruktur-Lösungen für Nieder-, Mittel- und Hochspannungsnetze bis 110 kV"
backgroundImage={{ url: '/assets/photos/DSC01123.JPG' }} backgroundImage={{ url: '/assets/photos/DSC01123.JPG' }}
alignment="center" alignment="center"
ctaLabel="Projekt anfragen" ctaLabel="Projekt anfragen"
+1 -2
View File
@@ -15,7 +15,6 @@ const nextConfig = {
pagesBufferLength: 2, pagesBufferLength: 2,
}, },
experimental: { experimental: {
inlineCss: true,
staleTimes: { staleTimes: {
dynamic: 0, dynamic: 0,
static: 30, static: 30,
@@ -449,7 +448,7 @@ const nextConfig = {
}, },
images: { images: {
qualities: [25, 50, 75, 100], qualities: [25, 50, 75, 100],
formats: ['image/webp'], formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840], deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
remotePatterns: [ remotePatterns: [
{ {
+1 -1
View File
@@ -139,7 +139,7 @@
"prepare": "husky", "prepare": "husky",
"preinstall": "npx only-allow pnpm" "preinstall": "npx only-allow pnpm"
}, },
"version": "2.2.94", "version": "2.4.5",
"pnpm": { "pnpm": {
"onlyBuiltDependencies": [ "onlyBuiltDependencies": [
"@parcel/watcher", "@parcel/watcher",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 86 KiB

@@ -39,7 +39,7 @@ describe('Task 6 Content Updates', () => {
// DE Home // DE Home
expect(deContent).toContain('title: "Kabelleitungsnetzbau"'); expect(deContent).toContain('title: "Kabelleitungsnetzbau"');
expect(deContent).toContain('description: "Kabelleitungsnetzbau (Hoch-/Mittel- und Niederspannung) sowie Kabelmontagen bis 110 kV"'); expect(deContent).toContain('description: "Kabelleitungsnetzbau (Nieder-/Mittel- und Hochspannung bis 110 kV)"');
expect(deContent).toContain('100+'); expect(deContent).toContain('100+');
expect(deContent).toContain('Mitarbeitende'); expect(deContent).toContain('Mitarbeitende');
@@ -58,7 +58,7 @@ describe('Task 6 Content Updates', () => {
expect(deContent).toContain('title: "Kabelleitungsnetzbau"'); expect(deContent).toContain('title: "Kabelleitungsnetzbau"');
expect(deContent).toContain('excerpt: "Professioneller Kabelleitungsnetzbau'); expect(deContent).toContain('excerpt: "Professioneller Kabelleitungsnetzbau');
expect(deContent).toContain('Kabelmontagen bis 110 kV'); expect(deContent).toContain('Kabelmontagen bis 110 kV');
expect(deContent).toContain('subtitle="Komplette Infrastruktur-Lösungen für Hoch-, Mittel- und Niederspannungsnetze sowie Kabelmontagen bis 110 kV"'); expect(deContent).toContain('subtitle="Komplette Infrastruktur-Lösungen für Nieder-, Mittel- und Hochspannungsnetze bis 110 kV"');
expect(deContent).toContain('"Kabelmontagen bis 110 kV"'); expect(deContent).toContain('"Kabelmontagen bis 110 kV"');
// EN Kabelnetzbau // EN Kabelnetzbau