Web· Design, code and content· 2026
saintmilian.com — this site
The site you're reading. Two languages, no CMS, no bought template. I designed it, built it and write it.
Next.js 16TypeScriptTailwind CSS 4next-intlVeliteMDXResendVercel
This is the site you are reading. I designed it, built it, and write it — no CMS, no bought template.
The problem
A bilingual editorial site competing for organic search can't improvise its i18n. Every post needs its language sibling correctly linked (reciprocal hreflang + x-default), a stable canonical URL, and content that validates at build time, not in production.
The approach
- Next.js 16 App Router with
proxy.ts(the Next 16 rename ofmiddleware) driving next-intl routing. - Type-safe content layer with Velite: every frontmatter block is Zod-validated and types are generated into
.velite/. An invalid post breaks the build, not the site. - hreflang per translation pair: each post carries a
translationKey; from it I derivealternates.languagesingenerateMetadataand insitemap.ts. - SEO as an invariant: dynamic OG via
/api/og, per-page JSON-LD, and a sitemap with per-localealternates.
// i18n/routing.ts — folders stay Spanish; EN URLs are mapped
pathnames: {
"/sobre-mi": { es: "/sobre-mi", en: "/about" },
"/blog/[slug]": { es: "/notas/[slug]", en: "/writeups/[slug]" },
}The result
Lighthouse mobile ≥95 across all four categories, SEO 100, dark mode by default, and GitHub Actions CI running typecheck + build on every push. All content lives in git as MDX — versioned, reviewable, portable.