I built and run bandziuk.com — a multilingual site on Next.js 14 with Sanity as the CMS, running in English, Polish and Russian.
The interesting part wasn't the framework, it was the structure. Every page type — services, articles, portfolio cases — exists in three locales with hreflang pairs, and adding a new locale is a content task rather than a rebuild. Locale routing is automatic, and the language switcher lands on the equivalent page rather than the homepage, which is the part most multilingual sites get wrong.
A few things I ran into that might be useful to others here:
Nested service pages needed full ancestor-chain resolution for canonical URLs and redirects — the same one-level-slug assumption turned up in four separate places in my own code before I found them all.
Listing child pages automatically required a separate document type; a page can't list its own children the same way a hub can.
Structured data is emitted per page type, with service area and language declared explicitly, which turned out to matter more for AI assistants than for search.
Happy to answer questions about the Sanity schema or the i18n setup.