We tried next-intl with the Next.js plugin. Turbopack silently broke it. Here's the approach we took instead — direct JSON imports, a createT() helper, and TypeScript enforcement.
We wanted i18n for SocialMate's public landing pages. We reached for `next-intl` — the standard choice. Added `createNextIntlPlugin` to `next.config.ts` and got everything wired up.
Then Turbopack happened.
`createNextIntlPlugin` injects a webpack alias that Turbopack silently ignores. At runtime: "Couldn't find next-intl config file." Not an obvious error. Not easy to debug.
We removed the plugin entirely and rewrote the localized landing page with direct JSON imports:
```typescript
import enMessages from '@/messages/en.json'
import esMessages from '@/messages/es.json'
// ... other locales
const MESSAGES: Record<string, typeof enMessages> = { en, es, de, fr, pt, ru, zh }
function createT(locale: string) {
const messages = MESSAGES[locale] ?? MESSAGES['en']
return (key: string) => key.split('.').reduce((o, k) => o?.[k], messages) ?? key
}
```
The `Record<string, typeof enMessages>` type constraint means every locale file must match the shape of `en.json`. Add a key to English and forget to add it to `zh.json`? TypeScript build error. Caught before Vercel deploy.
For the app interior (Dashboard, Compose, etc.), we use a React context: `I18nContext` with `useI18n()` and `t()`. Each namespace (e.g. `app_dashboard`, `app_queue`) is a flat object under the locale JSON.
Rule: any new key added to `en.json` must be added to all 6 other locale files in the same commit.
Next.js 15 + Turbopack + third-party plugins = verify every assumption. When the plugin breaks silently, ditch the plugin and own the implementation.
[SocialMate is open to creators in 7 languages at socialmate.studio](https://socialmate.studio)
Schedule to 16 platforms, manage your team, and grow your audience — all for free. No credit card required.
Create free account →16 platforms · Unlimited posts · Free forever
Comparing tools?
❤️ 2% of every SocialMate subscription goes to SM-Give — our charity initiative. Learn about SM-Give →