Most localization workflows assume a build step: extract strings, translate them, rebuild, redeploy. That model breaks the moment your product ships dynamic content, user-generated text, CMS-driven pages, real-time notifications, or personalized dashboards where strings are unknown at compile time. When every deployment adds 15-30 minutes of pipeline overhead per locale, runtime translation via API becomes the only practical path.
Dynamic localization via APIs lets you translate content on the fly at request time, without rebuilds. The challenge is doing it fast enough that users never notice. This article walks through the architectural patterns, client-side vs. server-side vs. edge execution, caching strategies, request coalescing, fallback chains, and cache invalidation, that let you ship dynamic language switching while meeting p95 latency targets. If your team is weighing these tradeoffs now, explore how Ollang handles runtime translation at enterprise scale.
Why Runtime Translation Matters for Modern Apps
Static localization pipelines were designed for a world where content was known ahead of time. That world is shrinking. Modern applications generate content dynamically: product catalogs change hourly, support articles are authored in real time, and user interfaces adapt based on context, role, and region.
Rebuilding and redeploying for every content change in every locale is operationally expensive and introduces lag between authoring and availability. A single CMS update that touches 40 locales can cascade into 40 rebuilds, each requiring QA and staged rollouts.
Runtime translation decouples content authoring from localization delivery. The application requests translations at the moment it needs them, either on the server before sending HTML to the client or on the client after initial render. This means:
- New content is available in all supported languages immediately, without a deployment.
- Locale coverage scales without multiplying build pipelines.
- A/B tests, feature flags, and personalized content can be localized without pre-generating every variant.
The tradeoff is latency. Every translation request adds network round-trip time, API processing time, and serialization overhead. The rest of this article is about eliminating or hiding that cost.
See a live integration and SLA details
Client-Side vs. Server-Side vs. Edge Translation
Client-Side Translation Tradeoffs
Client-side translation means the browser fetches untranslated content, then calls a translation API (or a proxy to one) to localize strings before rendering them to the user. This approach is simple to implement, a useEffect hook or an onLoad handler can fire translation requests after the initial paint.
The downsides are significant:
- Flash of untranslated content (FOUC): Users see the source language before translations arrive. This is jarring and unprofessional.
- SEO blindness: Search engine crawlers typically do not execute JavaScript-heavy translation flows, so translated content never enters the index.
- Latency multiplication: Each user's browser independently calls the API, often from high-latency mobile connections. There is no opportunity for server-side caching to absorb repeated requests.
- Secret exposure: API keys or tokens must be embedded in client-side code or proxied, adding complexity.
Client-side translation is acceptable for authenticated dashboards or internal tools where SEO is irrelevant and FOUC can be masked with skeleton loaders. For public-facing content, it is almost always the wrong choice.
Server-Side Translation with Caching
Server-side translation moves the API call to your backend. The server receives the request, determines the target locale, fetches translations, and returns fully localized HTML. The user never sees untranslated content.
This pattern works well with caching. Since the server controls the translation pipeline, it can cache results in memory (e.g., an LRU cache), in a shared store like Redis, or in a CDN layer. Repeated requests for the same content in the same locale hit the cache instead of the translation API.
A typical Node.js implementation looks like this:
const translationCache = new Map();
async function getTranslation(text, targetLocale) {
const cacheKey = `${targetLocale}:${hashString(text)}`;
if (translationCache.has(cacheKey)) {
return translationCache.get(cacheKey);
}
const result = await callTranslationAPI(text, targetLocale);
translationCache.set(cacheKey, result);
return result;
}
The tradeoff is that your origin server bears the computational and memory cost of caching, and cold starts (first request for a given string + locale pair) still incur full API latency.
Edge Execution with CDN Workers
Edge execution pushes translation logic to CDN workers, Cloudflare Workers, Vercel Edge Functions, AWS CloudFront Functions, or similar runtimes. These run in data centers geographically close to the user, cutting network round-trip time to the translation cache dramatically.
The pattern combines the benefits of server-side translation (no FOUC, SEO-friendly) with the latency profile of a CDN. The edge worker intercepts the request, checks a distributed key-value store for cached translations, and only calls the translation API on a cache miss.
Edge execution is particularly effective because:
- Translation results are highly cacheable. The same string translated to the same locale produces the same output deterministically.
- Edge KV stores (like Cloudflare KV or Vercel Edge Config) provide single-digit-millisecond reads from the nearest PoP.
- You can perform locale detection (via Accept-Language header, geo-IP, or cookie) at the edge before the request ever reaches your origin.
The constraint is runtime limitations. Edge workers typically have CPU time limits (often 10-50ms of compute), limited memory, and restricted access to external APIs. You must design translation calls to be fast and fallback-safe.
Prefetch and Caching Strategies for Translation APIs
KV Stores for Per-Locale Translation Caching
A distributed key-value store is the backbone of any low-latency runtime translation system. The design of your cache keys determines whether the system is fast and correct or fast and subtly wrong.
A robust cache key scheme encodes the target locale, a content hash, and glossary identity/version:
translation:{locale}:{contentHash}:{glossaryId}:{glossaryVersion}
For example:
translation:de-DE:a1b2c3d4:gloss_abc123:v3
This ensures that:
- Different locales never collide.
- Content changes produce new hashes, automatically invalidating stale translations.
- Glossary updates (e.g., a rebranded product name) invalidate only the affected entries.
When using edge KV stores like Cloudflare KV, keep in mind that writes are eventually consistent (typically propagating globally within ~60 seconds). For most translation use cases, this is acceptable, a brief window where some PoPs serve a slightly older translation is far better than a cache miss on every request.
ETags, Cache-Control, and Stale-While-Revalidate
HTTP-level caching headers provide a second layer of defense against unnecessary API calls, especially for responses served through CDNs or browser caches.
A well-configured response from your translation endpoint should include:
Cache-Control: public, max-age=300, stale-while-revalidate=3600
ETag: "a1b2c3d4-de-DE-gloss_abc123-v3"
- max-age=300 tells caches the translation is fresh for 5 minutes.
- stale-while-revalidate=3600 allows caches to serve the stale version for up to an hour while asynchronously fetching a fresh copy in the background. This is critical for latency: the user always gets an instant response, and revalidation happens invisibly.
- The ETag enables conditional requests. On revalidation, the cache sends If-None-Match: "a1b2c3d4-de-DE-gloss_abc123-v3", and if the translation hasn't changed, the API responds with 304 Not Modified, no body, minimal bandwidth.
The stale-while-revalidate directive, defined in RFC 5861, is the single most impactful header for runtime translation latency. It effectively guarantees that cached translations are served instantly while keeping them fresh in the background.
Prefetching Common Locale Bundles
For pages with predictable content (navigation, footers, common UI strings), prefetch translations during deployment or on a scheduled basis rather than waiting for the first user request. A background job can warm the cache by iterating through your supported locales and calling the translation API for each string bundle.
This converts cold-start latency from a user-facing problem to a background operational cost. The first real user request for any prefetched string hits the cache immediately.
Selecting APIs for Low-Latency SLAs
Not all translation APIs are built for runtime use. Many are designed for batch workflows where a 2-5 second response time is acceptable. When selecting an API for on-the-fly localization, evaluate these criteria:
| Criterion | What to Look For |
|---|---|
| p95 Latency | Sub-200ms for short strings (under 500 characters). Ask for SLA documentation, not just averages. |
| Glossary Enforcement | API-level support for term glossaries that override generic translations. Critical for brand consistency. |
| Placeholder Safety | Guaranteed preservation of placeholders like {userName}, {{count}}, and HTML tags. The API must return them intact and correctly positioned. |
| Batch Endpoints | Ability to send multiple strings in a single request to amortize network overhead. |
| Async/Webhook Support | For longer content, the API should support async jobs with webhook callbacks rather than forcing long-polling. |
| Rate Limits | Published, generous rate limits with clear 429 response behavior and Retry-After headers. |
If you want a concrete option that focuses on runtime constraints, latency-conscious endpoints, glossary enforcement, and placeholder safety, Ollang is one provider designed for these integration patterns. For a review of API fit against your latency and glossary needs, see how Ollang's API fits your integration.
Glossary Enforcement at the API Level
Glossary enforcement ensures that specific terms, product names, legal terms, branded phrases, are translated consistently and correctly every time. Without it, a translation API might render "Workspace" as "Arbeitsbereich" in one response and "Arbeitsplatz" in another.
The best translation APIs accept a glossary ID or inline glossary entries as part of the request payload:
{
"text": "Create a new Workspace in your Dashboard.",
"source_lang": "en",
"target_lang": "de",
"glossary_id": "gloss_abc123"
}
This is non-negotiable for enterprise localization. If your API does not support glossary enforcement, you will spend engineering time on post-processing heuristics that are fragile and error-prone.
Placeholder and Markup Preservation
Dynamic content is full of interpolation placeholders and HTML markup. A translation API that corrupts {count} items remaining into {Anzahl} Artikel übrig has broken your application. The API must treat placeholders as opaque tokens.
Look for APIs that explicitly document placeholder preservation behavior. Some APIs support a preserve_formatting or tag_handling parameter. Others require you to pre-process strings, replacing placeholders with XML-style tags that the translation engine is trained to preserve:
{
"text": "Hello <x id='1'/>, you have <x id='2'/> notifications.",
"source_lang": "en",
"target_lang": "ja",
"tag_handling": "xml"
}
Ollang's API is built for runtime use: glossary-aware, placeholder-safe, and engineered for low-latency across text, software UI, and document types. Talk to our team about integrating Ollang’s runtime API.
