feat(frontend): add per-language SEO metadata, JSON-LD, robots.txt, and sitemap
Part of the Ombrora Convert redesign (Task 4/5).
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const SITE_URL = 'https://convert.ombrora.com';
|
||||
|
||||
const META = {
|
||||
fr: {
|
||||
title: 'Ombrora Convert — Conversion de fichiers en ligne',
|
||||
description:
|
||||
"Convertissez vos fichiers en ligne gratuitement : images, documents, polices et ebooks. Aucun compte requis, fichiers supprimés automatiquement.",
|
||||
},
|
||||
en: {
|
||||
title: 'Ombrora Convert — Online File Conversion',
|
||||
description:
|
||||
'Convert your files online for free: images, documents, fonts, and ebooks. No account required, files deleted automatically.',
|
||||
},
|
||||
};
|
||||
|
||||
function setNameMeta(name, content) {
|
||||
let el = document.head.querySelector(`meta[name="${name}"]`);
|
||||
if (!el) {
|
||||
el = document.createElement('meta');
|
||||
el.setAttribute('name', name);
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
el.setAttribute('content', content);
|
||||
}
|
||||
|
||||
function setPropertyMeta(property, content) {
|
||||
let el = document.head.querySelector(`meta[property="${property}"]`);
|
||||
if (!el) {
|
||||
el = document.createElement('meta');
|
||||
el.setAttribute('property', property);
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
el.setAttribute('content', content);
|
||||
}
|
||||
|
||||
function setAlternateLink(hreflang, href) {
|
||||
const selector = `link[rel="alternate"][hreflang="${hreflang}"]`;
|
||||
let el = document.head.querySelector(selector);
|
||||
if (!el) {
|
||||
el = document.createElement('link');
|
||||
el.setAttribute('rel', 'alternate');
|
||||
el.setAttribute('hreflang', hreflang);
|
||||
document.head.appendChild(el);
|
||||
}
|
||||
el.setAttribute('href', href);
|
||||
}
|
||||
|
||||
function setJsonLd(lang) {
|
||||
const id = 'seo-jsonld';
|
||||
let script = document.getElementById(id);
|
||||
if (!script) {
|
||||
script = document.createElement('script');
|
||||
script.id = id;
|
||||
script.type = 'application/ld+json';
|
||||
document.head.appendChild(script);
|
||||
}
|
||||
script.textContent = JSON.stringify({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'SoftwareApplication',
|
||||
name: 'Ombrora Convert',
|
||||
applicationCategory: 'UtilitiesApplication',
|
||||
operatingSystem: 'Any',
|
||||
offers: { '@type': 'Offer', price: '0', priceCurrency: 'EUR' },
|
||||
inLanguage: lang,
|
||||
url: `${SITE_URL}/${lang}/`,
|
||||
});
|
||||
}
|
||||
|
||||
export function SeoHead({ lang }) {
|
||||
useEffect(() => {
|
||||
const meta = META[lang] ?? META.fr;
|
||||
document.title = meta.title;
|
||||
document.documentElement.lang = lang;
|
||||
setNameMeta('description', meta.description);
|
||||
setPropertyMeta('og:title', meta.title);
|
||||
setPropertyMeta('og:description', meta.description);
|
||||
setPropertyMeta('og:type', 'website');
|
||||
setPropertyMeta('og:locale', lang === 'fr' ? 'fr_FR' : 'en_US');
|
||||
setAlternateLink('fr', `${SITE_URL}/fr/`);
|
||||
setAlternateLink('en', `${SITE_URL}/en/`);
|
||||
setAlternateLink('x-default', `${SITE_URL}/fr/`);
|
||||
setJsonLd(lang);
|
||||
}, [lang]);
|
||||
|
||||
return null;
|
||||
}
|
||||
Reference in New Issue
Block a user