Communitygithub.com

timerise-ai/blog-markdown

Compétence d'agent : construire un blog multilingue en Markdown basé sur des fichiers — articles partitionnés par locale, slugs par locale reliés par une clé de traduction commune, pages de tags avec identité par slug, articles connexes, image de couverture, RSS, sitemap, hreflang, validateur de contenu CI — dans Next.js App Router, sans CMS.

Qu'est-ce que blog-markdown ?

Cette compétence d'agent fournit un plan d'architecture complet et des règles de mise en œuvre pour un blog multilingue en Markdown utilisant le Next.js App Router. Elle est conçue pour les développeurs qui souhaitent que le contenu réside dans des fichiers Markdown dans le référentiel plutôt que dans un CMS, avec une prise en charge complète du référencement multilingue, des pages de tags, des articles connexes, des flux RSS et des sitemaps. Le principe central est qu'un article est identifié par son `translationKey`, et non par son slug, ce qui permet d'avoir des slugs localisés pour le référencement tout en garantissant que les traductions d'un même article sont correctement liées. La compétence couvre également des pièges critiques de mise en œuvre, notamment la gestion des échecs d'analyse YAML avec `gray-matter`, la mémorisation des charges pour éviter les amplifications de lecture de fichiers, et les règles strictes pour ne jamais déduire les relations inter-locales des slugs. Elle renvoie à un ensemble de documents de référence détaillés pour la mise en œuvre étape par étape, les tests et l'adaptation aux applications existantes.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add timerise-ai/blog-markdown

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Blog Markdown (multilingue, avec tags)

Un blog où le contenu est constitué de fichiers, pas de lignes de base de données. L'ensemble de la conception repose sur une idée : l'identité d'un article est sa translationKey, pas son slug. Les slugs sont localisés pour le référencement et diffèrent selon la langue ; la clé est ce qui fait de trois fichiers un seul article, et c'est ce qui alimente le hreflang, le sélecteur de langue, les articles connexes et les redirections inter-locales. Obtenez ce champ correctement et tout le reste n'est que des recherches.

Écrit par l'ingénieur qui a livré ce module. L'implémentation précédente contre laquelle il a été audité était un blog marketing multilingue généré statiquement avec son sitemap et sa surface SEO. Les faits et règles ci-dessous sont ce que la suite de couche de contenu et la build vérifient ; references/provenance.md contient le compte rendu.

Quand l'utiliser

  • Contenu rédigé en Markdown dans le dépôt, déployé avec l'application
  • Plus d'une langue, avec des slugs différents par langue
  • Pages de tags, articles connexes, flux ou hreflang sont dans le périmètre
  • Vous voulez que le tout soit généré statiquement au moment de la build

Quand NE PAS l'utiliser

Au lieu de celaUtilisez
Un CMS hébergé est la source de véritéle SDK de ce CMS ; ne gardez que references/content-model.md
Un site de documentation / centre d'aide (catégories, barre latérale, recherche)une compétence de centre d'aide — modèle de navigation différent
Un blog monolingue de moins de 10 articlesfs simple + gray-matter en ligne ; ceci est un surcoût
Rendre du Markdown soumis par l'utilisateurun moteur de rendu avec assainissement ; voir la note XSS dans references/rendering.md

Architecture

