type
Post
status
Published
date
Jan 22, 2026
slug
summary
Learn how to achieve multi-language support in Next.js
tags
Next.js
开发
category
技术分享
icon
password
This article documents a production-ready internationalization (i18n) setup using next-intl with the Next.js App Router, based on a real project configuration (not just a demo).
📝 Cookie-Based i18n with next-intl (App Router) — A Real-World Guide
✨ Key highlights of this approach:
- ✅ No locale prefix in URLs (
/aboutinstead of/en/about)
- ✅ Language preference stored in Cookies
- ✅ Works seamlessly with Server & Client Components
- ✅ Clean URLs + persistent user preference
If you’re building a SaaS / dashboard / web app and want i18n without polluting URLs, this setup is for you.
🧠 Overall Idea (Read This First)
Unlike the official
next-intl example that uses locale-based routing (/[locale]), this solution is Cookie-driven.How it works
- The user’s language is stored in a cookie:
locale=en | zh | ko
- During server rendering, Next.js reads the cookie
next-intlloads the corresponding message file
- When switching language:
- Update the cookie
- Refresh the current route (URL stays the same)
🎯 Result:
/aboutalways stays/about
- Language persists across visits
- The whole app updates instantly
📁 Project Structure
Install the dependency
🗂️ Message Files
🇺🇸 messages/en.json
🇨🇳 messages/zh.json
🇰🇷 messages/ko.json
Tip: Group keys by feature or page instead of flattening everything.
⚙️ i18n/request.ts (Core Configuration)
This file is the heart of the entire setup.
It:
- Reads the locale from cookies
- Tells
next-intlwhich locale to use
- Dynamically loads the correct message file
i18n/request.ts
✅ Why this works
cookies()is server-only, perfect for App Router
- No global state or middleware needed
- Message files are loaded on demand, not bundled together
🧩 Root Layout Provider (Do NOT Skip This)
No matter which i18n strategy you use,
NextIntlClientProvider must be mounted at the root.app/layout.tsx
🔑 This enables:
useTranslations()
useLocale()
in any Client Component.
🖥️ Using Translations in Pages
Server Component Example
🔁 Language Switcher (Cookie-Based, No URL Change)
This is a clean and user-friendly language switcher that keeps URLs untouched.
components/language-switcher.tsx
🔍 What happens when you switch language?
- User selects a language
- Cookie is updated on the client
router.refresh()triggers server re-render
next-intlre-reads the cookie
- New messages are loaded 🎉
⚖️ Why Choose This Approach?
Feature | Locale in URL | Cookie-based |
Clean URLs | ❌ | ✅ |
Persistent preference | ⚠️ | ✅ |
App / Dashboard UX | ⚠️ | ⭐⭐⭐ |
SEO | ⭐⭐⭐ | ⭐⭐ |
📌 Best for: Apps, dashboards, authenticated products
⚠️ Common Pitfalls
cookies()only works on the server
- Client-side switching must call
router.refresh()
- Missing message files will throw runtime errors (add fallbacks if needed)
✅ Final Thoughts
This Cookie-based next-intl setup:
- Keeps URLs clean ✨
- Fully embraces the App Router
- Scales well for real-world applications
If you don’t need locale-prefixed URLs for SEO, this is one of the cleanest i18n solutions available today.
🚀 Want to go further?
- Type-safe translation keys with TypeScript
- Hybrid SEO + Cookie strategies
- Integrating locale with Auth / Supabase
Happy coding! 👋
📎 参考文章
- Author:Tao Chen
- URL:https://www.nextdaddy.cn/article/2f09b3f5-e6ae-80aa-9704-f82d21fc60f1
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!



