Build-time JSON Export
Export translations to static JSON files for build-time bundling
This pattern works well when you want LocaleLens as your source of truth, but prefer bundling translations as static JSON files rather than fetching at runtime.
- •Static sites or SSG builds
- •Apps with infrequent translation changes
- •Teams preferring explicit deploy cycles for copy changes
- •Early-stage apps that don't need OTA updates yet
A minimal working example using React, Vite, and i18next:
Includes a fetch script, i18next configuration, and sample translations.
No runtime API calls, server-side proxy, or caching logic required. JSON files are generated artifacts and should not be edited manually.
A simple Node.js script fetches all translations from LocaleLens and writes them to JSON files:
// scripts/fetch-translations.ts
import 'dotenv/config'
import { writeFileSync, mkdirSync } from 'node:fs'
const API_BASE = process.env.LOCALELENS_API_BASE || 'https://localelens.ai/api/v1'
const PROJECT_ID = process.env.LOCALELENS_PROJECT_ID
const API_KEY = process.env.LOCALELENS_API_KEY
async function main() {
// Fetch available locales
const localesRes = await fetch(
`${API_BASE}/projects/${PROJECT_ID}/locales`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
)
const { locales } = await localesRes.json()
mkdirSync('locales', { recursive: true })
// Fetch and write translations for each locale
for (const { code } of locales) {
const res = await fetch(
`${API_BASE}/projects/${PROJECT_ID}/translations/${code}`,
{ headers: { Authorization: `Bearer ${API_KEY}` } }
)
const translations = await res.json()
writeFileSync(`locales/${code}.json`, JSON.stringify(translations, null, 2))
console.log(` ${code}.json - ${Object.keys(translations).length} keys`)
}
}
main()Run with npx tsx scripts/fetch-translations.ts or add to your build pipeline.
Import the JSON files directly — they're bundled at build time:
// i18n.ts
import i18n from 'i18next'
import { initReactI18next } from 'react-i18next'
// Import locale JSON files directly (bundled at build time)
import en from '../locales/en.json'
import de from '../locales/de.json'
import fr from '../locales/fr.json'
i18n.use(initReactI18next).init({
resources: {
en: { translation: en },
de: { translation: de },
fr: { translation: fr },
},
lng: 'en',
fallbackLng: 'en',
interpolation: { escapeValue: false },
})
export { i18n }Be aware: Translation updates require a rebuild and redeploy. There are no over-the-air updates with this approach.
| Aspect | Behavior |
|---|---|
| Updates | Require rebuild and redeploy |
| OTA updates | Not supported |
| Runtime locale switching | Supported (between exported locales only) |
| New locales | Require rebuild |
| API key exposure | None (build-time only) |
If you need over-the-air translation updates, environment-specific translations, or frequently changing copy, consider using the runtime API instead:
- •The fetch script runs at build time only — API keys are never exposed to clients
- •Store API keys in CI secrets or local
.env.localfiles - •The fetch script is safe to run in CI pipelines with read-only API access