From 0af590fd26a2359f81c3213434d15dc6989f89eb Mon Sep 17 00:00:00 2001 From: Matheo Guilbert Date: Tue, 5 May 2026 09:35:27 +0200 Subject: [PATCH] adding alternative language versions to article metadata --- app/[locale]/blog/[slug]/page.tsx | 14 ++++++++++- .../01-How-I-built-my-new-website-and-why.mdx | 1 + .../en/02-Claude-Design-vs-Figma-Make.mdx | 23 ++++++++++--------- .../01-How-I-built-my-new-website-and-why.mdx | 23 ++++++++++--------- .../fr/02-Claude-Design-vs-Figma-Make.mdx | 23 ++++++++++--------- lib/blog/get-articles.ts | 21 +++++++++++++++++ lib/blog/types.ts | 1 + 7 files changed, 72 insertions(+), 34 deletions(-) diff --git a/app/[locale]/blog/[slug]/page.tsx b/app/[locale]/blog/[slug]/page.tsx index af83166..84d1f9d 100644 --- a/app/[locale]/blog/[slug]/page.tsx +++ b/app/[locale]/blog/[slug]/page.tsx @@ -1,7 +1,7 @@ import type { Metadata } from "next"; import { notFound } from "next/navigation"; import { MDXRemote } from "next-mdx-remote/rsc"; -import { getArticleBySlug, getAllArticles } from "@/lib/blog/get-articles"; +import { getArticleBySlug, getAllArticles, getAlternatesArticle } from "@/lib/blog/get-articles"; import { ArticleHero } from "@/components/sections/ArticleHero"; import { ArticleSummary } from "@/components/sections/ArticleSummary"; import { locales } from "@/middleware"; @@ -24,6 +24,14 @@ export async function generateMetadata({ params }: props): Promise { return {}; } + const languageAlternates = getAlternatesArticle(article); + const absoluteLanguageAlternates = Object.fromEntries( + Object.entries(languageAlternates).map(([language, path]) => [ + language, + `${siteUrl}${path}`, + ]) + ); + const url = `${siteUrl}/${locale}/blog/${slug}`; const title = article.title; const description = article.description; @@ -38,6 +46,10 @@ export async function generateMetadata({ params }: props): Promise { description, alternates: { canonical: url, + languages: { + ...absoluteLanguageAlternates, + "x-default": url, + }, }, openGraph: { title, diff --git a/content/blog/en/01-How-I-built-my-new-website-and-why.mdx b/content/blog/en/01-How-I-built-my-new-website-and-why.mdx index d88e85c..2835fae 100644 --- a/content/blog/en/01-How-I-built-my-new-website-and-why.mdx +++ b/content/blog/en/01-How-I-built-my-new-website-and-why.mdx @@ -1,5 +1,6 @@ --- ready: true +translationKey: "how-I-built-my-new-website" title: "How I built my new website, and why ?" description: "Discover how I built my website, the origin of this need, and the steps I went through." date: "2026-04-17" diff --git a/content/blog/en/02-Claude-Design-vs-Figma-Make.mdx b/content/blog/en/02-Claude-Design-vs-Figma-Make.mdx index e9a1724..5857fa2 100644 --- a/content/blog/en/02-Claude-Design-vs-Figma-Make.mdx +++ b/content/blog/en/02-Claude-Design-vs-Figma-Make.mdx @@ -1,22 +1,23 @@ --- ready: true +translationKey: "claude-design-vs-figma-make" title: "Claude Design vs. Figma Make: How I Combined the Two to Optimize My Prototyping" -description: A comparison of the two tools and how I used them -date: 2026-04-30 -category: Technologies +description: "A comparison of the two tools and how I used them" +date: "2026-04-30" +category: "Technologies" tags: - - Design - - AI - - Experience - - Comparison - - Technologies -readTime: 5 min + - "Design" + - "AI" + - "Experience" + - "Comparison" + - "Technologies" +readTime: "5 min" summary: - - The Arrival of Claude Design + - "The Arrival of Claude Design" - "The Flip Side: A Restrictive Pricing Model" - "The Alternative: Figma Make" - "The Ideal Workflow: Making Claude and Figma Talk" - - Epilogue + - "Epilogue" --- ## The Arrival of Claude Design diff --git a/content/blog/fr/01-How-I-built-my-new-website-and-why.mdx b/content/blog/fr/01-How-I-built-my-new-website-and-why.mdx index 498d456..682a793 100644 --- a/content/blog/fr/01-How-I-built-my-new-website-and-why.mdx +++ b/content/blog/fr/01-How-I-built-my-new-website-and-why.mdx @@ -1,19 +1,20 @@ --- ready: true -title: Comment j'ai construit mon nouveau site internet, et pourquoi ? -description: Découvrez comment j'ai construit mon site, l'origine de ce besoin et les étapes par lesquelles je suis passé. -date: 2026-04-17 -category: Développement Web +translationKey: "how-I-built-my-new-website" +title: "Comment j'ai construit mon nouveau site internet, et pourquoi ?" +description: "Découvrez comment j'ai construit mon site, l'origine de ce besoin et les étapes par lesquelles je suis passé." +date: "2026-04-17" +category: "Développement Web" tags: - - Portfolio - - Design - - Apprentissage -readTime: 5 min + - "Portfolio" + - "Design" + - "Apprentissage" +readTime: "5 min" summary: - - Pourquoi maintenant et pas des années plus tôt ? + - "Pourquoi maintenant et pas des années plus tôt ?" - "Le plus long : maquette Figma" - - Comment et avec quoi ? La stack de rêve - - Mon terrain de jeu personnel + - "Comment et avec quoi ? La stack de rêve" + - "Mon terrain de jeu personnel" --- ## Pourquoi maintenant et pas des années plus tôt ? diff --git a/content/blog/fr/02-Claude-Design-vs-Figma-Make.mdx b/content/blog/fr/02-Claude-Design-vs-Figma-Make.mdx index e08ebc1..f5b3944 100644 --- a/content/blog/fr/02-Claude-Design-vs-Figma-Make.mdx +++ b/content/blog/fr/02-Claude-Design-vs-Figma-Make.mdx @@ -1,22 +1,23 @@ --- ready: true +translationKey: "claude-design-vs-figma-make" title: "Claude Design face à Figma Make : Comment j'ai combiné les deux pour optimiser mon prototypage" -description: Comparatif des deux outils et comment je m'en suis servie -date: 2026-04-30 -category: Technologies +description: "Comparatif des deux outils et comment je m'en suis servie" +date: "2026-04-30" +category: "Technologies" tags: - - Design - - IA - - Expérience - - Comparatif - - Technologies -readTime: 5 min + - "Design" + - "IA" + - "Expérience" + - "Comparatif" + - "Technologies" +readTime: "5 min" summary: - - L'arrivée de Claude Design + - "L'arrivée de Claude Design" - "Le revers de la médaille : un modèle économique contraignant" - "L'alternative : Figma Make" - "Le workflow idéal : faire dialoguer Claude et Figma" - - Épilogue + - "Épilogue" --- ## L'arrivée de Claude Design diff --git a/lib/blog/get-articles.ts b/lib/blog/get-articles.ts index 1b708fa..7f3f4ed 100644 --- a/lib/blog/get-articles.ts +++ b/lib/blog/get-articles.ts @@ -1,6 +1,8 @@ import fs from "node:fs"; import path from "node:path"; import matter from "gray-matter"; +import { locales } from "@/middleware"; + import { Article, ArticleFrontmatter } from "./types"; const CONTENT_DIR = path.join(process.cwd(), "content/blog"); @@ -42,3 +44,22 @@ export function getAllArticles(locale: string): Article[] { .filter((article): article is Article => article !== null && article.ready) .sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); } + +export function getAlternatesArticle(article: Article) { + if (!article.translationKey) { + return {}; + } + + return locales.reduce>((acc, locale) => { + const translatedArticle = getAllArticles(locale).find( + (candidate) => + candidate.translationKey === article.translationKey + ); + + if (translatedArticle) { + acc[locale] = `/${locale}/blog/${translatedArticle.slug}`; + } + + return acc; + }, {}); +} \ No newline at end of file diff --git a/lib/blog/types.ts b/lib/blog/types.ts index 3c0fff3..595920f 100644 --- a/lib/blog/types.ts +++ b/lib/blog/types.ts @@ -1,5 +1,6 @@ export type ArticleFrontmatter = { ready: boolean; + translationKey: string; title: string; description: string; date: string;