File Mode
File mode uses a static JSON translation file — no server connection at runtime. Perfect for static sites, CDNs, and offline-first apps.
Setup
<script src="/path/to/loco.js"></script>
<script>
// Single file
Loco.init({ file: '/translations.json' });
// Multiple files (merged)
Loco.init({ files: ['/translations-core.json', '/translations-extra.json'] });
// Multiple files with a high-priority override file
Loco.init({
files: [
'/translations-core.json',
{ url: '/client-overrides.json', priority: 100 }
]
});
Loco.apply('zh-CN');
// Optional floating language picker
Loco.widget({ position: 'bottom-right' });
</script>
Merge order and file priority
When multiple files are passed, they merge in order — a later file's entries win any key conflicts. Each entry in files can be a URL string or an object:
Loco.init({
files: [
'/translations-core.json', // priority 0 (default)
{ url: '/client-overrides.json', priority: 100 } // merges last, wins conflicts
]
});
Files merge in ascending priority order, so the highest-priority file always wins key conflicts regardless of its position in the array. Files with equal priority keep their array order (later still wins).
URLs containing clientSpecificTranslationsJson automatically get priority 100 unless an explicit priority is set. New integrations should use the explicit { url, priority } form instead.
Getting the JSON file
Export from the dashboard: Translations → Approved tab → Export JSON.
Or download a single language: GET /api/export/:lang from the REST API.
Translation JSON format
{
"languages": ["fr", "zh-CN"],
"languageNames": {
"fr": "Français",
"zh-CN": "Simplified Chinese"
},
"translations": {
"fr": [
{ "key": "Hello", "context": "", "value": "Bonjour" },
{ "key": "Delete", "context": "button", "value": "Supprimer" },
{ "key": "Welcome back, {{text:0}}", "context": "", "value": "Bon retour, {{text:0}}" },
{ "key": "{{number:0}} items in cart", "context": "", "value": "{{number:0}} articles dans le panier" }
],
"zh-CN": [
{ "key": "Hello", "context": "", "value": "你好" },
{ "key": "Delete", "context": "button", "value": "删除" }
]
},
"timestamp": 1715000000000
}
Each translation is an object with key, context, and value. The context field disambiguates the same phrase appearing in multiple UI locations. Translations within each language are an array, not a map.
Variable slots in translations
Slot tokens ({{text:0}}, {{number:0}}, {{date:0}}) must be preserved in the translated value. See Variable Slots for details.
Caching (IndexedDB)
Loco caches translation files in IndexedDB for offline use and faster load times. To force a refresh:
await Loco.pullLatest(); // re-fetches if server timestamp is newer
await Loco.clearCache(); // clear all cached files + saved language preference
Differences from Server Mode
| Server Mode | File Mode | |
|---|---|---|
| Server required at runtime | ✅ Yes | ❌ No |
| Auto phrase discovery | ✅ Yes | ❌ No (manual export) |
| Real-time translation updates | ✅ Yes | ❌ No (redeploy required) |
| AI translate | ✅ Yes | ✅ (export after) |
| Language switcher widget | ✅ Yes | ✅ Yes |
| IndexedDB offline cache | ❌ No | ✅ Yes |
| Works on static hosting | ❌ No | ✅ Yes |