This commit is contained in:
2026-05-27 20:35:54 +02:00
parent 26713b13b1
commit 9d80dc8875
20 changed files with 979 additions and 175 deletions

View File

@@ -0,0 +1,21 @@
import { notFound, permanentRedirect } from 'next/navigation'
import { getGermanSeoPageBySlug, germanSeoPageSlugs } from '@/lib/seoPages'
type GermanSeoRouteProps = {
params: Promise<{ slug: string }>
}
export function generateStaticParams() {
return germanSeoPageSlugs.map((slug) => ({ slug }))
}
export default async function GermanSeoRoute({ params }: GermanSeoRouteProps) {
const { slug } = await params
const profile = getGermanSeoPageBySlug(slug)
if (!profile) {
notFound()
}
permanentRedirect(`/${slug}`)
}

View File

@@ -0,0 +1,5 @@
import { permanentRedirect } from 'next/navigation'
export default function GermanHomeRedirect() {
permanentRedirect('/')
}

View File

@@ -0,0 +1,64 @@
import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
import SeoCategoryPage from '@/components/SeoCategoryPage'
import { getSpanishSeoPageBySlug, spanishSeoPageSlugs } from '@/lib/spanishSeoPages'
import { siteConfig } from '@/lib/site'
type SpanishSeoRouteProps = {
params: Promise<{ slug: string }>
}
export function generateStaticParams() {
return spanishSeoPageSlugs
.filter((slug) => slug !== 'comparar-google-lens')
.map((slug) => ({ slug }))
}
export async function generateMetadata({ params }: SpanishSeoRouteProps): Promise<Metadata> {
const { slug } = await params
if (slug === 'comparar-google-lens') {
notFound()
}
const profile = getSpanishSeoPageBySlug(slug)
if (!profile) {
return {}
}
return {
title: profile.metaTitle,
description: profile.metaDescription,
alternates: {
canonical: profile.canonical,
languages: {
es: profile.canonical,
'x-default': '/',
},
},
openGraph: {
title: profile.metaTitle,
description: profile.metaDescription,
url: `${siteConfig.domain}${profile.canonical}`,
type: 'website',
locale: 'es_ES',
images: [{ url: '/og-image.png', width: 1200, height: 630, alt: profile.metaTitle }],
},
twitter: {
card: 'summary_large_image',
title: profile.metaTitle,
description: profile.metaDescription,
images: ['/og-image.png'],
},
}
}
export default async function SpanishSeoRoute({ params }: SpanishSeoRouteProps) {
const { slug } = await params
const profile = getSpanishSeoPageBySlug(slug)
if (!profile) {
notFound()
}
return <SeoCategoryPage profile={profile} />
}

View File

@@ -0,0 +1,40 @@
import type { Metadata } from 'next'
import { notFound } from 'next/navigation'
import SeoCategoryPage from '@/components/SeoCategoryPage'
import { getSpanishSeoPageBySlug } from '@/lib/spanishSeoPages'
import { siteConfig } from '@/lib/site'
const profile = getSpanishSeoPageBySlug('comparar-google-lens')
export const metadata: Metadata = !profile
? {}
: {
title: profile.metaTitle,
description: profile.metaDescription,
alternates: {
canonical: profile.canonical,
languages: {
es: profile.canonical,
'x-default': '/',
},
},
openGraph: {
title: profile.metaTitle,
description: profile.metaDescription,
url: `${siteConfig.domain}${profile.canonical}`,
type: 'website',
locale: 'es_ES',
images: [{ url: '/og-image.png', width: 1200, height: 630, alt: profile.metaTitle }],
},
twitter: {
card: 'summary_large_image',
title: profile.metaTitle,
description: profile.metaDescription,
images: ['/og-image.png'],
},
}
export default function SpanishGoogleLensComparisonPage() {
if (!profile) notFound()
return <SeoCategoryPage profile={profile} />
}

View File

