Major homepage and SEO enhancements based on optimization document: **Homepage Content Updates:** - Updated H1 titles with SEO-optimized text for both RO/EN - Enhanced hero descriptions with targeted keywords - Improved feature descriptions for better clarity - Updated daily verse section with keyword-rich titles - Added new footer description with SEO focus **SEO Implementation:** - Added dynamic metadata generation with locale-specific SEO - Implemented Open Graph tags for social media sharing - Added Twitter Card metadata for enhanced sharing - Integrated Schema.org JSON-LD structured data - Set up hreflang tags for international SEO - Added canonical URLs to prevent duplicate content - Included targeted keywords for both languages **Technical Improvements:** - Migrated from Docker to PM2 deployment - Removed Docker files and updated deployment scripts - Updated README with PM2 instructions - Fixed console log cleanup for production - Added proper favicon with Next.js app directory - Increased memory limit to 4GB for better performance - Updated port configuration to 0.0.0.0:3010 - Set Romanian (/ro) as default locale with proper redirects **Translation Updates:** - Enhanced Romanian translations with SEO-optimized content - Updated English translations with matching SEO improvements - Added new 'seo' namespace for metadata translations 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
116 lines
3.3 KiB
TypeScript
116 lines
3.3 KiB
TypeScript
import '../globals.css'
|
|
import type { Metadata } from 'next'
|
|
import { NextIntlClientProvider } from 'next-intl'
|
|
import { getMessages, getTranslations } from 'next-intl/server'
|
|
import { notFound } from 'next/navigation'
|
|
import { MuiThemeProvider } from '@/components/providers/theme-provider'
|
|
import { AuthProvider } from '@/components/auth/auth-provider'
|
|
import { Navigation } from '@/components/layout/navigation'
|
|
import FloatingChat from '@/components/chat/floating-chat'
|
|
import { merriweather, lato } from '@/lib/fonts'
|
|
|
|
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {
|
|
const { locale } = await params
|
|
const t = await getTranslations({ locale, namespace: 'seo' })
|
|
|
|
const currentUrl = locale === 'ro' ? 'https://ghidulbiblic.ro/ro/' : 'https://ghidulbiblic.ro/en/'
|
|
const alternateUrl = locale === 'ro' ? 'https://ghidulbiblic.ro/en/' : 'https://ghidulbiblic.ro/ro/'
|
|
|
|
return {
|
|
title: t('title'),
|
|
description: t('description'),
|
|
keywords: t('keywords'),
|
|
alternates: {
|
|
canonical: currentUrl,
|
|
languages: {
|
|
'ro': 'https://ghidulbiblic.ro/ro/',
|
|
'en': 'https://ghidulbiblic.ro/en/',
|
|
'x-default': 'https://ghidulbiblic.ro/'
|
|
}
|
|
},
|
|
openGraph: {
|
|
title: t('ogTitle'),
|
|
description: t('ogDescription'),
|
|
url: currentUrl,
|
|
siteName: locale === 'ro' ? 'Ghid Biblic' : 'Biblical Guide',
|
|
locale: locale,
|
|
type: 'website',
|
|
images: [
|
|
{
|
|
url: `https://ghidulbiblic.ro/og-image-${locale}.jpg`,
|
|
width: 1200,
|
|
height: 630,
|
|
alt: t('ogTitle'),
|
|
},
|
|
],
|
|
},
|
|
twitter: {
|
|
card: 'summary_large_image',
|
|
site: '@ghidbiblic',
|
|
title: t('twitterTitle'),
|
|
description: t('twitterDescription'),
|
|
images: [`https://ghidulbiblic.ro/og-image-${locale}.jpg`],
|
|
},
|
|
other: {
|
|
'application/ld+json': JSON.stringify({
|
|
"@context": "https://schema.org",
|
|
"@type": "MobileApplication",
|
|
"name": locale === 'ro' ? "Ghid Biblic" : "Biblical Guide",
|
|
"url": "https://ghidulbiblic.ro",
|
|
"description": t('description'),
|
|
"applicationCategory": "EducationApplication",
|
|
"operatingSystem": "iOS, Android, Web",
|
|
"inLanguage": [locale],
|
|
"offers": {
|
|
"@type": "Offer",
|
|
"price": "0",
|
|
"priceCurrency": "USD"
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
export async function generateStaticParams() {
|
|
return [
|
|
{ locale: 'ro' },
|
|
{ locale: 'en' }
|
|
]
|
|
}
|
|
|
|
interface LocaleLayoutProps {
|
|
children: React.ReactNode
|
|
params: Promise<{ locale: string }>
|
|
}
|
|
|
|
const locales = ['ro', 'en']
|
|
|
|
export default async function LocaleLayout({
|
|
children,
|
|
params
|
|
}: LocaleLayoutProps) {
|
|
const { locale } = await params
|
|
|
|
// Validate locale
|
|
if (!locales.includes(locale)) {
|
|
notFound()
|
|
}
|
|
|
|
const messages = await getMessages({ locale })
|
|
|
|
return (
|
|
<html lang={locale}>
|
|
<body className={`${merriweather.variable} ${lato.variable}`}>
|
|
<NextIntlClientProvider messages={messages} locale={locale}>
|
|
<MuiThemeProvider>
|
|
<AuthProvider>
|
|
<Navigation />
|
|
{children}
|
|
<FloatingChat />
|
|
</AuthProvider>
|
|
</MuiThemeProvider>
|
|
</NextIntlClientProvider>
|
|
</body>
|
|
</html>
|
|
)
|
|
} |