Localization & Internationalization
Generate documents in multiple languages with proper formatting for dates, currencies, and text direction.
Overview
Document Stack supports generating documents in any language. Since templates use data binding, localization is handled through the data you pass to the API — the template stays the same, and the content adapts based on your data.
Language Through Data
The simplest approach is to pass localized strings in your API data:
{
"invoiceTitle": "Invoice",
"dateLabel": "Date",
"totalLabel": "Total",
"customerName": "John Smith",
"invoiceDate": "January 15, 2025",
"total": "$1,250.00"
}{
"invoiceTitle": "Rechnung",
"dateLabel": "Datum",
"totalLabel": "Gesamt",
"customerName": "Hans Müller",
"invoiceDate": "15. Januar 2025",
"total": "1.250,00 €"
}The same template works for both — field elements display whatever text you send.
Date Formatting
Format dates on the client side before sending to the API. Different locales expect different formats:
| Locale | Format | Example |
|---|---|---|
| US English | MM/DD/YYYY | 01/15/2025 |
| UK English | DD/MM/YYYY | 15/01/2025 |
| German | DD.MM.YYYY | 15.01.2025 |
| Japanese | YYYY年MM月DD日 | 2025年01月15日 |
| ISO | YYYY-MM-DD | 2025-01-15 |
const date = new Date("2025-01-15");
// US English
date.toLocaleDateString("en-US"); // "1/15/2025"
// German
date.toLocaleDateString("de-DE"); // "15.1.2025"
// Japanese
date.toLocaleDateString("ja-JP"); // "2025/1/15"
// Long format
date.toLocaleDateString("en-US", {
year: "numeric",
month: "long",
day: "numeric",
}); // "January 15, 2025"Currency Formatting
Currency symbols and number formatting vary by locale:
const amount = 1250.5;
// US Dollar
new Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
}).format(amount); // "$1,250.50"
// Euro (German)
new Intl.NumberFormat("de-DE", {
style: "currency",
currency: "EUR",
}).format(amount); // "1.250,50 €"
// Japanese Yen
new Intl.NumberFormat("ja-JP", {
style: "currency",
currency: "JPY",
}).format(amount); // "¥1,251"
// Indian Rupee
new Intl.NumberFormat("en-IN", {
style: "currency",
currency: "INR",
}).format(amount); // "₹1,250.50"Number Formatting
Thousands separators and decimal points differ across locales:
| Locale | Thousands | Decimal | Example |
|---|---|---|---|
| US/UK | , | . | 1,250.50 |
| Germany/France | . | , | 1.250,50 |
| Switzerland | ' | . | 1'250.50 |
| India | , | . | 1,250.50 |
Use Intl API
Always use JavaScript's built-inIntl.NumberFormat and Intl.DateTimeFormat for formatting. They handle locale-specific rules automatically.Multi-Language Templates
You have two approaches for supporting multiple languages:
- One template, localized data — Use field elements for all text (including labels) and pass translated strings in the data. Best for simple documents.
- Per-language templates — Create separate templates for each language with static text in the local language. Best when layout changes significantly.
Font Support for Non-Latin Scripts
When generating documents in languages with non-Latin scripts, ensure your template uses fonts that support those characters:
- CJK (Chinese, Japanese, Korean) — Use Noto Sans CJK or similar
- Arabic / Hebrew — Use fonts with RTL support
- Devanagari (Hindi) — Use Noto Sans Devanagari
- Thai — Use Noto Sans Thai
Character Support
If characters appear as boxes or question marks in the generated PDF, the selected font doesn't support those characters. Switch to a font with the required character set.Next Steps
- Custom Fonts — Add fonts for different scripts
- Data Formatting — Format values in templates
- Data Binding — Connect data to templates