content/blog/<locale>/<slug-localisé>.md   # frontmatter + corps
        |
        v
 parseFrontmatter  --YAML, avec repli sur un analyseur ligne par ligne en cas de guillemets malformés
        |
        v
   getAllPosts(locale)  <-- mémorisé par locale en production
        |
        +--> translationKey ----> alternatives / hreflang / changement de langue
        +--> tags -> SLUG du tag ---> pages de tags (le slug est l'identité, pas le libellé)
        +--> related (slugs EN) -> articles connexes, avec un repli EN
        |
        v
  /blog   /blog/[slug]   /blog/tag/[slug]   sitemap.xml   feed.xml

Faits critiques

  1. Les relations sont rédigées une fois, dans la locale par défaut, sous forme de slugs de la locale par défaut. Un fichier traduit peut omettre related entièrement et obtiendra tout de même les bons articles connexes, résolus via translationKey, de sorte que chaque traduction rend la même section connexe. Le test de repli le vérifie.
  2. L'identité d'un tag est son slug, pas son libellé. "IA Agents" et "IA agents" produisent le même slug d'URL. Regroupez par slug et associez les articles par slug, de sorte que toutes les variantes orthographiques apparaissent sur la même page de tag. Deux tests le vérifient.
  3. gray-matter lève une exception sur un scalaire YAML entre guillemets contenant des caractères de guillemets bruts — les guillemets typographiques dans un extrait traduit le font. Sans un analyseur de repli, la build s'arrête sur ce fichier ; l'analyseur ligne par ligne le garde fonctionnel. Vérifié par rapport à la bibliothèque et couvert par un test.
  4. gray-matter met en cache un échec d'analyse comme un résultat vide. Il écrit son entrée de cache avant d'analyser, donc la deuxième analyse et toutes les suivantes d'un fichier qui a levé une exception renvoient {} — aucune erreur, aucun frontmatter. Appelez toujours matter(contents, {}) ; tout objet d'options désactive le cache.
  5. Le chargement est O(articles x locales) par page sauf si vous mémorisez. Mémorisez par locale pour que chaque fichier de contenu soit lu une fois par build ; la résolution des alternatives dans generateMetadata est autrement une amplification de lecture de fichier de 71x, mesurée sur l'implémentation précédente.
  6. getPostSlugs doit filtrer .md. Le filtre empêche un fichier .DS_Store errant de devenir une lecture .DS_Store.md et une erreur ENOENT. Un test le vérifie.
  7. Les pages de tags n'ont pas d'identité inter-locale. Les tags sont du texte libre par locale, donc le sélecteur de langue doit se rabattre sur l'index du blog pour une URL de tag plutôt que de construire une URL qui aboutit à une 404.

Règles strictes

Ne jamais utiliser le slug comme clé pour les recherches inter-locales. Les slugs sont localisés intentionnellement. translationKey est la colonne de jointure ; une correspondance de slug entre locales est une coïncidence, pas une relation.

Ne jamais laisser getPostBySlug décider implicitement de la visibilité des brouillons. Filtrez les brouillons dans le chargeur ; dynamicParams = false ne les cache que comme effet secondaire et cesse de le faire dès que le drapeau change. Le test des brouillons applique le filtre.

Ne jamais afficher une constante « 5 min de lecture ». Calculez-la à partir du corps ; cela coûte un split, et le test du temps de lecture le vérifie.

Ne jamais déduire l'URL d'une page de tag à partir du libellé au moment de la lecture et le libellé à partir de l'URL au moment du rendu sans une vérification de collision. Cet aller-retour n'est sans perte que tant que chaque libellé produit un slug unique.

Démarrage rapide

  1. Définissez le contrat de locale et le schéma frontmatter — content-model.md
  2. Construisez le chargeur (mémorisé, filtré .md, analyseur de repli) — content-loader.md
  3. Branchez les locales, les alternatives et les redirections inter-locales — i18n-and-routing.md
  4. Ajoutez le regroupement par tags et les pages de tags — tags.md
  5. Construisez les trois routes, les métadonnées et JSON-LD — pages-and-seo.md
  6. Affichez les corps et les couvertures — rendering.md
  7. Ajoutez le script de validation et lisez les lacunes opérateur — operations.md
  8. Exécutez les fixtures et les tests — testing.md

Vous portez ceci dans une application existante ? Remplissez d'abord le tableau des points d'insertion dans adaptation.md — cela prend dix minutes et vous évite un renommage.

Répertoire des références

ScénarioMots-clés déclencheursRéférence
Champs frontmatter, brouillons, clés de traduction, relationsfrontmatter, schéma, translationKey, brouillon, related, extraitcontent-model.md
Lecture de fichiers, mise en cache, échecs YAML, temps de lecturegray-matter, fs, cache, mémoriser, ENOENT, YAMLException, analysercontent-loader.md
Locales, hreflang, alternatives, liens vers la mauvaise localei18n, locale, hreflang, alternatives, canonique, sélecteur de langue, redirectioni18n-and-routing.md
URL de tags, collisions, pages de tags finestag, slug, diacritiques, collision, page de tag, taxonomietags.md
Les routes, métadonnées, JSON-LD, sitemap, RSSpage.tsx, generateStaticParams, generateMetadata, dynamicParams, sitemap, RSS, flux, BlogPostingpages-and-seo.md
Markdown vers React, blocs de code, images de couverturereact-markdown, remark-gfm, coloration syntaxique, couverture, motif, accent, XSSrendering.md
Validation du contenu, coût de la build, flux de travail de l'éditeurvalidation, vérification CI, temps de build, brouillons, rédaction, opérateuroperations.md
Fixtures et la suite de tests passantetest, fixture, vitest, node:test, régression, asserttesting.md
Intégration dans une application hôte : points d'insertion, renommages, sondeadapter, porter, hôte, point d'insertion, renommer, CMS, intégreradaptation.md
Le registre d'audit : ce qui a changé, a été conservé et a été ajouté par rapport à l'implémentation précédenteprovenance, écarts, fidélité, audit, registreprovenance.md

Skills associés