@@ -0,0 +1,81 @@
import type { Metadata } from 'next'
import Link from 'next/link'
import Navbar from '@/components/Navbar'
import Footer from '@/components/Footer'
import { siteConfig } from '@/lib/site'
import { spanishSeoPageProfiles } from '@/lib/spanishSeoPages'
export const metadata: Metadata = {
title: 'GreenLens en español - Identificar y cuidar plantas',
description:
'GreenLens en español: identifica plantas por foto, organiza cuidados, recibe recordatorios y diagnostica sintomas comunes.',
alternates: {
canonical: '/es',
languages: {
es: '/es',
'x-default': '/',
},
},
openGraph: {
title: 'GreenLens en español - Identificar y cuidar plantas',
description:
'Identifica plantas por foto, organiza cuidados, recibe recordatorios y diagnostica sintomas comunes con GreenLens.',
url: `${siteConfig.domain}/es`,
type: 'website',
locale: 'es_ES',
},
}
const pages = [
spanishSeoPageProfiles['identificador-de-plantas'],
spanishSeoPageProfiles['escaner-de-plantas'],
spanishSeoPageProfiles['app-para-cuidar-plantas'],
spanishSeoPageProfiles['diagnosticar-enfermedades-plantas'],
spanishSeoPageProfiles['comparar-google-lens'],
]
export default function SpanishHomePage() {
return (
<>
<Navbar />
<main className="comparison-page">
<section className="comparison-hero">
<div className="container comparison-hero-grid">
<div className="comparison-hero-copy">
<p className="tag">GreenLens en español</p>
<h1>Identifica, cuida y rescata tus plantas con mas claridad.</h1>
<p className="comparison-lead">
Escanea una planta, entiende que necesita y organiza cuidados, recordatorios y diagnostico desde una sola app.
</p>
<div className="comparison-actions">
<a href="#cta" className="btn-primary">Probar GreenLens</a>
<a href="#guias" className="btn-outline">Ver guias</a>
</div>
</div>
<aside className="comparison-hero-card">
<p className="comparison-card-label">Arquitectura en español</p>
<p>
Esta seccion agrupa las paginas principales para busquedas en español:
identificacion, escaneo, cuidado, diagnostico y comparacion con Google Lens.
</p>
</aside>
</div>
</section>
<section className="comparison-links" id="guias">
<div className="container comparison-links-grid">
{pages.map((page) => (
<Link key={page.slug} href={page.canonical} className="comparison-link-card">
<p className="comparison-mini-label">Guia</p>
<h2>{page.h1}</h2>
<p>{page.metaDescription}</p>
</Link>
))}
</div>
</section>
</main>
<Footer />
</>
)
}

View File

