Building a Multilingual Product: Translation API Integration Guide
Why Build Translation Into Your Product?
There are two approaches to multilingual products: translate everything manually before release, or build translation capabilities directly into your product. The first approach works for static content but fails for dynamic, user-generated, or frequently updated content. The second approach scales.
Building translation into your product means:
- User-generated content can be translated on the fly
- New features are automatically available in all languages
- Content updates propagate to all languages without manual intervention
- Users can switch languages without waiting for a manual translation cycle
Architecture Patterns
Pattern 1: Translate at Write Time
When content is created or updated, immediately translate it into all supported languages and store the translations alongside the original.
Pros: Fast read performance, no translation latency for end users, works offline Cons: Higher storage costs, translation API calls on every write, all languages must be defined upfront
Best for: Product UI strings, structured content with known language targets
``typescript
// Example: Translate at write time
async function createArticle(article: Article) {
const translations = await Promise.all(
SUPPORTED_LANGUAGES.map(async (lang) => ({
language: lang,
title: await translateText(article.title, 'en', lang),
body: await translateText(article.body, 'en', lang),
}))
);
await db.articles.create({
...article,
translations,
});
}
`
Pattern 2: Translate at Read Time
Translate content when a user requests it in a specific language. Cache the translation for subsequent requests.
Pros: Only translates what is actually needed, supports adding languages without re-translating everything Cons: First request in each language has translation latency, requires caching infrastructure
Best for: Large content libraries, user-generated content, applications with many supported languages
`typescript
// Example: Translate at read time with caching
async function getArticle(id: string, language: string) {
// Check cache first
const cacheKey = article:${id}:lang:${language};
const cached = await cache.get(cacheKey);
if (cached) return JSON.parse(cached);
// Fetch original const article = await db.articles.findById(id);
if (language === article.originalLanguage) { return article; }
// Translate and cache const translated = { ...article, title: await translateText(article.title, article.originalLanguage, language), body: await translateText(article.body, article.originalLanguage, language), };
await cache.set(cacheKey, JSON.stringify(translated), { ttl: 86400 });
return translated;
}
`
Pattern 3: Hybrid Approach
Translate high-traffic content at write time and low-traffic content at read time.
Pros: Optimizes both performance and cost Cons: More complex implementation, need to classify content by traffic level
Best for: Most production applications
API Integration
Basic API Call
Most translation APIs follow a similar pattern:
`typescript
interface TranslationRequest {
text: string;
sourceLanguage: string;
targetLanguage: string;
glossaryId?: string;
}
interface TranslationResponse { translatedText: string; detectedLanguage?: string; confidence: number; }
async function translateText(
text: string,
source: string,
target: string
): Promise,
},
body: JSON.stringify({
text,
sourceLanguage: source,
targetLanguage: target,
glossaryId: 'your-glossary-id',
}),
});
const data: TranslationResponse = await response.json();
return data.translatedText;
}
`
Batch Translation
For efficiency, batch multiple strings into a single API call:
`typescript
async function translateBatch(
texts: string[],
source: string,
target: string
): PromiseBearer ${process.env.TRANSLATE_API_KEY},
},
body: JSON.stringify({
texts,
sourceLanguage: source,
targetLanguage: target,
glossaryId: 'your-glossary-id',
}),
});
const data = await response.json();
return data.translations.map((t: TranslationResponse) => t.translatedText);
}
`
Error Handling and Retries
Translation API calls can fail due to rate limits, network issues, or service outages. Implement proper error handling:
`typescript
async function translateWithRetry(
text: string,
source: string,
target: string,
maxRetries: number = 3
): Promise
if (err.status === 429) { // Rate limited - wait with exponential backoff const delay = Math.pow(2, attempt) * 1000; await new Promise(resolve => setTimeout(resolve, delay)); continue; }
if (attempt === maxRetries) {
// Return original text as fallback
console.error(Translation failed after ${maxRetries} attempts, error);
return text;
}
}
}
return text;
}
`
Caching Strategy
Translation results should be cached aggressively. The same English sentence translates to the same French sentence every time (assuming the same glossary version).
Cache Key Design
`typescript
function getCacheKey(text: string, source: string, target: string, glossaryVersion: string): string {
const hash = createHash('sha256').update(text).digest('hex').substring(0, 16);
return trans:${source}:${target}:g${glossaryVersion}:${hash};
}
`
Include the glossary version in the cache key so that updating your glossary automatically invalidates cached translations.
Cache Levels
L1: In-memory cache (Node.js Map or LRU cache): For frequently translated strings like UI labels. Sub-millisecond lookup, limited by process memory.
L2: Redis/Memcached: For all translations. Shared across application instances. Sub-millisecond to low-millisecond lookup.
L3: Database: For permanent storage of translations that should survive cache flushes.
Cache Invalidation
Invalidate cached translations when:
- The source content changes
- The glossary is updated
- A human reviewer corrects a translation
- You upgrade to a new translation model
Handling Dynamic Content
Interpolation Variables
Template strings with variables need special handling:
`typescript
// English: "Hello {name}, you have {count} new messages"
// The variables {name} and {count} must not be translated
function translateTemplate(
template: string,
source: string,
target: string
): Promise;
});
// Translate the cleaned text const translated = await translateText(cleaned, source, target);
// Restore variables
return translated.replace(/__VAR(\d+)__/g, (_, index) => variables[parseInt(index)]);
}
`
Pluralization
Different languages have different pluralization rules. English has two forms (singular, plural). Russian has three. Arabic has six. Use a library like intl-messageformat to handle pluralization correctly:
`typescript
import { IntlMessageFormat } from 'intl-messageformat';
const messages = { en: '{count, plural, one {# item} other {# items}}', fr: '{count, plural, one {# element} other {# elements}}', ru: '{count, plural, one {# элемент} few {# элемента} many {# элементов} other {# элементов}}', };
function formatMessage(language: string, count: number): string {
const msg = new IntlMessageFormat(messages[language], language);
return msg.format({ count }) as string;
}
`
Performance Optimization
Pre-translate Common Content
Identify your most-viewed content and pre-translate it during off-peak hours. This ensures the most-accessed pages are always served from cache.
Lazy-Load Translations
For pages with many translatable elements, translate the visible content first and lazy-load translations for below-the-fold content:
`typescript
// Translate visible content immediately
const visibleTranslations = await translateBatch(
visibleStrings,
'en',
userLanguage
);
// Translate remaining content asynchronously translateBatch(remainingStrings, 'en', userLanguage) .then(translations => updateUI(translations)); ``
Monitor API Usage
Track your translation API usage to optimize costs:
- Cache hit rate (target above 90%)
- Average translation latency
- API calls per minute
- Cost per language per month
Getting Started with TranslateAI API
TranslateAI provides a REST API with batch translation, custom glossaries, and language detection. Sign up for a free account, get your API key, and start with the code examples above.
The API supports 40+ languages, handles code blocks and formatting automatically, and includes built-in rate limiting with clear response headers. Start with a small integration, measure the impact, and expand from there.
Ready to Translate with Context-Aware AI?
Try TranslateAI free. Upload your content, configure custom glossaries, and get accurate translations in 40+ languages in seconds.
Get Started Free