Compare commits

..

2 Commits

Author SHA1 Message Date
denshooter
258143b362 Merge branch 'dev' into production
All checks were successful
CI / CD / test-build (push) Successful in 10m14s
CI / CD / deploy-dev (push) Has been skipped
CI / CD / deploy-production (push) Successful in 23s
2026-04-19 15:47:39 +02:00
denshooter
049dda8dc5 feat: improve SEO with locale-specific metadata, structured data, and keywords
All checks were successful
CI / CD / test-build (push) Successful in 10m14s
CI / CD / deploy-dev (push) Successful in 1m20s
CI / CD / deploy-production (push) Has been skipped
- Add locale-specific title/description for DE and EN homepage
- Expand keywords with local SEO terms (Webentwicklung Osnabrück, Informatik, etc.)
- Add WebSite schema and enhance Person schema with knowsAbout, alternateName
- Add hreflang alternates for DE/EN
- Update projects page with locale-specific metadata
- Keep visible titles short, move SEO terms to description/structured data
2026-04-19 15:47:22 +02:00
6 changed files with 91 additions and 20 deletions

View File

@@ -2,6 +2,19 @@ import type { Metadata } from "next";
import HomePageServer from "../_ui/HomePageServer"; import HomePageServer from "../_ui/HomePageServer";
import { getLanguageAlternates, toAbsoluteUrl } from "@/lib/seo"; import { getLanguageAlternates, toAbsoluteUrl } from "@/lib/seo";
const localeMetadata: Record<string, { title: string; description: string }> = {
de: {
title: "Dennis Konkol Webentwickler Osnabrück",
description:
"Dennis Konkol Software Engineer & Webentwickler in Osnabrück. Webentwicklung, Fullstack-Apps, Docker, Next.js, Flutter. Projekte ansehen und Kontakt aufnehmen.",
},
en: {
title: "Dennis Konkol Web Developer Osnabrück",
description:
"Dennis Konkol Software Engineer & Web Developer in Osnabrück, Germany. Web development, fullstack apps, Docker, Next.js, Flutter.",
},
};
export async function generateMetadata({ export async function generateMetadata({
params, params,
}: { }: {
@@ -9,7 +22,10 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { locale } = await params; const { locale } = await params;
const languages = getLanguageAlternates({ pathWithoutLocale: "" }); const languages = getLanguageAlternates({ pathWithoutLocale: "" });
const meta = localeMetadata[locale] ?? localeMetadata.en;
return { return {
title: meta.title,
description: meta.description,
alternates: { alternates: {
canonical: toAbsoluteUrl(`/${locale}`), canonical: toAbsoluteUrl(`/${locale}`),
languages, languages,

View File

@@ -13,7 +13,12 @@ export async function generateMetadata({
}): Promise<Metadata> { }): Promise<Metadata> {
const { locale } = await params; const { locale } = await params;
const languages = getLanguageAlternates({ pathWithoutLocale: "projects" }); const languages = getLanguageAlternates({ pathWithoutLocale: "projects" });
const isDe = locale === "de";
return { return {
title: isDe ? "Projekte Dennis Konkol" : "Projects Dennis Konkol",
description: isDe
? "Webentwicklung, Fullstack-Apps und Mobile-Projekte von Dennis Konkol. Next.js, Flutter, Docker und mehr Osnabrück."
: "Web development, fullstack apps and mobile projects by Dennis Konkol. Next.js, Flutter, Docker and more Osnabrück.",
alternates: { alternates: {
canonical: toAbsoluteUrl(`/${locale}/projects`), canonical: toAbsoluteUrl(`/${locale}/projects`),
languages, languages,

View File

@@ -31,20 +31,41 @@ export default async function HomePageServer({ locale }: HomePageServerProps) {
return ( return (
<div className="min-h-screen"> <div className="min-h-screen">
<Script <Script
id={"structured-data"} id={"structured-data-person"}
type="application/ld+json" type="application/ld+json"
dangerouslySetInnerHTML={{ dangerouslySetInnerHTML={{
__html: JSON.stringify({ __html: JSON.stringify({
"@context": "https://schema.org", "@context": "https://schema.org",
"@type": "Person", "@type": "Person",
name: "Dennis Konkol", name: "Dennis Konkol",
alternateName: ["dk0", "denshooter"],
url: "https://dk0.dev", url: "https://dk0.dev",
jobTitle: "Software Engineer", jobTitle: "Software Engineer",
description:
locale === "de"
? "Software Engineer & Webentwickler in Osnabrück. Webentwicklung, Fullstack-Apps, Docker, Next.js, Flutter."
: "Software Engineer & Web Developer in Osnabrück, Germany. Web development, fullstack apps, Docker, Next.js, Flutter.",
address: { address: {
"@type": "PostalAddress", "@type": "PostalAddress",
addressLocality: "Osnabrück", addressLocality: "Osnabrück",
addressCountry: "Germany", addressRegion: "Niedersachsen",
addressCountry: "DE",
}, },
knowsAbout: [
"Webentwicklung",
"Web Development",
"Next.js",
"React",
"TypeScript",
"Flutter",
"Docker",
"DevOps",
"Self-Hosting",
"CI/CD",
"Fullstack Development",
"Softwareentwicklung",
"Informatik",
],
sameAs: [ sameAs: [
"https://github.com/Denshooter", "https://github.com/Denshooter",
"https://linkedin.com/in/dkonkol", "https://linkedin.com/in/dkonkol",
@@ -52,6 +73,20 @@ export default async function HomePageServer({ locale }: HomePageServerProps) {
}), }),
}} }}
/> />
<Script
id={"structured-data-website"}
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
"@context": "https://schema.org",
"@type": "WebSite",
name: "Dennis Konkol",
alternateName: "dk0.dev",
url: "https://dk0.dev",
inLanguage: ["de", "en"],
}),
}}
/>
<Header locale={locale} /> <Header locale={locale} />
{/* Spacer to prevent navbar overlap */} {/* Spacer to prevent navbar overlap */}
<div className="h-24 md:h-32" aria-hidden="true"></div> <div className="h-24 md:h-32" aria-hidden="true"></div>

View File

@@ -49,23 +49,33 @@ export default async function RootLayout({
export const metadata: Metadata = { export const metadata: Metadata = {
metadataBase: new URL(getBaseUrl()), metadataBase: new URL(getBaseUrl()),
title: { title: {
default: "Dennis Konkol | Portfolio", default: "Dennis Konkol",
template: "%s | Dennis Konkol", template: "%s | dk0",
}, },
description: description:
"Portfolio of Dennis Konkol, a student and software engineer based in Osnabrück, Germany. Passionate about technology, coding, and solving real-world problems.", "Dennis Konkol Software Engineer & Webentwickler in Osnabrück. Webentwicklung, Fullstack-Apps, Docker, Next.js, Flutter. Portfolio mit Projekten und Kontakt.",
keywords: [ keywords: [
"Dennis Konkol", "Dennis Konkol",
"dk0",
"denshooter",
"Webentwicklung Osnabrück",
"Webentwicklung",
"Softwareentwicklung Osnabrück",
"Website erstellen Osnabrück",
"Web Design Osnabrück",
"Informatik Osnabrück",
"Software Engineer", "Software Engineer",
"Portfolio",
"Student",
"Web Development",
"Full Stack Developer", "Full Stack Developer",
"Osnabrück", "Frontend Developer Osnabrück",
"Germany",
"React",
"Next.js", "Next.js",
"React",
"TypeScript", "TypeScript",
"Flutter",
"Docker",
"Self-Hosting",
"DevOps",
"Portfolio",
"Osnabrück",
], ],
authors: [{ name: "Dennis Konkol", url: "https://dk0.dev" }], authors: [{ name: "Dennis Konkol", url: "https://dk0.dev" }],
creator: "Dennis Konkol", creator: "Dennis Konkol",
@@ -82,26 +92,27 @@ export const metadata: Metadata = {
}, },
}, },
openGraph: { openGraph: {
title: "Dennis Konkol | Portfolio", title: "Dennis Konkol",
description: description:
"Explore my projects and contact me for collaboration opportunities!", "Software Engineer & Webentwickler in Osnabrück. Next.js, Flutter, Docker, DevOps. Projekte ansehen und Kontakt aufnehmen.",
url: "https://dk0.dev", url: "https://dk0.dev",
siteName: "Dennis Konkol Portfolio", siteName: "Dennis Konkol",
images: [ images: [
{ {
url: "https://dk0.dev/api/og", url: "https://dk0.dev/api/og",
width: 1200, width: 1200,
height: 630, height: 630,
alt: "Dennis Konkol Portfolio", alt: "Dennis Konkol",
}, },
], ],
locale: "en_US", locale: "de_DE",
alternateLocale: ["en_US"],
type: "website", type: "website",
}, },
twitter: { twitter: {
card: "summary_large_image", card: "summary_large_image",
title: "Dennis Konkol | Portfolio", title: "Dennis Konkol",
description: "Student & Software Engineer based in Osnabrück, Germany.", description: "Software Engineer & Webentwickler in Osnabrück.",
images: ["https://dk0.dev/api/og"], images: ["https://dk0.dev/api/og"],
creator: "@denshooter", creator: "@denshooter",
}, },
@@ -110,5 +121,9 @@ export const metadata: Metadata = {
}, },
alternates: { alternates: {
canonical: "https://dk0.dev", canonical: "https://dk0.dev",
languages: {
de: "https://dk0.dev/de",
en: "https://dk0.dev/en",
},
}, },
}; };

View File

@@ -34,7 +34,7 @@
"f2": "Docker Swarm & CI/CD", "f2": "Docker Swarm & CI/CD",
"f3": "Self-Hosted Infrastruktur" "f3": "Self-Hosted Infrastruktur"
}, },
"description": "Ich bin Dennis, Student aus Osnabrück und leidenschaftlicher Selfhoster. Ich entwickle Fullstack Apps und sorge am liebsten selbst dafür, dass sie auf meiner eigenen Infrastruktur perfekt laufen.", "description": "Ich bin Dennis Konkol, Informatik-Student und Webentwickler aus Osnabrück. Ich entwickle Fullstack-Apps mit Next.js und Flutter und betreibe meine eigene Infrastruktur mit Docker und CI/CD.",
"ctaWork": "Meine Projekte", "ctaWork": "Meine Projekte",
"ctaContact": "Kontakt" "ctaContact": "Kontakt"
}, },

View File

@@ -35,7 +35,7 @@
"f2": "Docker Swarm & CI/CD", "f2": "Docker Swarm & CI/CD",
"f3": "Self-Hosted Infrastructure" "f3": "Self-Hosted Infrastructure"
}, },
"description": "I'm Dennis, a student from Germany and a passionate selfhoster. I build fullstack applications and love the challenge of managing the infrastructure they run on.", "description": "I'm Dennis Konkol, a computer science student and web developer from Osnabrück, Germany. I build fullstack apps with Next.js and Flutter and love running my own infrastructure with Docker and CI/CD.",
"ctaWork": "View Projects", "ctaWork": "View Projects",
"ctaContact": "Get in touch" "ctaContact": "Get in touch"
}, },