@@ -7,36 +7,41 @@ import { siteConfig, hasIosStoreUrl } from '@/lib/site'
export const metadata: Metadata = {
metadataBase: new URL(siteConfig.domain),
title: {
default: 'GreenLens Pflanzen erkennen & Pflege-App',
default: 'GreenLens - Pflanzen erkennen & Pflege planen',
template: '%s',
},
description:
'GreenLens erkennt Pflanzen per Foto in Sekunden und liefert sofort Pflegeplan, Gießerinnerungen und Gesundheitscheck — alles in einer App.',
'GreenLens erkennt Pflanzen per Foto in Sekunden und gibt dir Pflegepläne, Erinnerungen und Gesundheitschecks in einer App.',
keywords: [
'Pflanzen erkennen App',
'Pflanzen bestimmen per Foto',
'Blumen Scanner',
'Pflanzen erkennen per Foto',
'Pflanzen Pflege App',
'plant identifier app',
'plant care app',
'Pflanzen App',
'plant scanner',
'plant disease identifier',
'identificador de plantas',
'GreenLens',
],
authors: [{ name: siteConfig.name }],
openGraph: {
title: 'GreenLens Pflanzen erkennen & Pflege-App',
description: 'Pflanzen per Foto erkennen, Pflegeplan erhalten und Gesundheitsprobleme diagnostizieren — alles in einer App.',
title: 'GreenLens - Pflanzen erkennen & Pflege planen',
description: 'Pflanzen per Foto erkennen, Pflegeplan erhalten und Pflanzenprobleme in einer App einordnen.',
type: 'website',
url: siteConfig.domain,
},
alternates: {
// Do not emit hreflang until each language has its own URL.
languages: {},
languages: {
de: '/',
es: '/es',
'x-default': '/',
},
},
twitter: {
card: 'summary_large_image',
title: 'GreenLens Pflanzen erkennen & Pflege-App',
description: 'Pflanzen per Foto erkennen, Pflegeplan erhalten und Gesundheitsprobleme diagnostizieren — alles in einer App.',
title: 'GreenLens - Pflanzen erkennen & Pflege planen',
description: 'Pflanzen per Foto erkennen, Pflegeplan erhalten und Pflanzenprobleme in einer App einordnen.',
},
}
@@ -61,7 +66,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
'@type': 'WebSite',
name: siteConfig.name,
url: siteConfig.domain,
inLanguage: ['de', 'en', 'es'],
inLanguage: ['en', 'de', 'es'],
},
{
'@context': 'https://schema.org',
@@ -70,8 +75,8 @@ export default async function RootLayout({ children }: { children: React.ReactNo
operatingSystem: 'iOS, Android',
applicationCategory: 'LifestyleApplication',
description:
'Pflanzen per Foto erkennen, Pflegeplan erhalten und Gesundheitsprobleme diagnostizieren.',
inLanguage: ['de', 'en', 'es'],
'Pflanzen per Foto erkennen, Pflegepläne nutzen und Pflanzenprobleme einordnen.',
inLanguage: ['en', 'de', 'es'],
...(hasIosStoreUrl && { downloadUrl: siteConfig.iosAppStoreUrl }),
offers: {
'@type': 'Offer',

View File

@@ -1,4 +1,5 @@
import type { Metadata } from 'next'
import Link from 'next/link'
import Navbar from '@/components/Navbar'
import Hero from '@/components/Hero'
import Ticker from '@/components/Ticker'
@@ -11,39 +12,47 @@ import CTA from '@/components/CTA'
import Footer from '@/components/Footer'
export const metadata: Metadata = {
title: 'GreenLens - Pflanzen erkennen & Pflege planen',
description:
'Scanne Pflanzen per Foto, verstehe ihre Bedürfnisse und organisiere Pflege, Erinnerungen und Sammlung in einer App.',
alternates: {
canonical: '/',
languages: {
de: '/',
es: '/es',
'x-default': '/',
},
},
}
const howToSchema = {
'@context': 'https://schema.org',
'@type': 'HowTo',
name: 'How to identify a plant with GreenLens',
name: 'So erkennst du eine Pflanze mit GreenLens',
step: [
{
'@type': 'HowToStep',
position: 1,
name: 'Photograph your plant',
text: 'Open the app, point the camera at your plant and tap Scan.',
name: 'Pflanze fotografieren',
text: 'Öffne die App, richte die Kamera auf deine Pflanze und tippe auf Scan.',
},
{
'@type': 'HowToStep',
position: 2,
name: 'AI identifies instantly',
text: 'In under a second you get the exact name, species and all key details.',
name: 'KI identifiziert sofort',
text: 'In unter einer Sekunde erhältst du den Namen, die Art und die wichtigsten Eckdaten.',
},
{
'@type': 'HowToStep',
position: 3,
name: 'Receive care plan',
text: 'GreenLens automatically creates a personalized care plan for your plant and location.',
name: 'Pflegeplan erhalten',
text: 'GreenLens erstellt automatisch einen Pflegeplan passend zu deiner Pflanze und deinem Standort.',
},
{
'@type': 'HowToStep',
position: 4,
name: 'Track growth',
text: 'Document photos, track watering and get reminded of important care dates.',
name: 'Wachstum verfolgen',
text: 'Dokumentiere Fotos, verfolge das Gießen und lass dich an wichtige Pflegetermine erinnern.',
},
],
}
@@ -54,42 +63,42 @@ const faqSchema = {
mainEntity: [
{
'@type': 'Question',
name: 'How does GreenLens identify a plant?',
name: 'Wie erkennt GreenLens eine Pflanze?',
acceptedAnswer: {
'@type': 'Answer',
text: 'GreenLens analyzes the plant photo and combines that with app-side care guidance so you can move from scan to next steps faster.',
text: 'GreenLens analysiert das Pflanzenfoto und verbindet das Ergebnis mit Pflegehinweisen in der App, damit du schneller zu klaren nächsten Schritten kommst.',
},
},
{
'@type': 'Question',
name: 'Is GreenLens free to use?',
name: 'Ist GreenLens kostenlos?',
acceptedAnswer: {
'@type': 'Answer',
text: 'GreenLens includes free functionality plus paid options such as subscriptions and credit top-ups for advanced AI features.',
text: 'GreenLens bietet kostenlose Funktionen und zusätzlich kostenpflichtige Optionen wie Abos und Credit-Top-ups für erweiterte KI-Funktionen.',
},
},
{
'@type': 'Question',
name: 'Can I use GreenLens offline?',
name: 'Kann ich GreenLens offline nutzen?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Plant identification and health checks require an internet connection. Your saved collection, care notes, and watering reminders are available offline.',
text: 'Pflanzenidentifikation und Gesundheitscheck benötigen eine Internetverbindung. Deine gespeicherte Sammlung, Pflegenotizen und Gieß-Erinnerungen sind offline verfügbar.',
},
},
{
'@type': 'Question',
name: 'What kind of plants can I use GreenLens for?',
name: 'Für welche Pflanzen kann ich GreenLens nutzen?',
acceptedAnswer: {
'@type': 'Answer',
text: 'GreenLens covers 450+ plant species including houseplants, garden plants, and succulents. It is built for everyday plant owners who want identification and care guidance in one place.',
text: 'GreenLens umfasst über 450 Pflanzenarten, darunter Zimmerpflanzen, Gartenpflanzen und Sukkulenten. Die App richtet sich an Pflanzenbesitzer, die Identifikation und Pflege an einem Ort wollen.',
},
},
{
'@type': 'Question',
name: 'How do I start my plant collection in GreenLens?',
name: 'Wie starte ich meine Pflanzensammlung?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Start with a scan, review the result, and save the plant to your collection to keep notes, reminders, and follow-up care in one place.',
text: 'Starte mit einem Scan, prüfe das Ergebnis und speichere die Pflanze in deiner Sammlung, damit Notizen, Erinnerungen und Pflege an einem Ort bleiben.',
},
},
],
@@ -115,6 +124,36 @@ export default function Home() {
<Intelligence />
<HowItWorks />
<FAQ />
<section className="comparison-links" aria-labelledby="homepage-guides-heading">
<div className="container">
<div className="comparison-section-head">
<p className="tag">Guides</p>
<h2 id="homepage-guides-heading">Pflanzen schneller erkennen und richtig handeln.</h2>
</div>
<div className="comparison-links-grid">
<Link href="/blumen-scanner" className="comparison-link-card">
<p className="comparison-mini-label">Blumen</p>
<h3>Blumen Scanner</h3>
<p>Blumen per Foto erkennen, Namen erhalten und direkt Pflegehinweise nutzen.</p>
</Link>
<Link href="/blumen-scanner" className="comparison-link-card">
<p className="comparison-mini-label">Foto-Erkennung</p>
<h3>Blumen per Foto erkennen</h3>
<p>Ideal, wenn du eine Blume fotografiert hast und sofort wissen willst, was sie braucht.</p>
</Link>
<Link href="/pflanzen-bestimmen" className="comparison-link-card">
<p className="comparison-mini-label">Pflanzen</p>
<h3>Pflanzen bestimmen</h3>
<p>Pflanze scannen, Artname sehen und den passenden Pflegeplan erhalten.</p>
</Link>
<Link href="/pflanzen-krankheiten-erkennen" className="comparison-link-card">
<p className="comparison-mini-label">Diagnose</p>
<h3>Pflanzenkrankheiten erkennen</h3>
<p>Gelbe Blätter, braune Spitzen oder weiche Stiele einordnen und den nächsten Schritt finden.</p>
</Link>
</div>
</div>
</section>
<CTA />
</main>
<Footer />

View File

@@ -1,4 +1,6 @@
import { MetadataRoute } from 'next'
import { germanSeoPageSlugs, getGermanSeoPageBySlug } from '@/lib/seoPages'
import { spanishSeoPageProfiles, spanishSeoPageSlugs } from '@/lib/spanishSeoPages'
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = (process.env.NEXT_PUBLIC_SITE_URL || 'https://greenlenspro.com').trim()
@@ -34,24 +36,6 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: 'monthly',
priority: 0.75,
},
{
url: `${baseUrl}/pflanzen-erkennen-app`,
lastModified: new Date('2026-05-10'),
changeFrequency: 'monthly',
priority: 0.85,
},
{
url: `${baseUrl}/blumen-scanner`,
lastModified: new Date('2026-05-10'),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/pflanzen-bestimmen`,
lastModified: new Date('2026-05-10'),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/vs/picturethis`,
lastModified: new Date('2026-04-27'),
@@ -106,24 +90,6 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: 'monthly',
priority: 0.75,
},
{
url: `${baseUrl}/pflanzen-krankheiten-erkennen`,
lastModified: new Date('2026-05-10'),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/pflanzen-pflege-app`,
lastModified: new Date('2026-05-10'),
changeFrequency: 'monthly',
priority: 0.75,
},
{
url: `${baseUrl}/zimmerpflanzen-bestimmen`,
lastModified: new Date('2026-05-10'),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/best-plant-identification-app`,
lastModified: new Date('2026-04-27'),
@@ -136,12 +102,6 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: `${baseUrl}/pflanzen-erkennen-kostenlos`,
lastModified: new Date('2026-04-27'),
changeFrequency: 'monthly',
priority: 0.85,
},
{
url: `${baseUrl}/imprint`,
lastModified: new Date('2026-04-08'),
@@ -160,5 +120,26 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: 'monthly',
priority: 0.3,
},
...germanSeoPageSlugs.map((slug) => {
const profile = getGermanSeoPageBySlug(slug)
return {
url: `${baseUrl}${profile?.canonical ?? `/${slug}`}`,
lastModified: new Date('2026-05-20'),
changeFrequency: 'monthly' as const,
priority: slug === 'pflanzen-erkennen-kostenlos' || slug === 'pflanzen-erkennen-app' ? 0.85 : 0.75,
}
}),
{
url: `${baseUrl}/es`,
lastModified: new Date('2026-05-20'),
changeFrequency: 'monthly',
priority: 0.85,
},
...spanishSeoPageSlugs.map((slug) => ({
url: `${baseUrl}${spanishSeoPageProfiles[slug].canonical}`,
lastModified: new Date('2026-05-20'),
changeFrequency: 'monthly' as const,
priority: slug === 'identificador-de-plantas' ? 0.85 : 0.75,
})),
]
}