Sander Korf
  • Portfolio
  • Resume

Sander Korf

Dutch Full Stack AI Engineer helping businesses cut costs through intelligent automation. 13+ years turning expensive manual processes into systems that work 24/7. Based in Amsterdam, available for freelance projects.

Navigation

  • Portfolio
  • Resume

Legal

  • Cookies
  • Privacy Policy
  • Terms and Conditions

Blog

Algolia

  • Algolia InstantSearch INP and object identity
  • Algolia merch by Sanity _type, not title
  • Algolia InstantSearch search key, not admin

Vercel

  • Next.js empty Suspense fallbacks wreck CLS P95
  • Vercel Workflows: skip closed eToro legs

eToro

  • eToro deploy vs rotate: idle cash not rotate
  • eToro search 404: query fields, not ticker
  • eToro v2 opens at-most-once, settlement
  • eToro LLM overlay ±10pp: critic cannot veto

Next.js

  • next-intl useTranslate skip links above fold
  • next-intl owns Klaviyo nl-NL email copy

Firebase & Expo

  • Staging deep links must not hijack production
  • Turn off Worklets Bundle Mode for EAS SHA-1
  • Reclaim Firebase orphan without password wipe

Centra & Klaviyo

  • Centra to Klaviyo tags need a plugin contract

About

  • Full Stack AI Engineer in Amsterdam

© 2026 Sander Korf. All rights reserved

94719489

  • Applied AI
  1. Home
  2. Blog
  3. next-intl owns Klaviyo nl-NL email copy

next-intl owns Klaviyo nl-NL email copy

Dutch shoppers notice English order emails instantly. I resolve locale on the server before triggering mail, not inside a default template.

Sander KorfPublished August 21, 20263 min read
next-intlklaviyocentranextjs

This was a fashion storefront, not a demo inbox

Next.js storefront. Centra as commerce. Klaviyo as the mail pipe. next-intl as the dictionary. The market that paid the bills spoke Dutch. If a receipt arrived in English, the shopper did not file a Jira. They forwarded it to support and asked if they ordered from the wrong site.

What they would notice if it failed

Order confirmation in en. Password reset in en. Shipping update that says "Your order" to a profile whose Centra language is nl-NL. Klaviyo still "sent." The metric still fired. The copy was just from the wrong room.

The puzzle: Klaviyo is not a locale

I treated Klaviyo like it would pick Dutch because the profile had a Dutch email and a Dutch shipping address. Klaviyo sends whatever string you put on the event or in the template. It does not run next-intl. It does not read your Next.js request locale. A flow triggered off Placed Order will happily render the default template language.

The storefront already had next-intl wired for nl-NL. Product pages were fine. Transactional copy lived in a second pile: hardcoded English in the Klaviyo template, or a server helper that called getTranslations() without a locale and inherited the default.

That default was English. Of course it was.

Resolve nl-NL before the event leaves

Transactional HTML that we still render ourselves goes through next-intl with an explicit locale. Not "whatever the current request is." A Klaviyo event can be sent from a webhook, a queue, a Centra plugin callback. There is no incoming Accept-Language. If you do not pass nl-NL, you get the default.

const locale = profile.language === 'nl' ? 'nl-NL' : 'en';
const t = await getTranslations({ locale, namespace: 'Transactional' });
 
await klaviyo.events.create({
	data: {
		type: 'event',
		attributes: {
			metric: { data: { type: 'metric', attributes: { name: 'Placed Order' } } },
			profile: { data: { type: 'profile', attributes: { email } } },
			properties: {
				subject: t('orderReceipt.subject'),
				preview: t('orderReceipt.preview'),
			},
		},
	},
});

When Klaviyo owns the template, the template must branch on the profile language Centra already syncs (person|lookup:"Language"), or we send pre-rendered next-intl strings as event properties. Guessing from the shipping country is how Belgium gets French and the Netherlands gets English on a Tuesday.

next-intl already knew nl-NL. I just had not invited it to the email.


Happy coding!
Sander