Building an AI Document Translation SaaS with Next.js 16 and Cloudflare Workers
The boring engineering decisions that actually make AI products work

Introduction
I've been building and running ExcelTranslator.ai — an AI-powered document translation service.
Despite the name, it handles a lot more than spreadsheets: Excel, Word, PowerPoint, PDF, CSV, subtitle files, and even audio and video. The headline feature is that it translates documents without breaking their layout, formatting, or formulas — which turns out to be the hard part.
This post isn't a code dump. Instead, I want to walk through the architecture and design decisions that make a product like this work. I'll skip the proprietary internals (prompts, backend specifics), but if you're building anything that "takes a file, runs it through AI, and gives a file back," there should be something useful here.
Why "translation" is harder than it looks
Translating raw text is trivial today — one API call and you're done. The hard part is putting the translated text back into the original file structure.
Take Excel as an example. A naive approach immediately runs into:
How do you preserve merged cells, borders, fonts, and background colors?
How do you translate text without corrupting formulas like
=SUM(...)?How do you handle columns that should never be translated (IDs, codes, SKUs)?
What about embedded images, shapes, and charts?
PDFs bring layout reconstruction. Audio and video bring a whole "transcribe → translate → rebuild subtitles" pipeline. Every format has its own flavor of pain.
So the product is really less of a "translation service" and more of a pipeline that understands a file format, extracts exactly what should be translated, and reassembles it. The AI is just one component inside that pipeline.
The high-level architecture
Responsibilities split cleanly into three parts:
[ Browser (Next.js) ]
│ ① Config (languages, style, glossary…)
│ ② Upload the file to storage
▼
[ Object Storage (Cloudflare R2) ]
│
▼
[ Backend (parse → AI translate → reassemble) ]
Frontend stack
Next.js 16 (App Router)
next-intl for internationalization
Tailwind CSS v4 + shadcn/ui for a consistent design system
Deployed on Cloudflare Workers via the OpenNext adapter
Design language
The whole UI follows a "Premium B2B SaaS" direction — the kind of trustworthy-but-not-flashy tone you see in Linear or Stripe. Primary color is Indigo, structural color is Slate. I keep these rules written down in a project guidelines file so the implementation doesn't drift (which also pairs really well with AI-assisted development).
A few design decisions worth sharing
1. A "preview before you pay" UX
Something underrated in translation SaaS: letting users verify quality before paying.
After upload, the system translates just a portion of the file to generate a preview. Users can:
See the original and translated content side by side
See the estimated token count and price
…and only then decide whether to run the full translation. For Excel previews I use Univer to render the spreadsheet with formatting, right in the browser. Letting people see what the translated file will actually look like — before downloading — does a lot for trust.
2. Give users control over the AI
Left unsupervised, AI translation gets creative in bad ways. So I built in several control surfaces:
Translation styles — formal, casual, academic, technical, and so on
Glossaries — "always translate this term this way." There's a reusable account-level dictionary and a per-file working copy
Exclusion rules — for Excel, skip specific columns, rows, or sheets. Essential for protecting IDs and codes
Document context — pass hints like "this is a medical document" to improve accuracy
The philosophy here is "don't hand everything to the AI — let humans draw the boundaries."
3. Take i18n seriously from day one
Since a translation product inherently serves a global audience, the UI is multilingual from the start. I use next-intl to manage 10+ locales.
A few things I got right early:
URL-based locales (
as-needed, so the default language carries no prefix)getTranslations()in server components,useTranslations()in client componentsProper
hreflangand canonical URLs for SEO
Retrofitting i18n later is a nightmare. Nailing the routing and message structure at the start ended up being the cheapest path by far.
Deploying Next.js on Cloudflare Workers: the good and the gotchas
Running Next.js on Cloudflare Workers (via OpenNext), here's my honest take:
What's great
Edge delivery — fast from anywhere in the world
Tight integration with R2 (S3-compatible storage), and no egress fees, which is a perfect match for a file-heavy product
Low infrastructure overhead
What to watch for
Libraries that assume a full Node.js runtime won't always just work
Heavy processing should not live at the edge — design around offloading it to a separate worker or backend
Splitting responsibilities — "light work at the edge on Cloudflare, heavy file processing on a dedicated backend" — let me lean into the strengths of each.
See it in action (video)
Text only goes so far, so here's a short walkthrough of the actual flow: uploading a file, picking languages and a translation style, checking the preview, and translating.
https://www.youtube.com/watch?v=YhK0i1yPnuI
Wrapping up
On the surface, ExcelTranslator.ai is just "upload a file, get a translation." Underneath, it's a stack of deliberate decisions:
A parse-and-reassemble pipeline that keeps formatting intact
Preview-before-pay to earn user trust
Glossaries and exclusion rules to keep the AI on a leash
An i18n setup that was multilingual from line one
It's tempting to think "AI product = the model and the prompt." But what actually determines the experience is all the unglamorous engineering around it. That was my biggest takeaway from building this.
If you're curious, give ExcelTranslator.ai a try — feedback always welcome.
