Two weeks before the scheduled launch of a luxury limo booking platform for a client in Dubai, we hit a wall. Arabic date formatting — yes, that specific — was breaking the production build on Vercel. The dev environment? Fine. Local builds? Fine. Staging? Breaking with cryptic errors about moment.js being undefined. You can imagine the fun.
This wasn't my first time shipping a bilingual Next.js app, but it was the first time dealing with Arabic language quirks at scale. Here's what ended up in the deployment notes after that chaotic week.
Handling i18n in Next.js 14 with appDir
The switch to Next.js 14's App Router meant revisiting how we handled bilingual routes. The older Pages Router pattern (with i18next and next-i18next) worked fine, but the new approach relies on app/[lang]/ directory patterns. We used next.config.js to enforce this:
i18n: {
locales: ['en', 'ar'],
defaultLocale: 'en',
localeDetection: false,
}But here's the trap: Vercel's cache invalidation logic doesn't play nicely with locale-specific pages unless you include the lang param in all your API routes. Spent half a day debugging why the /api/bookings endpoint was returning English responses for Arabic users until we added explicit lang headers in API handlers.
Vercel Cache Gotchas for Server-Side Data Fetching
One of our data fetching layers used SWR. In development, stale-while-revalidate worked perfectly. In production? Arabic users were getting stale English data. The culprit: Vercel's ISR cache treats /api/data and /ar/api/data as separate entries by default, right? Turns out, not if you have middleware-based language detection that strips the locale for backend calls.
We switched to including next.config.js rewrites that append a query param instead of path prefixes for internal APIs:
async rewrites() {
return {
beforeFiles: [
{
source: '/api/:path*',
has: [{ type: 'query', key: 'lang', value: 'ar' }],
destination: 'https://backend.ar.example/api/:path*',
}
]
}
}Stupid? Maybe. But it forced Vercel to treat /api/something?lang=ar and /api/something?lang=en as separate cache entries. Would've saved two days if I'd thought of it earlier.
Localizing Dates: Luxon vs date-fns When Arabic is Involved
Had to use Luxon because one of our features required timezone-aware date calculations on the client. In Arabic, however, month names needed localized formatting. This line killed me:
ERROR: Cannot create date formatter for locale: arOnly appeared in production builds. The fix? Explicitly importing the Arabic locale in the root layout. Add this somewhere in app/layout.tsx:
import { toJestEach } from 'next-i18next'
import { arabic } from 'date-fns/locale'
if (typeof window !== 'undefined') {
window.__dateFnsLocale = arabic
}And no, this isn't documented anywhere official.
UAE Client Expectations: Arabic Isn't Just a Translation
A small but recurring pain point: local clients treat Arabic as a separate product, not just a language toggle. Colors change (red ≠ celebration), icons flip (RTL directionality), and date formats must follow hijri calendar for certain fields.
We learned this on a UAE real estate platform project — a 3% font size bug in Arabic caused a client escalation because "the menu looked broken on iPhone Safari." Turns out 90% of their users use iOS Safari, per analytics. Mobile emulation in Chrome just won't cut it.
For Tawasul Limo, we ended up running visual regression tests with WebdriverIO for both languages. The extra hours billed? Worth it. The client now thinks we're "magicians who care."
Production Bugs You Can't Predict
Here's one that made me question reality: On a Monday morning, the staging environment started returning 404s for Arabic routes. Local builds worked. Vercel CLI builds worked. The actual deployment? 404. After a support ticket exchange involving screenshots, terminal logs, and bad coffee, the Vercel engineer noticed our deployment's environment variables included I18N_NUMBER with leading zeros — a non-standard formatting that made the routing logic explode.
Removing I18N_NUMBER=042 and using 42 instead fixed it.
No, I'm not making this up.
Final Deployment Tips
- Test cache invalidation patterns aggressively. Use the Vercel CLI to simulate deploys and check cached routes with different headers.
- Don't assume client expectations align with your tech stack. When a UAE client says "bilingual," ask if they want two identical experiences or two localized products.
- Add Arabic RTL testing to your QA process. Safari has different quirks with flexbox, and the cheapest way to find them is letting your designer try the app on an iPhone set to Arabic.
- Write date formatting tests for edge cases. Does 1st of Ramadan display as ١ في رمضان? Can't trust libraries to handle that.
I've done this 6 times now — and every time, something new goes wrong.
Still, it's better than the days of trying to make Gatsby handle Arabic SEO properly.
Found a better way to handle bilingual Next.js builds on Vercel? I'd love to hear it. I'm [Sarah][1] — full-stack dev based in Abu Dhabi, currently working on a plant care app for UAE iOS users (more updates on that coming soon to this blog).
[1]: https://sarahprofile.com/contact