feat: SEO SPA Sites, Articles and Integration (4/4)

This commit is contained in:
Florian Sylvain committed 2026-10-18 15:51:28 +02:00
1 parent cb737b7ae3
commit 02fb8751fd
47 files changed
+3218 -227

No files matched your search

+115 -4
View File
@@ -1967,10 +1967,6 @@ export const messages = {
'Lié à votre compte. Les nouveaux articles commencent avec cet auteur.',
"You don't have an author profile yet. Create one to be credited on your own articles.":
'Vous n’avez pas encore de profil d’auteur. Créez-en un pour être crédité sur vos propres articles.',
'The sites an article can belong to. Any verified user can read them and anyone can read a sitemap; changes are made in the browser by the owner.':
'Les sites auxquels un article peut appartenir. Tout utilisateur vérifié peut les lire et tout le monde peut lire un sitemap ; les modifications se font dans le navigateur par le propriétaire.',
'List the published URLs of a site, by id ascending, as an array. The total is in the X-Total-Count header.':
'Liste les adresses publiées d’un site, par identifiant croissant, sous forme de tableau. Le total est dans l’en-tête X-Total-Count.',
'The request cannot be processed due to a mismatch in the format of the body.':
'La requête ne peut pas être traitée car le format du corps ne correspond pas.',
site_not_found: 'Site introuvable',
@@ -2144,6 +2140,121 @@ export const messages = {
'cover image': 'image de couverture',
'site social image': 'image de partage du site',
'site address + slug': 'adresse du site + slug',
'Site name': 'Nom du site',
'Shown in titles through the template, and sent as the Open Graph site name.':
'Affiché dans les titres via le modèle, et envoyé comme nom de site Open Graph.',
'e.g. Renew': 'p. ex. Renew',
'Title template': 'Modèle de titre',
'Use %title% for the article title and %site% for the site name.':
'Utilisez %title% pour le titre de l’article et %site% pour le nom du site.',
'The template must contain %title%.': 'Le modèle doit contenir %title%.',
Example: 'Exemple',
'Default description': 'Description par défaut',
'Used when an article has no description, excerpt or body text.':
'Utilisée quand un article n’a ni description, ni extrait, ni texte.',
'One or two sentences about the site.': 'Une ou deux phrases sur le site.',
'How articles use these defaults': 'Comment les articles utilisent ces valeurs par défaut',
'Article title, then the template.': 'Titre de l’article, puis le modèle.',
Description: 'Description',
"Used last, after the article's description, excerpt and body.":
'Utilisée en dernier, après la description, l’extrait et le texte de l’article.',
'Used when an article has no cover image.':
'Utilisée quand un article n’a pas d’image de couverture.',
Robots: 'Robots',
'Used unless an article is hidden from search engines.':
'Utilisée sauf si l’article est masqué des moteurs de recherche.',
'Needs attention': 'À traiter',
Hidden: 'Masqué',
'Hidden from search engines': 'Masqué des moteurs de recherche',
'Nothing needs attention': 'Rien à traiter',
'Every article has a clean check. Suggestions are optional, so this is just a bonus.':
'Tous les articles passent la vérification. Les suggestions sont facultatives, c’est un petit plus.',
'Show all articles': 'Afficher tous les articles',
'1 dismissed suggestion is hidden.': '1 suggestion ignorée est masquée.',
'{0} dismissed suggestions are hidden.': '{0} suggestions ignorées sont masquées.',
'Show dismissed': 'Afficher les suggestions ignorées',
'Dismiss suggestion: {0}': 'Ignorer la suggestion : {0}',
'Suggestions never block saving or publishing. Dismiss one and it stays hidden for this article.':
'Les suggestions ne bloquent jamais l’enregistrement ni la publication. Ignorez-en une et elle reste masquée pour cet article.',
"Couldn't dismiss the suggestion": 'Impossible d’ignorer la suggestion',
'The key of a site. Only its articles are listed. An unknown key answers an empty page.':
'La clé d’un site. Seuls ses articles sont listés. Une clé inconnue renvoie une page vide.',
'ready, suggestions or hidden. Only the articles with that SEO status are listed, before paging; counts stay unfiltered. Any other value is refused.':
'ready, suggestions ou hidden. Seuls les articles ayant ce statut SEO sont listés, avant la pagination ; les compteurs restent non filtrés. Toute autre valeur est refusée.',
'Update the body of an article, move it to another site, or edit its SEO fields. Send at least one field; absent fields are untouched.':
'Modifie le corps d’un article, le déplace vers un autre site ou modifie ses champs SEO. Envoyez au moins un champ ; les champs absents ne sont pas touchés.',
'slug_taken (the X-Slug-Suggestion header holds the first free slug)':
'slug_taken (l’en-tête X-Slug-Suggestion contient le premier slug libre)',
'Up to 10 000 characters. An empty string empties the body; null is refused.':
'Jusqu’à 10 000 caractères. Une chaîne vide vide le corps ; null est refusé.',
'The id of an existing site, 1 or more. null is refused.':
'L’identifiant d’un site existant, 1 ou plus. null est refusé.',
'Lowercase letters, digits and single dashes, 1 to 100 characters, unique on the site. An empty string regenerates it from the title. null is refused.':
'Lettres minuscules, chiffres et tirets simples, de 1 à 100 caractères, unique sur le site. Une chaîne vide le régénère à partir du titre. null est refusé.',
'Up to 300 characters. An empty string clears it; null is refused.':
'Jusqu’à 300 caractères. Une chaîne vide l’efface ; null est refusé.',
'Up to 120 characters. An empty string clears it; null is refused.':
'Jusqu’à 120 caractères. Une chaîne vide l’efface ; null est refusé.',
'Up to 320 characters. An empty string clears it; null is refused.':
'Jusqu’à 320 caractères. Une chaîne vide l’efface ; null est refusé.',
'The id of an existing image, 1 or more. null removes the cover.':
'L’identifiant d’une image existante, 1 ou plus. null retire la couverture.',
'Up to 200 characters. An empty string clears it; null is refused.':
'Jusqu’à 200 caractères. Une chaîne vide l’efface ; null est refusé.',
'The id of an existing image, 1 or more. null removes the social image.':
'L’identifiant d’une image existante, 1 ou plus. null retire l’image de partage.',
'An absolute https address with a host, up to 2048 characters. An empty string clears it; null is refused.':
'Une adresse https absolue avec un hôte, jusqu’à 2048 caractères. Une chaîne vide l’efface ; null est refusé.',
'Only a flag: the article stays online. null is refused.':
'Un simple indicateur : l’article reste en ligne. null est refusé.',
'Dismissed suggestion codes: title_long, title_empty, desc_short, desc_long, cover_alt, cover_none, slug_long, no_au, no_h, body_alt, short. Duplicates are collapsed; null is refused.':
'Codes des suggestions ignorées : title_long, title_empty, desc_short, desc_long, cover_alt, cover_none, slug_long, no_au, no_h, body_alt, short. Les doublons sont fusionnés ; null est refusé.',
'Check the SEO of an article without saving anything. Send {} for the saved state, or fields that replace the saved values for this check only.':
'Vérifie le SEO d’un article sans rien enregistrer. Envoyez {} pour l’état enregistré, ou des champs qui remplacent les valeurs enregistrées pour cette vérification seulement.',
'Replaces the saved body for this check only. null is refused.':
'Remplace le corps enregistré pour cette vérification seulement. null est refusé.',
'Same rules as PATCH. An empty string regenerates it from the title. null is refused.':
'Mêmes règles que PATCH. Une chaîne vide le régénère à partir du titre. null est refusé.',
'Up to 300 characters. null is refused.': 'Jusqu’à 300 caractères. null est refusé.',
'Up to 120 characters. null is refused.': 'Jusqu’à 120 caractères. null est refusé.',
'Up to 320 characters. null is refused.': 'Jusqu’à 320 caractères. null est refusé.',
'The id of an existing image. null means no cover.':
'L’identifiant d’une image existante. null signifie pas de couverture.',
'Up to 200 characters. null is refused.': 'Jusqu’à 200 caractères. null est refusé.',
'The id of an existing image. null means no social image.':
'L’identifiant d’une image existante. null signifie pas d’image de partage.',
'An absolute https address with a host, up to 2048 characters. null is refused.':
'Une adresse https absolue avec un hôte, jusqu’à 2048 caractères. null est refusé.',
'null is refused.': 'null est refusé.',
'Dismissed suggestion codes, replacing the saved list for this check only. null is refused.':
'Codes des suggestions ignorées, qui remplacent la liste enregistrée pour cette vérification seulement. null est refusé.',
"RenewCMS doesn't render pages or add meta tags. These endpoints give your frontend the resolved SEO data and the list of published URLs.":
'RenewCMS n’affiche pas de pages et n’ajoute pas de balises meta. Ces routes donnent à votre frontend les données SEO résolues et la liste des URL publiées.',
'Get the resolved SEO object of an article: title with the site template applied, description, canonical_url, robots, og, twitter, image, authors, published_at, modified_at, fallbacks and json_ld. Drafts answer 404 to anonymous callers.':
'Renvoie l’objet SEO résolu d’un article : title avec le modèle du site appliqué, description, canonical_url, robots, og, twitter, image, authors, published_at, modified_at, fallbacks et json_ld. Les brouillons répondent 404 aux appelants anonymes.',
'List the published URLs of a site, by id ascending, as an array of { url, modified_at, noindex }. The total is in the X-Total-Count header.':
'Liste les adresses publiées d’un site, par identifiant croissant, sous forme de tableau de { url, modified_at, noindex }. Le total est dans l’en-tête X-Total-Count.',
'The sites an article can belong to. Any verified user can read them; changes are made in the browser by the owner.':
'Les sites auxquels un article peut appartenir. Tout utilisateur vérifié peut les lire ; les modifications se font dans le navigateur par le propriétaire.',
'Site SEO defaults are owner only. Article SEO fields need only the right to edit the article.':
'Les valeurs SEO par défaut d’un site sont réservées au propriétaire. Les champs SEO d’un article demandent seulement le droit de modifier l’article.',
'The server expects the ID to be in the format of an unsigned 32-bit integer (uint32).':
'Le serveur attend un identifiant au format d’un entier non signé de 32 bits (uint32).',
'Article not found': 'Article introuvable',
'Choose an image to keep and at least one other image to merge into it.':
'Choisissez une image à conserver et au moins une autre image à fusionner dedans.',
'Some of the images to merge changed. Refresh and try again.':
'Certaines images à fusionner ont changé. Actualisez et réessayez.',
'List the articles, authors and sites that use an image, with the places where each one uses it.':
'Liste les articles, auteurs et sites qui utilisent une image, avec les endroits où chacun l’utilise.',
'Log in. Made for the browser. A key is ignored here, with no 403.':
'Se connecter. Conçu pour le navigateur. Une clé est ignorée ici, sans 403.',
'Log out. Made for the browser. A key is ignored here, with no 403.':
'Se déconnecter. Conçu pour le navigateur. Une clé est ignorée ici, sans 403.',
'Register. Made for the browser. A key is ignored here, with no 403.':
'S’inscrire. Conçu pour le navigateur. Une clé est ignorée ici, sans 403.',
'Reset password. Made for the browser. A key is ignored here, with no 403.':
'Réinitialiser le mot de passe. Conçu pour le navigateur. Une clé est ignorée ici, sans 403.',
} as const
export type MessageKey = keyof typeof messages