SEO
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type { Metadata } from 'next'
|
||||
import Home from '../page'
|
||||
import { siteConfig } from '@/lib/site'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'GreenLens - Plant Identifier & Care Planner',
|
||||
@@ -18,11 +19,18 @@ export const metadata: Metadata = {
|
||||
title: 'GreenLens - Plant Identifier & Care Planner',
|
||||
description:
|
||||
'Scan plants by photo, understand what they need, and keep care, reminders, and your collection in one app.',
|
||||
url: `${siteConfig.domain}/en`,
|
||||
type: 'website',
|
||||
locale: 'en_US',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: 'GreenLens - Plant Identifier & Care Planner',
|
||||
description:
|
||||
'Scan plants by photo, understand what they need, and keep care, reminders, and your collection in one app.',
|
||||
},
|
||||
}
|
||||
|
||||
export default function EnglishHomePage() {
|
||||
return <Home />
|
||||
return <Home locale="en" />
|
||||
}
|
||||
|
||||
@@ -23,8 +23,14 @@ export const metadata: Metadata = {
|
||||
type: 'website',
|
||||
locale: 'es_ES',
|
||||
},
|
||||
twitter: {
|
||||
card: 'summary_large_image',
|
||||
title: 'GreenLens - Identificar y cuidar plantas',
|
||||
description:
|
||||
'Identifica plantas por foto, organiza cuidados, recibe recordatorios y diagnostica síntomas comunes con GreenLens.',
|
||||
},
|
||||
}
|
||||
|
||||
export default function SpanishHomePage() {
|
||||
return <Home />
|
||||
return <Home locale="es" />
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { cookies } from 'next/headers'
|
||||
import { headers } from 'next/headers'
|
||||
import './globals.css'
|
||||
import { LangProvider } from '@/context/LangContext'
|
||||
import { siteConfig, hasIosStoreUrl } from '@/lib/site'
|
||||
import { siteConfig, hasIosStoreUrl, hasAndroidStoreUrl } from '@/lib/site'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
metadataBase: new URL(siteConfig.domain),
|
||||
@@ -54,6 +54,20 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
const lang = (routeLang ?? cookieStore.get('lang')?.value ?? 'de') as 'de' | 'en' | 'es'
|
||||
const validLangs = ['de', 'en', 'es']
|
||||
const htmlLang = validLangs.includes(lang) ? lang : 'de'
|
||||
const schemaDescription = {
|
||||
de: 'Pflanzen per Foto einordnen, Pflegepläne nutzen und sichtbare Pflanzenprobleme prüfen.',
|
||||
en: 'Assess plants from photos, use care plans, and review visible plant problems.',
|
||||
es: 'Evalúa plantas con fotos, utiliza planes de cuidado y revisa problemas visibles.',
|
||||
}[htmlLang]
|
||||
const organizationDescription = {
|
||||
de: 'GreenLens ist eine App zur Pflanzenerkennung und Pflegeplanung.',
|
||||
en: 'GreenLens is an app for plant identification and care planning.',
|
||||
es: 'GreenLens es una app para identificar plantas y planificar sus cuidados.',
|
||||
}[htmlLang]
|
||||
const operatingSystems = [
|
||||
hasIosStoreUrl ? 'iOS' : null,
|
||||
hasAndroidStoreUrl ? 'Android' : null,
|
||||
].filter((value): value is string => Boolean(value))
|
||||
|
||||
return (
|
||||
<html lang={htmlLang}>
|
||||
@@ -76,11 +90,10 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SoftwareApplication',
|
||||
name: siteConfig.name,
|
||||
operatingSystem: 'iOS, Android',
|
||||
...(operatingSystems.length > 0 && { operatingSystem: operatingSystems.join(', ') }),
|
||||
applicationCategory: 'LifestyleApplication',
|
||||
description:
|
||||
'Pflanzen per Foto erkennen, Pflegepläne nutzen und Pflanzenprobleme einordnen.',
|
||||
inLanguage: ['en', 'de', 'es'],
|
||||
description: schemaDescription,
|
||||
inLanguage: htmlLang,
|
||||
...(hasIosStoreUrl && { downloadUrl: siteConfig.iosAppStoreUrl }),
|
||||
offers: {
|
||||
'@type': 'Offer',
|
||||
@@ -93,8 +106,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
'@type': 'Organization',
|
||||
name: siteConfig.name,
|
||||
url: siteConfig.domain,
|
||||
description:
|
||||
'GreenLens ist eine App zur Pflanzenerkennung und Pflegeplanung für iOS und Android.',
|
||||
description: organizationDescription,
|
||||
contactPoint: {
|
||||
'@type': 'ContactPoint',
|
||||
contactType: 'customer support',
|
||||
@@ -109,7 +121,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
|
||||
/>
|
||||
</head>
|
||||
<body>
|
||||
<LangProvider>{children}</LangProvider>
|
||||
<LangProvider initialLang={htmlLang}>{children}</LangProvider>
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
|
||||
@@ -10,6 +10,8 @@ import HowItWorks from '@/components/HowItWorks'
|
||||
import FAQ from '@/components/FAQ'
|
||||
import CTA from '@/components/CTA'
|
||||
import Footer from '@/components/Footer'
|
||||
import type { Lang } from '@/lib/i18n'
|
||||
import { getHomeSchemas } from '@/lib/homeSchema'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: 'GreenLens - Pflanzen erkennen & Pflege planen',
|
||||
@@ -26,86 +28,8 @@ export const metadata: Metadata = {
|
||||
},
|
||||
}
|
||||
|
||||
const howToSchema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'HowTo',
|
||||
name: 'So erkennst du eine Pflanze mit GreenLens',
|
||||
step: [
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
position: 1,
|
||||
name: 'Pflanze fotografieren',
|
||||
text: 'Öffne die App, richte die Kamera auf deine Pflanze und tippe auf Scan.',
|
||||
},
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
position: 2,
|
||||
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: 'Pflegeplan erhalten',
|
||||
text: 'GreenLens erstellt automatisch einen Pflegeplan passend zu deiner Pflanze und deinem Standort.',
|
||||
},
|
||||
{
|
||||
'@type': 'HowToStep',
|
||||
position: 4,
|
||||
name: 'Wachstum verfolgen',
|
||||
text: 'Dokumentiere Fotos, verfolge das Gießen und lass dich an wichtige Pflegetermine erinnern.',
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const faqSchema = {
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
mainEntity: [
|
||||
{
|
||||
'@type': 'Question',
|
||||
name: 'Wie erkennt GreenLens eine Pflanze?',
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
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: 'Ist GreenLens kostenlos?',
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
text: 'GreenLens bietet kostenlose Funktionen und zusätzlich kostenpflichtige Optionen wie Abos und Credit-Top-ups für erweiterte KI-Funktionen.',
|
||||
},
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
name: 'Kann ich GreenLens offline nutzen?',
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
text: 'Pflanzenidentifikation und Gesundheitscheck benötigen eine Internetverbindung. Deine gespeicherte Sammlung, Pflegenotizen und Gieß-Erinnerungen sind offline verfügbar.',
|
||||
},
|
||||
},
|
||||
{
|
||||
'@type': 'Question',
|
||||
name: 'Für welche Pflanzen kann ich GreenLens nutzen?',
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
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: 'Wie starte ich meine Pflanzensammlung?',
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
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.',
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
export default function Home({ locale = 'de' }: { locale?: Lang }) {
|
||||
const { howTo: howToSchema, faq: faqSchema } = getHomeSchemas(locale)
|
||||
return (
|
||||
<>
|
||||
<script
|
||||
|
||||
@@ -8,7 +8,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
return [
|
||||
{
|
||||
url: baseUrl,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'weekly',
|
||||
priority: 1,
|
||||
},
|
||||
@@ -26,19 +26,19 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/plant-identifier-app`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/plant-disease-identifier`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.75,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/plant-care-app`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.75,
|
||||
},
|
||||
@@ -68,43 +68,43 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/flower-scanner`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/identify-plant-photo`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/plant-scanner`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/houseplant-identifier`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.75,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/succulent-identifier`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.75,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/best-plant-identification-app`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.85,
|
||||
},
|
||||
{
|
||||
url: `${baseUrl}/plant-health-app`,
|
||||
lastModified: new Date('2026-04-27'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.8,
|
||||
},
|
||||
@@ -130,20 +130,20 @@ export default function sitemap(): MetadataRoute.Sitemap {
|
||||
const profile = getGermanSeoPageBySlug(slug)
|
||||
return {
|
||||
url: `${baseUrl}${profile?.canonical ?? `/${slug}`}`,
|
||||
lastModified: new Date('2026-05-20'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
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'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly',
|
||||
priority: 0.85,
|
||||
},
|
||||
...spanishSeoPageSlugs.map((slug) => ({
|
||||
url: `${baseUrl}${spanishSeoPageProfiles[slug].canonical}`,
|
||||
lastModified: new Date('2026-05-20'),
|
||||
lastModified: new Date('2026-07-10'),
|
||||
changeFrequency: 'monthly' as const,
|
||||
priority: slug === 'identificador-de-plantas' ? 0.85 : 0.75,
|
||||
})),
|
||||
|
||||
Reference in New Issue
Block a user