Urdu Translation ServiceBidirectional, CPU-Only
A bidirectional Urdu and English translation service on MarianMT, served via FastAPI behind a right-to-left aware web UI, running entirely on CPU with no API keys.
Headline results
- Directions
- Urdu ↔ English
- Runtime
- CPU-only, no keys
- Models
- MarianMT, ~300MB each
- Tests
- Mocked, no weights needed
System architecture

Problem
Urdu is spoken by hundreds of millions of people and served by a fraction of the tooling English gets. A usable bidirectional translation service should not require a GPU, an API key, or a paid tier, and the right-to-left rendering that Urdu needs is the part most quick builds get wrong.
Approach
Two Helsinki-NLP MarianMT models, one per direction, behind a FastAPI service exposing translate, sentiment and health endpoints. Model ids and the inference device are configured in YAML rather than hardcoded. The web UI is vanilla JavaScript with explicit right-to-left handling for the Urdu side. Sentiment analysis runs on translated English output and is deliberately restricted to the Urdu-to-English direction, because the sentiment model is English-only and running it on Urdu would produce a confident meaningless score. The test suite mocks the models so it passes without downloading anything.
Impact
A translation service anyone can run on a laptop with no GPU and no keys, roughly 300MB per direction pulled from Hugging Face on first use. It is off-the-shelf models rather than trained ones, and the engineering is in the deployment: configuration as data, right-to-left rendering, an honest restriction on where sentiment is valid, and tests that do not need the weights.
Decisions & tradeoffs
Refuse to run sentiment where it is meaningless
The sentiment model is English-only. Running it on Urdu input would return a confident score with no basis, so the service restricts it to the direction where it is valid rather than offering it everywhere.
Mock the models in tests
A test suite that downloads 600MB of weights does not run in CI and stops being run locally. Mocking the pipelines keeps the routing, validation and error handling under test where the actual bugs live.
Handle right-to-left properly rather than approximately
Urdu text rendered with default left-to-right assumptions is subtly wrong in ways that are obvious to a reader and invisible to the developer. The UI sets direction explicitly on the Urdu side.
Build spec
- ur → en
- Helsinki-NLP/opus-mt-ur-en
- en → ur
- Helsinki-NLP/opus-mt-en-ur
- Sentiment
- distilbert SST-2, ur→en direction only
- API
- /translate · /sentiment · /health
- Runtime
- CPU-only, no API keys, ~300MB per model
System notes
- Runs on CPU with no keys; each MarianMT model is roughly 300MB and downloads on first use
- Sentiment is restricted to the Urdu-to-English direction because the sentiment model is English-only
- Model ids and device configured in YAML, so swapping models needs no code change
- TestClient tests mock the pipelines, so CI passes without downloading model weights
Stack
MarianMT · transformers · sentencepiece · FastAPI · Vanilla JS · RTL