diff --git a/mdx-components.tsx b/mdx-components.tsx
index b13a250..7ddd4f0 100644
--- a/mdx-components.tsx
+++ b/mdx-components.tsx
@@ -5,6 +5,7 @@ import { MDXRemote, MDXRemoteProps } from 'next-mdx-remote/rsc';
import { highlight } from 'sugar-high';
import { CardProfile } from '@/components/CardProfile';
import { CopyButton } from '@/components/copy-button';
+import { LocaleLink } from '@/components/LocaleLink';
// Type definitions
type HeadingProps = ComponentPropsWithoutRef<'h1'>;
@@ -72,23 +73,16 @@ function Table({ data }: { data: TableData }) {
);
}
-// Custom link component with support for internal/external links
+// Custom link: internal links get /[locale] prefix via LocaleLink; external stay
function CustomLink(props: React.AnchorHTMLAttributes) {
const href = props.href;
-
- if (href && href.startsWith('/')) {
- return (
-
- {props.children}
-
- );
+ if (href && (href.startsWith('http') || href.startsWith('//'))) {
+ return ;
}
-
if (href && href.startsWith('#')) {
return ;
}
-
- return ;
+ return ;
}
// MDX Components for direct usage
diff --git a/package.json b/package.json
index e3abe32..5d75ed2 100644
--- a/package.json
+++ b/package.json
@@ -38,13 +38,16 @@
"@types/three": "^0.176.0",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
+ "i18next": "^25.8.0",
"lucide-react": "^0.511.0",
"next": ">=15.5.9",
+ "next-i18next": "^15.4.3",
"next-mdx-remote": "^5.0.0",
"next-themes": "^0.4.6",
"postcss": "^8.5.4",
"react": "^19.1.0",
"react-dom": "^19.1.0",
+ "react-i18next": "^16.5.4",
"react-icons": "^5.5.0",
"sugar-high": "^0.9.3",
"tailwind-merge": "^3.3.0",
diff --git a/src/app/biomass/about/page.mdx b/src/app/[locale]/biomass/about/page.mdx
similarity index 100%
rename from src/app/biomass/about/page.mdx
rename to src/app/[locale]/biomass/about/page.mdx
diff --git a/src/app/[locale]/biomass/disc&data/content-de.mdx b/src/app/[locale]/biomass/disc&data/content-de.mdx
new file mode 100644
index 0000000..9913686
--- /dev/null
+++ b/src/app/[locale]/biomass/disc&data/content-de.mdx
@@ -0,0 +1,77 @@
+import { Button } from "@/components/ui/button"
+
+
+# BIOMASS-PRODUKTE
+
+
+
+Die BIOMASS-Mission liefert eine Reihe globaler, konsistenter Waldprodukte aus P-Band-SAR-Beobachtungen. Zu den Kerndatenprodukten zählen oberirdische Waldbiomasse, Waldhöhe und Waldschäden und bieten neue Einblicke in Waldstruktur, Kohlenstoffvorräte und ihre Veränderung. Die Produkte werden als Level-2- und Level-3-Datensätze erzeugt und dienen der Langzeitbeobachtung, Klimaforschung und Erdsystemmodellierung.
+
+Zusätzlich erstellt BIOMASS experimentelle und explorative Datensätze, die die Besonderheiten von P-Band-SAR nutzen – für Forschung zu Walddynamik, Untersaatenstreuung und Ökosystemprozessen. Alle Produkte werden mit Unsicherheitsangaben geliefert und folgen Prinzipien offener Wissenschaft.
+
+
+
+
+
+
Level
+
Produkttyp
+
Beschreibung
+
+
+
+
+
Level-1
+
SAR-Rückstreuung & interferometrische Daten
+
Kalibrierte P-Band-SAR-Messungen als Grundlage aller höheren Produkte.
+
+
+
Level-2
+
Waldbiophysikalische Produkte
+
Globale Karten zu oberirdischer Biomasse, Waldhöhe und Waldschäden inkl. Unsicherheiten.
+
+
+
Level-3
+
Raster- & Zeitreihenprodukte
+
Räumlich und zeitlich aggregierte Datensätze für Klimastudien, Kohlenstoffbilanzen und Langzeitmonitoring.
+
+
+
Experimental
+
Fortgeschrittene Forschungsprodukte
+
Explorative Datensätze zur Nutzung der P-Band-SAR-Möglichkeiten für Wald- und Ökosystemforschung.
+
+
+
+
+
+##
Open Access, Open Science und Beteiligung der Community
+
+BIOMASS-Produkte, Algorithmen und Validierungswerkzeuge werden nach Prinzipien offener Wissenschaft und Open Source entwickelt. Die Prozessierungssoftware und Algorithmen sind im BIOMASS Product Algorithm Laboratory (BioPAL) verankert – für Transparenz, Reproduzierbarkeit und gemeinsame Weiterentwicklung. Offener Zugang zu Daten, Prozessierungsumgebungen und Auswertewerkzeugen wird über die Multi-mission Algorithm and Analysis Platform (MAAP) unterstützt.
+
+🔗 MAAP: https://maap-project.org
+🔗 BioPAL: https://github.com/BioPAL/BioPAL
+
+Am 12. Dezember 2025 veröffentlichte die ESA die ersten BIOMASS-Open-Access-Datenprodukte:
+
+
+
+##
BIOMASS Data Innovation and Science Cluster (DISC)
+
+
Kernaufgaben
+
+Der BIOMASS DISC sichert Qualität, Zuverlässigkeit und wissenschaftlichen Nutzen der BIOMASS-Produkte. Zu den Hauptaufgaben zählen:
+
+
+Instrumenten- und Datenqualitätsüberwachung
+Laufende Kalibrierung, Leistungsüberwachung und Qualitätssicherung für zuverlässige BIOMASS-SAR-Daten.
+
+Prozessierung und Produktentwicklung
+Pflege und Weiterentwicklung der Prozessierungsketten und Kerndaten, Einbindung neuer Erkenntnisse, Kalibrierung und Validierung.
+
+Validierung und Neunprozessierung
+Validierung der Waldprodukte anhand von Referenzdaten aus Boden- und Flugzeugmessungen sowie regelmäßige Neuprozessierungen für konsistente Langzeitdaten.
+
+Wissenschaftliche Innovation und Nutzerunterstützung
+Entwicklung experimenteller Produkte, Unterstützung der Nutzenden und Erweiterung der BIOMASS-Möglichkeiten.
+
+
+Weitere Informationen: https://biomass-disc.info/
diff --git a/src/app/biomass/disc&data/page.mdx b/src/app/[locale]/biomass/disc&data/content-en.mdx
similarity index 99%
rename from src/app/biomass/disc&data/page.mdx
rename to src/app/[locale]/biomass/disc&data/content-en.mdx
index 528f642..f473bf1 100644
--- a/src/app/biomass/disc&data/page.mdx
+++ b/src/app/[locale]/biomass/disc&data/content-en.mdx
@@ -113,5 +113,3 @@ Validation of forest products against high-quality ground and airborne reference
Development of experimental products, support to the user community, and extension of BIOMASS scientific capabilities.
Further information: https://biomass-disc.info/
-
-
diff --git a/src/app/[locale]/biomass/disc&data/page.tsx b/src/app/[locale]/biomass/disc&data/page.tsx
new file mode 100644
index 0000000..16dd7a6
--- /dev/null
+++ b/src/app/[locale]/biomass/disc&data/page.tsx
@@ -0,0 +1,19 @@
+import { isValidLocale, defaultLocale, type Locale } from '@/config/i18n'
+import ContentEn from './content-en.mdx'
+import ContentDe from './content-de.mdx'
+
+const content = {
+ en: ContentEn,
+ de: ContentDe,
+} as const
+
+interface PageProps {
+ params: Promise<{ locale?: string }>
+}
+
+export default async function DiscDataPage({ params }: PageProps) {
+ const { locale: raw } = await params
+ const locale: Locale = raw && isValidLocale(raw) ? raw : defaultLocale
+ const Page = content[locale] ?? content.en
+ return
+}
diff --git a/src/app/biomass/earthexplorer/page.mdx b/src/app/[locale]/biomass/earthexplorer/page.mdx
similarity index 100%
rename from src/app/biomass/earthexplorer/page.mdx
rename to src/app/[locale]/biomass/earthexplorer/page.mdx
diff --git a/src/app/blog/[slug]/page.tsx b/src/app/[locale]/blog/[slug]/page.tsx
similarity index 73%
rename from src/app/blog/[slug]/page.tsx
rename to src/app/[locale]/blog/[slug]/page.tsx
index 581db82..f48f893 100644
--- a/src/app/blog/[slug]/page.tsx
+++ b/src/app/[locale]/blog/[slug]/page.tsx
@@ -1,26 +1,29 @@
// Adapted from https://github.com/vercel/examples/tree/main/solutions/blog MIT License
import { notFound } from 'next/navigation'
import { CustomMDX } from '@/../mdx-components'
-import { formatDate, getBlogPosts } from '@/utils/utilsBlog'
+import { formatDate, getBlogPosts, getAllBlogPosts } from '@/utils/utilsBlog'
import { baseUrl } from '@/utils/sitemap'
import Link from 'next/link'
-import Image from "next/image";
+import Image from "next/image"
+import { isValidLocale, defaultLocale, type Locale } from '@/config/i18n'
export async function generateStaticParams() {
- const posts = getBlogPosts()
- return posts.map((post) => ({
- slug: post.slug,
- }))
+ const all = getAllBlogPosts()
+ return all.map((post) => {
+ const locale: Locale = post.slug.endsWith('_de') ? 'de' : 'en'
+ return { locale, slug: post.slug }
+ })
}
interface BlogParams {
- params: Promise<{ slug: string }>;
+ params: Promise<{ locale: string; slug: string }>;
}
export default async function Blog({ params }: BlogParams) {
- const { slug } = await params;
- const posts = getBlogPosts();
- const post = posts.find((post) => post.slug === slug);
+ const { slug, locale: raw } = await params
+ const locale: Locale = isValidLocale(raw) ? raw : defaultLocale
+ const posts = getBlogPosts(locale)
+ const post = posts.find((p) => p.slug === slug)
if (!post) {
notFound()
@@ -42,7 +45,7 @@ export default async function Blog({ params }: BlogParams) {
image: post.metadata.image2
? `${baseUrl}${post.metadata.image2}`
: `/og?title=${encodeURIComponent(post.metadata.title)}`,
- url: `${baseUrl}/blog/${post.slug}`,
+ url: `${baseUrl}/${locale}/blog/${post.slug}`,
author: {
'@type': 'Person',
name: 'My Portfolio',
@@ -51,7 +54,7 @@ export default async function Blog({ params }: BlogParams) {
}}
/>
diff --git a/src/app/[locale]/blog/page.tsx b/src/app/[locale]/blog/page.tsx
new file mode 100644
index 0000000..ac6c3f7
--- /dev/null
+++ b/src/app/[locale]/blog/page.tsx
@@ -0,0 +1,23 @@
+import { BlogPosts } from '@/components/posts'
+import { isValidLocale, defaultLocale, type Locale } from '@/config/i18n'
+
+export const metadata = {
+ title: 'Posts',
+ description: 'Read my posts.',
+}
+
+interface PageProps {
+ params: Promise<{ locale?: string }>
+}
+
+export default async function Page({ params }: PageProps) {
+ const { locale: raw } = await params
+ const locale: Locale = raw && isValidLocale(raw) ? raw : defaultLocale
+ return (
+
+
+
NEWS
+
+
+ )
+}
diff --git a/src/app/blog/posts/first_images.mdx b/src/app/[locale]/blog/posts/first_images.mdx
similarity index 100%
rename from src/app/blog/posts/first_images.mdx
rename to src/app/[locale]/blog/posts/first_images.mdx
diff --git a/src/app/blog/posts/first_images_de.mdx b/src/app/[locale]/blog/posts/first_images_de.mdx
similarity index 100%
rename from src/app/blog/posts/first_images_de.mdx
rename to src/app/[locale]/blog/posts/first_images_de.mdx
diff --git a/src/app/blog/posts/launch.mdx b/src/app/[locale]/blog/posts/launch.mdx
similarity index 100%
rename from src/app/blog/posts/launch.mdx
rename to src/app/[locale]/blog/posts/launch.mdx
diff --git a/src/app/blog/posts/launch_de.mdx b/src/app/[locale]/blog/posts/launch_de.mdx
similarity index 100%
rename from src/app/blog/posts/launch_de.mdx
rename to src/app/[locale]/blog/posts/launch_de.mdx
diff --git a/src/app/blog/posts/news1.mdx b/src/app/[locale]/blog/posts/news1.mdx
similarity index 100%
rename from src/app/blog/posts/news1.mdx
rename to src/app/[locale]/blog/posts/news1.mdx
diff --git a/src/app/blog/posts/news10.mdx b/src/app/[locale]/blog/posts/news10.mdx
similarity index 100%
rename from src/app/blog/posts/news10.mdx
rename to src/app/[locale]/blog/posts/news10.mdx
diff --git a/src/app/blog/posts/news11.mdx b/src/app/[locale]/blog/posts/news11.mdx
similarity index 100%
rename from src/app/blog/posts/news11.mdx
rename to src/app/[locale]/blog/posts/news11.mdx
diff --git a/src/app/blog/posts/news12.mdx b/src/app/[locale]/blog/posts/news12.mdx
similarity index 100%
rename from src/app/blog/posts/news12.mdx
rename to src/app/[locale]/blog/posts/news12.mdx
diff --git a/src/app/blog/posts/news13.mdx b/src/app/[locale]/blog/posts/news13.mdx
similarity index 100%
rename from src/app/blog/posts/news13.mdx
rename to src/app/[locale]/blog/posts/news13.mdx
diff --git a/src/app/blog/posts/news14.mdx b/src/app/[locale]/blog/posts/news14.mdx
similarity index 100%
rename from src/app/blog/posts/news14.mdx
rename to src/app/[locale]/blog/posts/news14.mdx
diff --git a/src/app/blog/posts/news15.mdx b/src/app/[locale]/blog/posts/news15.mdx
similarity index 100%
rename from src/app/blog/posts/news15.mdx
rename to src/app/[locale]/blog/posts/news15.mdx
diff --git a/src/app/blog/posts/news16.mdx b/src/app/[locale]/blog/posts/news16.mdx
similarity index 100%
rename from src/app/blog/posts/news16.mdx
rename to src/app/[locale]/blog/posts/news16.mdx
diff --git a/src/app/blog/posts/news17.mdx b/src/app/[locale]/blog/posts/news17.mdx
similarity index 100%
rename from src/app/blog/posts/news17.mdx
rename to src/app/[locale]/blog/posts/news17.mdx
diff --git a/src/app/blog/posts/news18.mdx b/src/app/[locale]/blog/posts/news18.mdx
similarity index 100%
rename from src/app/blog/posts/news18.mdx
rename to src/app/[locale]/blog/posts/news18.mdx
diff --git a/src/app/blog/posts/news19.mdx b/src/app/[locale]/blog/posts/news19.mdx
similarity index 100%
rename from src/app/blog/posts/news19.mdx
rename to src/app/[locale]/blog/posts/news19.mdx
diff --git a/src/app/blog/posts/news2.mdx b/src/app/[locale]/blog/posts/news2.mdx
similarity index 100%
rename from src/app/blog/posts/news2.mdx
rename to src/app/[locale]/blog/posts/news2.mdx
diff --git a/src/app/blog/posts/news20.mdx b/src/app/[locale]/blog/posts/news20.mdx
similarity index 100%
rename from src/app/blog/posts/news20.mdx
rename to src/app/[locale]/blog/posts/news20.mdx
diff --git a/src/app/blog/posts/news21.mdx b/src/app/[locale]/blog/posts/news21.mdx
similarity index 100%
rename from src/app/blog/posts/news21.mdx
rename to src/app/[locale]/blog/posts/news21.mdx
diff --git a/src/app/blog/posts/news22.mdx b/src/app/[locale]/blog/posts/news22.mdx
similarity index 100%
rename from src/app/blog/posts/news22.mdx
rename to src/app/[locale]/blog/posts/news22.mdx
diff --git a/src/app/blog/posts/news23.mdx b/src/app/[locale]/blog/posts/news23.mdx
similarity index 100%
rename from src/app/blog/posts/news23.mdx
rename to src/app/[locale]/blog/posts/news23.mdx
diff --git a/src/app/blog/posts/news24.mdx b/src/app/[locale]/blog/posts/news24.mdx
similarity index 100%
rename from src/app/blog/posts/news24.mdx
rename to src/app/[locale]/blog/posts/news24.mdx
diff --git a/src/app/blog/posts/news3.mdx b/src/app/[locale]/blog/posts/news3.mdx
similarity index 100%
rename from src/app/blog/posts/news3.mdx
rename to src/app/[locale]/blog/posts/news3.mdx
diff --git a/src/app/blog/posts/news4.mdx b/src/app/[locale]/blog/posts/news4.mdx
similarity index 100%
rename from src/app/blog/posts/news4.mdx
rename to src/app/[locale]/blog/posts/news4.mdx
diff --git a/src/app/blog/posts/news6.mdx b/src/app/[locale]/blog/posts/news6.mdx
similarity index 100%
rename from src/app/blog/posts/news6.mdx
rename to src/app/[locale]/blog/posts/news6.mdx
diff --git a/src/app/blog/posts/news7.mdx b/src/app/[locale]/blog/posts/news7.mdx
similarity index 100%
rename from src/app/blog/posts/news7.mdx
rename to src/app/[locale]/blog/posts/news7.mdx
diff --git a/src/app/blog/posts/news8.mdx b/src/app/[locale]/blog/posts/news8.mdx
similarity index 100%
rename from src/app/blog/posts/news8.mdx
rename to src/app/[locale]/blog/posts/news8.mdx
diff --git a/src/app/blog/posts/news9.mdx b/src/app/[locale]/blog/posts/news9.mdx
similarity index 100%
rename from src/app/blog/posts/news9.mdx
rename to src/app/[locale]/blog/posts/news9.mdx
diff --git a/src/app/blog/posts/summerschool24.mdx b/src/app/[locale]/blog/posts/summerschool24.mdx
similarity index 100%
rename from src/app/blog/posts/summerschool24.mdx
rename to src/app/[locale]/blog/posts/summerschool24.mdx
diff --git a/src/app/blog/posts/summerschool24_de.mdx b/src/app/[locale]/blog/posts/summerschool24_de.mdx
similarity index 100%
rename from src/app/blog/posts/summerschool24_de.mdx
rename to src/app/[locale]/blog/posts/summerschool24_de.mdx
diff --git a/src/app/blog/posts/summerschool25.mdx b/src/app/[locale]/blog/posts/summerschool25.mdx
similarity index 100%
rename from src/app/blog/posts/summerschool25.mdx
rename to src/app/[locale]/blog/posts/summerschool25.mdx
diff --git a/src/app/blog/posts/summerschool25_de.mdx b/src/app/[locale]/blog/posts/summerschool25_de.mdx
similarity index 100%
rename from src/app/blog/posts/summerschool25_de.mdx
rename to src/app/[locale]/blog/posts/summerschool25_de.mdx
diff --git a/src/app/blog/posts/workshop12.mdx b/src/app/[locale]/blog/posts/workshop12.mdx
similarity index 100%
rename from src/app/blog/posts/workshop12.mdx
rename to src/app/[locale]/blog/posts/workshop12.mdx
diff --git a/src/app/contact/page.mdx b/src/app/[locale]/contact/page.mdx
similarity index 100%
rename from src/app/contact/page.mdx
rename to src/app/[locale]/contact/page.mdx
diff --git a/src/app/decalval/about/page.mdx b/src/app/[locale]/decalval/about/page.mdx
similarity index 100%
rename from src/app/decalval/about/page.mdx
rename to src/app/[locale]/decalval/about/page.mdx
diff --git a/src/app/decalval/team/cards/Andreas.mdx b/src/app/[locale]/decalval/team/cards/Andreas.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Andreas.mdx
rename to src/app/[locale]/decalval/team/cards/Andreas.mdx
diff --git a/src/app/decalval/team/cards/Kostas.mdx b/src/app/[locale]/decalval/team/cards/Kostas.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Kostas.mdx
rename to src/app/[locale]/decalval/team/cards/Kostas.mdx
diff --git a/src/app/decalval/team/cards/Martin.mdx b/src/app/[locale]/decalval/team/cards/Martin.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Martin.mdx
rename to src/app/[locale]/decalval/team/cards/Martin.mdx
diff --git a/src/app/decalval/team/cards/Matthias.mdx b/src/app/[locale]/decalval/team/cards/Matthias.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Matthias.mdx
rename to src/app/[locale]/decalval/team/cards/Matthias.mdx
diff --git a/src/app/decalval/team/cards/Mikhail.mdx b/src/app/[locale]/decalval/team/cards/Mikhail.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Mikhail.mdx
rename to src/app/[locale]/decalval/team/cards/Mikhail.mdx
diff --git a/src/app/decalval/team/cards/Nicole.mdx b/src/app/[locale]/decalval/team/cards/Nicole.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Nicole.mdx
rename to src/app/[locale]/decalval/team/cards/Nicole.mdx
diff --git a/src/app/decalval/team/cards/Nuno.mdx b/src/app/[locale]/decalval/team/cards/Nuno.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Nuno.mdx
rename to src/app/[locale]/decalval/team/cards/Nuno.mdx
diff --git a/src/app/decalval/team/cards/Ralph.mdx b/src/app/[locale]/decalval/team/cards/Ralph.mdx
similarity index 100%
rename from src/app/decalval/team/cards/Ralph.mdx
rename to src/app/[locale]/decalval/team/cards/Ralph.mdx
diff --git a/src/app/decalval/team/page.mdx b/src/app/[locale]/decalval/team/page.mdx
similarity index 86%
rename from src/app/decalval/team/page.mdx
rename to src/app/[locale]/decalval/team/page.mdx
index 7d089ce..e1aca7a 100644
--- a/src/app/decalval/team/page.mdx
+++ b/src/app/[locale]/decalval/team/page.mdx
@@ -7,7 +7,7 @@ import TeamCardsGallery from '@/components/TeamCardsGallery'
\ No newline at end of file
diff --git a/src/app/decalval/wps/page.mdx b/src/app/[locale]/decalval/wps/page.mdx
similarity index 100%
rename from src/app/decalval/wps/page.mdx
rename to src/app/[locale]/decalval/wps/page.mdx
diff --git a/src/app/events/polinsar/page.mdx b/src/app/[locale]/events/polinsar/page.mdx
similarity index 100%
rename from src/app/events/polinsar/page.mdx
rename to src/app/[locale]/events/polinsar/page.mdx
diff --git a/src/app/events/summerschool/2022/page.mdx b/src/app/[locale]/events/summerschool/2022/page.mdx
similarity index 100%
rename from src/app/events/summerschool/2022/page.mdx
rename to src/app/[locale]/events/summerschool/2022/page.mdx
diff --git a/src/app/events/summerschool/2024/page.mdx b/src/app/[locale]/events/summerschool/2024/page.mdx
similarity index 100%
rename from src/app/events/summerschool/2024/page.mdx
rename to src/app/[locale]/events/summerschool/2024/page.mdx
diff --git a/src/app/events/summerschool/2025/page.mdx b/src/app/[locale]/events/summerschool/2025/page.mdx
similarity index 100%
rename from src/app/events/summerschool/2025/page.mdx
rename to src/app/[locale]/events/summerschool/2025/page.mdx
diff --git a/src/app/events/summerschool/page.mdx b/src/app/[locale]/events/summerschool/page.mdx
similarity index 100%
rename from src/app/events/summerschool/page.mdx
rename to src/app/[locale]/events/summerschool/page.mdx
diff --git a/src/app/events/webinar/page.mdx b/src/app/[locale]/events/webinar/page.mdx
similarity index 100%
rename from src/app/events/webinar/page.mdx
rename to src/app/[locale]/events/webinar/page.mdx
diff --git a/src/app/[locale]/landing-de.mdx b/src/app/[locale]/landing-de.mdx
new file mode 100644
index 0000000..344efc4
--- /dev/null
+++ b/src/app/[locale]/landing-de.mdx
@@ -0,0 +1,121 @@
+import ContentSplitSection from '@/components/ContentSplitSection';
+import Image from 'next/image';
+import { Button } from "@/components/ui/button"
+import {
+ Card,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@/components/ui/card"
+
+
+
+
+------------------
+
+
+
+Im April 2025 startete die ESA den Earth Explorer BIOMASS. Die Mission verbessert unser Verständnis der Rolle der Landbiosphäre im globalen Kohlenstoffkreislauf, mit klaren Implikationen im Kontext des Klimawandels. Mit Hilfe der Fernerkundung ist BIOMASS die erste Mission mit einem operationellen P-Band-SAR im Weltraum und erfasst den Zustand vor allem tropischer Wälder.
+
+Das Projektbüro BIOMASS ist eine Kooperation des Max-Planck-Instituts für Biogeochemie, der Friedrich-Schiller-Universität Jena, des Deutschen Zentrums für Luft- und Raumfahrt (DLR) und des Helmholtz-Zentrums für Umweltforschung (UFZ). Wir wollen
+
+- relevante Informationen in der nationalen BIOMASS-Community zusammenführen, aufbereiten und verbreiten
+- Lücken identifizieren
+- Lösungen im Kontext der BIOMASS-Mission untersuchen
+- den Dialog im weiteren Kontext der BIOMASS-Mission pflegen
+
+
+Der Koordinierte Deutsche Beitrag zu den BIOMASS Cal/Val-Aktivitäten ist eine Kooperation des Max-Planck-Instituts für Biogeochemie, des GFZ Helmholtz-Zentrums für Geowissenschaften, des DLR, des UFZ und der Technischen Universität Dresden (TUD), unterstützt von der University of Maryland und Wilderness International. Wir wollen
+
+- umfangreiche Gelegenheitsdatenbanken sammeln und Referenzdaten aus Airborne-LiDAR, Drohnenbildern und Radartransekten harmonisieren
+- Beobachtungskampagnen planen, die existierende Domänen und Dichtegradienten abdecken
+- BIOMASS-Produkte für oberirdische Biomasse (AGBD), Waldhöhe (FH) und Waldveränderungen validieren
+- prozessbasierte Modelle für die Dateninterpretation nutzen
+
+
+Für unsere Community bieten wir
+
+- Regelmäßige Webinare zu BIOMASS-Wissenschaft und Anwendungen
+- Sommerschulen zur BIOMASS-Mission
+- Tutorials und Hintergründe über das eo-college
+- Unterstützung für die DLR PolInSAR-Kurse
+
+
+
+
+
+
diff --git a/src/app/page.mdx b/src/app/[locale]/landing-en.mdx
similarity index 96%
rename from src/app/page.mdx
rename to src/app/[locale]/landing-en.mdx
index fa7ba46..ec4f9fb 100644
--- a/src/app/page.mdx
+++ b/src/app/[locale]/landing-en.mdx
@@ -1,4 +1,3 @@
-
import ContentSplitSection from '@/components/ContentSplitSection';
import Image from 'next/image';
import { Button } from "@/components/ui/button"
@@ -125,12 +124,12 @@ The Coordinated German Contribution to the BIOMASS Cal/Val Act
For our community, we host
- Regular webinars on topics related to BIOMASS science and applications
-- Summer schools on the upcoming BIOMASS mission and its context in current research goals
+- Summer schools on the upcoming BIOMASS mission and its context in current research goals
- Tutorials and background information on the BIOMASS mission via the eo-college
-- Support for the DLR’s PolInSAR courses
+- Support for the DLR's PolInSAR courses
-
\ No newline at end of file
+
diff --git a/src/app/[locale]/layout.tsx b/src/app/[locale]/layout.tsx
new file mode 100644
index 0000000..a8e2510
--- /dev/null
+++ b/src/app/[locale]/layout.tsx
@@ -0,0 +1,29 @@
+import { LocaleProvider } from '@/contexts/LocaleContext'
+import { SetHtmlLang } from '@/components/SetHtmlLang'
+import Menu from '@/components/Menu'
+import Footer from '@/components/Footer'
+import { locales, isValidLocale, defaultLocale, type Locale } from '@/config/i18n'
+
+export function generateStaticParams() {
+ return locales.map((locale) => ({ locale }))
+}
+
+export default async function LocaleLayout({
+ children,
+ params,
+}: {
+ children: React.ReactNode
+ params: Promise<{ locale: string }>
+}) {
+ const { locale: raw } = await params
+ const locale: Locale = isValidLocale(raw) ? raw : defaultLocale
+
+ return (
+
+
+
+ {children}
+
+
+ )
+}
diff --git a/src/app/[locale]/page.tsx b/src/app/[locale]/page.tsx
new file mode 100644
index 0000000..cb4f05d
--- /dev/null
+++ b/src/app/[locale]/page.tsx
@@ -0,0 +1,23 @@
+import { isValidLocale, defaultLocale, type Locale, locales } from '@/config/i18n'
+import LandingEn from './landing-en.mdx'
+import LandingDe from './landing-de.mdx'
+
+const landing = {
+ en: LandingEn,
+ de: LandingDe,
+} as const
+
+interface PageProps {
+ params: Promise<{ locale: string }>
+}
+
+export async function generateStaticParams() {
+ return (locales as readonly string[]).map((locale) => ({ locale }))
+}
+
+export default async function LocaleHomePage({ params }: PageProps) {
+ const { locale: raw } = await params
+ const locale: Locale = isValidLocale(raw) ? raw : defaultLocale
+ const Page = landing[locale] ?? landing[defaultLocale]
+ return
+}
diff --git a/src/app/[locale]/project/about/about-de.mdx b/src/app/[locale]/project/about/about-de.mdx
new file mode 100644
index 0000000..c336ebc
--- /dev/null
+++ b/src/app/[locale]/project/about/about-de.mdx
@@ -0,0 +1,62 @@
+import Image from 'next/image';
+import { FaGlobeEurope } from "react-icons/fa";
+import { FaSatelliteDish } from "react-icons/fa";
+
+
+ Informationen in der nationalen BIOMASS-Community zusammenführen, aufbereiten und verbreiten
+ Lücken identifizieren
+ Lösungen im Kontext der BIOMASS-Mission untersuchen
+ den Dialog im weiteren Kontext der BIOMASS-Mission pflegen
+
+ Earth Explorer BIOMASS @ ESA / Airbus Defence and Space
+
+
+
+Anlässlich der ESA BIOMASS-Mission ist es wichtig, den aktuellen Kenntnisstand zu Herausforderungen und Chancen bei der Beobachtung von Biomasse in terrestrischen Ökosystemen zu bündeln und weiterzuentwickeln. Bei den ESA Earth Explorers zielt BIOMASS darauf ab, die Rolle der Landbiosphäre im globalen Kohlenstoffkreislauf besser zu verstehen – mit deutlichen Auswirkungen im Kontext des Klimawandels. Der Informationsgehalt zur räumlichen und zeitlichen Variabilität von P-Band-Biomasse ist für terrestrische Ökosystemstudien beispiellos, besonders in Bezug auf Landnutzungsänderungen und Störungsdynamiken, und verbessert die Modellierung des globalen Kohlenstoffs. Die Mission bringt Herausforderungen in Instrumentendesign, Retrieval-Algorithmen, Kalibrierungs- und Validierungsstrategien sowie bei Datenkonzepten und Anwendungen mit sich.
+
+
+
+
+ Unsere Projektpartner Carsten Pathe und Christiane Schmullius (FSU) haben diese Übersicht zum Projektbüro und zur BIOMASS-Mission erstellt; sie können sie hier herunterladen.
+
diff --git a/src/app/project/about/page.mdx b/src/app/[locale]/project/about/about-en.mdx
similarity index 83%
rename from src/app/project/about/page.mdx
rename to src/app/[locale]/project/about/about-en.mdx
index 4e53d1b..4718636 100644
--- a/src/app/project/about/page.mdx
+++ b/src/app/[locale]/project/about/about-en.mdx
@@ -74,7 +74,7 @@ import {
regular virtual workshops on different topics around BIOMASS
summer Schools (2022, 2024, 2025 in Jena)
an online presentation on all aspects of the BIOMASS mission via eo-college
-
+
@@ -85,7 +85,7 @@ import {
-In the advent of ESA’s BIOMASS mission it is relevant to synthesize and bring forth the current understanding of challenges and opportunities in monitoring biomass in terrestrial ecosystems to further develop our knowledge of the Earth system. Within ESA’s Earth Explorers, the primary objective of BIOMASS is to improve our understanding on the role of the land biosphere on the global carbon cycle, with clear implications in a context of climate change. The information content in characterizing the spatial and temporal variability in P-band biomass is unprecedented and unique for terrestrial ecosystem studies, especially with what relates to land use change and disturbance dynamics fluxes, ultimately improving the ability to model the global carbon. The mission necessarily embeds challenges across the board, from instrument design, definition of retrieval algorithms and calibration-validation strategies, to downstream data concepts and deployment for a wide diversity of applications.
+In the advent of ESA's BIOMASS mission it is relevant to synthesize and bring forth the current understanding of challenges and opportunities in monitoring biomass in terrestrial ecosystems to further develop our knowledge of the Earth system. Within ESA's Earth Explorers, the primary objective of BIOMASS is to improve our understanding on the role of the land biosphere on the global carbon cycle, with clear implications in a context of climate change. The information content in characterizing the spatial and temporal variability in P-band biomass is unprecedented and unique for terrestrial ecosystem studies, especially with what relates to land use change and disturbance dynamics fluxes, ultimately improving the ability to model the global carbon. The mission necessarily embeds challenges across the board, from instrument design, definition of retrieval algorithms and calibration-validation strategies, to downstream data concepts and deployment for a wide diversity of applications.
+}
+
+export default async function ProjectAboutPage({ params }: PageProps) {
+ const { locale: raw } = await params
+ const locale: Locale = raw && isValidLocale(raw) ? raw : defaultLocale
+ const Page = content[locale] ?? content.en
+ return
+}
diff --git a/src/app/project/publications/page.mdx b/src/app/[locale]/project/publications/page.mdx
similarity index 100%
rename from src/app/project/publications/page.mdx
rename to src/app/[locale]/project/publications/page.mdx
diff --git a/src/app/project/team/page.mdx b/src/app/[locale]/project/team/page.mdx
similarity index 100%
rename from src/app/project/team/page.mdx
rename to src/app/[locale]/project/team/page.mdx
diff --git a/src/app/project/wps/page.mdx b/src/app/[locale]/project/wps/page.mdx
similarity index 100%
rename from src/app/project/wps/page.mdx
rename to src/app/[locale]/project/wps/page.mdx
diff --git a/src/app/resources/newsletter/page.mdx b/src/app/[locale]/resources/newsletter/page.mdx
similarity index 100%
rename from src/app/resources/newsletter/page.mdx
rename to src/app/[locale]/resources/newsletter/page.mdx
diff --git a/src/app/resources/publications/page.mdx b/src/app/[locale]/resources/publications/page.mdx
similarity index 100%
rename from src/app/resources/publications/page.mdx
rename to src/app/[locale]/resources/publications/page.mdx
diff --git a/src/app/resources/relatedmissions/page.mdx b/src/app/[locale]/resources/relatedmissions/page.mdx
similarity index 100%
rename from src/app/resources/relatedmissions/page.mdx
rename to src/app/[locale]/resources/relatedmissions/page.mdx
diff --git a/src/app/resources/tools-data/page.mdx b/src/app/[locale]/resources/tools-data/page.mdx
similarity index 100%
rename from src/app/resources/tools-data/page.mdx
rename to src/app/[locale]/resources/tools-data/page.mdx
diff --git a/src/app/terms/imprint/page.mdx b/src/app/[locale]/terms/imprint/page.mdx
similarity index 100%
rename from src/app/terms/imprint/page.mdx
rename to src/app/[locale]/terms/imprint/page.mdx
diff --git a/src/app/terms/privacy/page.mdx b/src/app/[locale]/terms/privacy/page.mdx
similarity index 100%
rename from src/app/terms/privacy/page.mdx
rename to src/app/[locale]/terms/privacy/page.mdx
diff --git a/src/app/blog/page.tsx b/src/app/blog/page.tsx
deleted file mode 100644
index 6324c27..0000000
--- a/src/app/blog/page.tsx
+++ /dev/null
@@ -1,16 +0,0 @@
-import { BlogPosts } from '@/components/posts'
-
-export const metadata = {
- title: 'Posts',
- description: 'Read my posts.',
-}
-
-export default function Page() {
- return (
-
-
-
NEWS
-
-
- )
-}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index ed417b6..fa6b88f 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -1,10 +1,7 @@
import type { Metadata } from "next";
import { ThemeProvider } from 'next-themes'
-import Menu from "@/components/Menu";
-import Footer from "@/components/Footer";
import "./globals.css";
-
export const metadata: Metadata = {
title: "eebiomass",
description: "Project Office BIOMASS.",
@@ -16,14 +13,10 @@ export default function RootLayout({
children: React.ReactNode;
}>) {
return (
-
-
+
+
-
{children}
-
diff --git a/src/app/not-found.js b/src/app/not-found.js
index b85178c..f220b2c 100644
--- a/src/app/not-found.js
+++ b/src/app/not-found.js
@@ -1,4 +1,6 @@
import Link from 'next/link'
+import { defaultLocale } from '@/config/i18n'
+
export default function NotFound() {
return (
@@ -10,8 +12,8 @@ export default function NotFound() {
Let insight guide us back to familiar ground.
-
- Go back to Home
+
+ Go back to Home
diff --git a/src/app/page.tsx b/src/app/page.tsx
new file mode 100644
index 0000000..ccc4129
--- /dev/null
+++ b/src/app/page.tsx
@@ -0,0 +1,21 @@
+'use client'
+
+import { useEffect } from 'react'
+import Link from 'next/link'
+import { defaultLocale } from '@/config/i18n'
+
+export default function RootPage() {
+ useEffect(() => {
+ window.location.replace(`/${defaultLocale}`)
+ }, [])
+
+ return (
+
+
eebiomass
+
Weiterleitung …
+
+ Weiter zur Startseite
+
+
+ )
+}
diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts
new file mode 100644
index 0000000..a653799
--- /dev/null
+++ b/src/app/sitemap.ts
@@ -0,0 +1,3 @@
+export const dynamic = 'force-static'
+
+export { default } from '@/utils/sitemap'
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index b1facde..d41ab7b 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -6,18 +6,19 @@ import Address from './Address';
import Contacts from './Contacts';
import Funding from './Funding';
import ProjectFunding from '@/assets/ProjectFunding';
-import { navFooter } from '@/config/nav';
+import { getNavFooter } from '@/config/nav';
import { contactInfo } from '@/assets/contacts';
import { fundsLogos } from '@/assets/fundingLogos';
-import Socials from '@/components/Socials'
-import { socialLinks } from '@/utils/socials'
+import Socials from '@/components/Socials';
+import { socialLinks } from '@/utils/socials';
+import type { Locale } from '@/config/i18n';
-const Footer = ({ className = "" }: FooterProps) => {
+const Footer = ({ className = '', locale }: FooterProps & { locale: Locale }) => {
+ const links = getNavFooter(locale);
return (
diff --git a/src/components/LocaleLink.tsx b/src/components/LocaleLink.tsx
new file mode 100644
index 0000000..1204a6c
--- /dev/null
+++ b/src/components/LocaleLink.tsx
@@ -0,0 +1,34 @@
+'use client'
+
+import Link from 'next/link'
+import { useLocale } from '@/contexts/LocaleContext'
+import { isValidLocale } from '@/config/i18n'
+
+/** Use for internal links in MDX so they are prefixed with /[locale] */
+export function LocaleLink(props: React.AnchorHTMLAttributes) {
+ const locale = useLocale()
+ const href = props.href
+ if (!href || typeof href !== 'string') {
+ return
+ }
+ // External or hash: keep as-is
+ if (href.startsWith('http') || href.startsWith('//') || href.startsWith('#')) {
+ return
+ }
+ // Already has a known locale prefix: use as-is
+ const firstSegment = href.split('/').filter(Boolean)[0]
+ if (firstSegment && isValidLocale(firstSegment)) {
+ return (
+
+ {props.children}
+
+ )
+ }
+ // Internal: prefix with /{locale}
+ const prefixed = href.startsWith('/') ? `/${locale}${href}` : `/${locale}/${href}`
+ return (
+
+ {props.children}
+
+ )
+}
diff --git a/src/components/LocaleSwitcher.tsx b/src/components/LocaleSwitcher.tsx
new file mode 100644
index 0000000..4bd4f88
--- /dev/null
+++ b/src/components/LocaleSwitcher.tsx
@@ -0,0 +1,46 @@
+'use client'
+
+import Link from 'next/link'
+import { usePathname } from 'next/navigation'
+import { locales, type Locale } from '@/config/i18n'
+
+const labels: Record = { de: 'DE', en: 'EN' }
+const titles: Record = { de: 'Deutsch', en: 'English' }
+
+export default function LocaleSwitcher({ currentLocale }: { currentLocale: Locale }) {
+ const pathname = usePathname() ?? ''
+
+ return (
+