fix(seo): canonical URL, og:locale:alternate, JSON-LD languages, sitemap x-default

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-10 14:55:10 -04:00
parent d68dd6ffc3
commit a8af84e864
3 changed files with 24 additions and 18 deletions

View File

@@ -21,6 +21,10 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
const { locale } = await params const { locale } = await params
const t = await getTranslations({ locale, namespace: 'meta' }) const t = await getTranslations({ locale, namespace: 'meta' })
const ogLocaleMap: Record<string, string> = { en: 'en_US', fr: 'fr_FR', it: 'it_IT', es: 'es_ES' }
const currentOgLocale = ogLocaleMap[locale] ?? 'en_US'
const otherOgLocales = Object.values(ogLocaleMap).filter((l) => l !== currentOgLocale)
return { return {
metadataBase: new URL(BASE_URL), metadataBase: new URL(BASE_URL),
title: { title: {
@@ -31,9 +35,12 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
openGraph: { openGraph: {
type: 'website', type: 'website',
siteName: t('siteName'), siteName: t('siteName'),
locale: ({ en: 'en_US', fr: 'fr_FR', it: 'it_IT', es: 'es_ES' } as Record<string, string>)[locale] ?? 'en_US', locale: currentOgLocale,
images: [{ url: '/images/og-default.png', width: 1200, height: 630 }], images: [{ url: '/images/og-default.png', width: 1200, height: 630 }],
}, },
other: {
'og:locale:alternate': otherOgLocales,
},
twitter: { twitter: {
card: 'summary_large_image', card: 'summary_large_image',
}, },
@@ -41,16 +48,6 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
index: true, index: true,
follow: true, follow: true,
}, },
alternates: {
canonical: BASE_URL,
languages: {
'en': BASE_URL,
'fr': `${BASE_URL}/fr`,
'it': `${BASE_URL}/it`,
'es': `${BASE_URL}/es`,
'x-default': BASE_URL,
},
},
} }
} }
@@ -75,6 +72,12 @@ const organizationJsonLd = {
email: 'hello@letsbe.biz', email: 'hello@letsbe.biz',
contactType: 'customer service', contactType: 'customer service',
}, },
availableLanguage: [
{ '@type': 'Language', name: 'English', alternateName: 'en' },
{ '@type': 'Language', name: 'French', alternateName: 'fr' },
{ '@type': 'Language', name: 'Italian', alternateName: 'it' },
{ '@type': 'Language', name: 'Spanish', alternateName: 'es' },
],
} }
export default async function LocaleLayout({ children, params }: Props) { export default async function LocaleLayout({ children, params }: Props) {

View File

@@ -38,17 +38,18 @@ export async function generateMetadata({ params }: Props): Promise<Metadata> {
} }
} }
const websiteJsonLd = {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'LetsBe.',
url: BASE_URL,
}
export default async function HomePage({ params }: Props) { export default async function HomePage({ params }: Props) {
const { locale } = await params const { locale } = await params
setRequestLocale(locale) setRequestLocale(locale)
const websiteJsonLd = {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: 'LetsBe.',
url: BASE_URL,
inLanguage: locale,
}
return ( return (
<main> <main>
<script <script

View File

@@ -19,6 +19,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
fr: `${BASE_URL}/fr${route}`, fr: `${BASE_URL}/fr${route}`,
it: `${BASE_URL}/it${route}`, it: `${BASE_URL}/it${route}`,
es: `${BASE_URL}/es${route}`, es: `${BASE_URL}/es${route}`,
'x-default': `${BASE_URL}${route}`,
}, },
}, },
})) }))
@@ -34,6 +35,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
fr: `${BASE_URL}/fr/work/${slug}`, fr: `${BASE_URL}/fr/work/${slug}`,
it: `${BASE_URL}/it/work/${slug}`, it: `${BASE_URL}/it/work/${slug}`,
es: `${BASE_URL}/es/work/${slug}`, es: `${BASE_URL}/es/work/${slug}`,
'x-default': `${BASE_URL}/work/${slug}`,
}, },
}, },
})) }))