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.