Back to blog

Posted by

Wednesday, January 17, 2024

Built a modern Blog CMS using Next.js and Sanity.

cover

Why I Chose Next.js and Sanity – It's More Than Just “Easy to Use”

When I first planned this blog, I didn’t want it to be just a space to “write and post images.”
I had a clear set of goals from day one:
  • Support three languages (Traditional Chinese, Japanese, English)
  • Embed videos, code snippets, and Twitter posts
  • Avoid being locked into Markdown limitations
  • Avoid being locked into Markdown limitations

I initially explored several options — Markdown-based blogs like Contentlayer + Next.js, even Notion API integrations.
But all of them hit a wall when it came to multi-language support with flexible content structure.

Eventually, I landed on Sanity.
Its schema system is highly customizable, allowing each post to have dedicated fields for each language.
Combined with Next.js dynamic routes and URL hash-based switching, the integration process was smoother than expected.

Multilingual Isn’t Just Translation — It’s About Structuring Content


At first, I thought handling multilingual content would mostly be about writing translations.
But I quickly realized the real challenge was how to structure the data — especially if I wanted each language to be independently maintained without cluttering the system or limiting future scalability.

Initially, I tried grouping content in objects or arrays, like:

{
  "title": {
    "EN": "...",
    "JP": "...",
    "HK": "..."
  }
}

It looked clean in the schema, but the frontend logic quickly became messy:
unpacking keys, writing fallbacks, nested conditionals...
Even worse, because the entire object was wrapped, changing language could trigger a full layout re-render. Debugging became painful.

Eventually, I redesigned the structure:
Each post in Sanity has explicit fields per language (e.g., title_EN, content_JP, smallDescription_HK),
and Next.js reads the correct version based on the URL hash or query.


This setup gave me three key benefits:

  • Clean, minimal frontend logic with no additional conversions
  • Instant language switching without reloading the page
  • Adding new languages only requires new fields — no schema overhaul needed

Final Setup

  • Define title_EN, content_JP, smallDescription_HK, etc., in Sanity schema
  • Fetch the corresponding field on the frontend using #EN, ?lang=JP, etc.
  • Seamlessly switch language versions on the same page

What I Learned

  • Multilingual UX isn't just about displaying text —it's a content architecture problem
  • Choosing tools is easy — designing a maintainable system is the real challenge
  • If you structure things right, scaling later (adding languages or content layers) is simple

Final Thoughts


This project wasn’t about mastering Sanity or Next.js.

It was the first time I tackled the idea that “language isn’t just translation — it’s structure.”

It forced me to think about how to build something that’s flexible, scalable, and actually maintainable — from scratch, with no template.

Yes, it’s still a work in progress.
But it’s mine — planned, tested, broken, fixed, and built line by line.