From a8af84e86432f6f9df3b0169577b45d27ebe6f8f Mon Sep 17 00:00:00 2001 From: Matt Date: Fri, 10 Apr 2026 14:55:10 -0400 Subject: [PATCH] fix(seo): canonical URL, og:locale:alternate, JSON-LD languages, sitemap x-default Co-Authored-By: Claude Opus 4.6 (1M context) --- src/app/(frontend)/[locale]/layout.tsx | 25 ++++++++++++++----------- src/app/(frontend)/[locale]/page.tsx | 15 ++++++++------- src/app/sitemap.ts | 2 ++ 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/src/app/(frontend)/[locale]/layout.tsx b/src/app/(frontend)/[locale]/layout.tsx index cd13fcc..d81cb25 100644 --- a/src/app/(frontend)/[locale]/layout.tsx +++ b/src/app/(frontend)/[locale]/layout.tsx @@ -21,6 +21,10 @@ export async function generateMetadata({ params }: Props): Promise { const { locale } = await params const t = await getTranslations({ locale, namespace: 'meta' }) + const ogLocaleMap: Record = { 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 { metadataBase: new URL(BASE_URL), title: { @@ -31,9 +35,12 @@ export async function generateMetadata({ params }: Props): Promise { openGraph: { type: 'website', siteName: t('siteName'), - locale: ({ en: 'en_US', fr: 'fr_FR', it: 'it_IT', es: 'es_ES' } as Record)[locale] ?? 'en_US', + locale: currentOgLocale, images: [{ url: '/images/og-default.png', width: 1200, height: 630 }], }, + other: { + 'og:locale:alternate': otherOgLocales, + }, twitter: { card: 'summary_large_image', }, @@ -41,16 +48,6 @@ export async function generateMetadata({ params }: Props): Promise { index: 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', 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) { diff --git a/src/app/(frontend)/[locale]/page.tsx b/src/app/(frontend)/[locale]/page.tsx index b61fc95..41c7b34 100644 --- a/src/app/(frontend)/[locale]/page.tsx +++ b/src/app/(frontend)/[locale]/page.tsx @@ -38,17 +38,18 @@ export async function generateMetadata({ params }: Props): Promise { } } -const websiteJsonLd = { - '@context': 'https://schema.org', - '@type': 'WebSite', - name: 'LetsBe.', - url: BASE_URL, -} - export default async function HomePage({ params }: Props) { const { locale } = await params setRequestLocale(locale) + const websiteJsonLd = { + '@context': 'https://schema.org', + '@type': 'WebSite', + name: 'LetsBe.', + url: BASE_URL, + inLanguage: locale, + } + return (