import { Helmet } from 'react-helmet-async'; import { useTranslation } from 'react-i18next'; import { buildLanguageAlternates, buildSocialImageUrl, getOgLocale } from '@/utils/seo'; const SITE_NAME = 'Dociva'; interface SEOHeadProps { /** Page title (will be appended with " — Dociva") */ title: string; /** Meta description */ description: string; /** Canonical URL path (e.g. "/about") — origin is auto-prefixed */ path: string; /** OG type — defaults to "website" */ type?: string; /** Optional JSON-LD objects to inject as structured data */ jsonLd?: object | object[]; } /** * Reusable SEO head component that injects: * - title, description, canonical URL * - OpenGraph meta tags (title, description, url, type, site_name, locale) * - Twitter card meta tags * - Optional JSON-LD structured data */ export default function SEOHead({ title, description, path, type = 'website', jsonLd }: SEOHeadProps) { const { i18n } = useTranslation(); const origin = typeof window !== 'undefined' ? window.location.origin : ''; const canonicalUrl = `${origin}${path}`; const socialImageUrl = buildSocialImageUrl(origin); const fullTitle = `${title} — ${SITE_NAME}`; const languageAlternates = buildLanguageAlternates(origin, path); const currentOgLocale = getOgLocale(i18n.language); const schemas = jsonLd ? (Array.isArray(jsonLd) ? jsonLd : [jsonLd]) : []; return ( {fullTitle} {languageAlternates.map((alternate) => ( ))} {/* OpenGraph */} {languageAlternates .filter((alternate) => alternate.ogLocale !== currentOgLocale) .map((alternate) => ( ))} {/* Twitter */} {/* JSON-LD Structured Data */} {schemas.map((schema, i) => ( ))} ); }