Skip to main content
LazyLocales works seamlessly with i18next and i18next-http-backend to load translations at runtime — no rebuild required when translations update.

Setup

1

Install dependencies

npm install i18next i18next-http-backend react-i18next
2

Create an API token

Generate a read API token in your project settings at lazylocales.com, or via the API:
curl -X POST https://<your-deployment>.convex.site/v1/projects/PROJECT_ID/tokens \
  -H "Authorization: Bearer <your-session-token>" \
  -H "Content-Type: application/json" \
  -d '{"label": "i18next frontend", "permissions": "read"}'
The token is shown once when created. Store it securely.
3

Configure i18next

Point i18next-http-backend at the LazyLocales locale endpoint:
i18n.ts
import i18next from 'i18next';
import HttpBackend from 'i18next-http-backend';
import { initReactI18next } from 'react-i18next';

i18next
  .use(HttpBackend)
  .use(initReactI18next)
  .init({
    backend: {
      loadPath:
        'https://<your-deployment>.convex.site/v1/projects/PROJECT_ID/locales/{{lng}}',
      customHeaders: {
        Authorization: 'Bearer ll_your_api_token',
      },
    },
    lng: 'en',
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false,
    },
  });

export default i18next;
4

Use translations in your components

import { useTranslation } from 'react-i18next';

function Greeting() {
  const { t } = useTranslation();
  return <h1>{t('greeting')}</h1>;
}

Query parameters

The locale endpoint supports optional query parameters:
ParameterTypeDescription
formatstringflat or nested — controls the JSON structure
fallbackstringLocale code to use for missing keys (e.g. en)
versionnumberPin to a specific source file version

Example with fallback

loadPath:
  'https://<your-deployment>.convex.site/v1/projects/PROJECT_ID/locales/{{lng}}?fallback=en',
This merges missing keys from your source locale into the response, so untranslated keys fall back to English.

Caching

The locale endpoint returns caching headers:
  • Cache-Control: public, max-age=300, stale-while-revalidate=3600
  • ETag — hash for cache validation
This means browsers and CDNs will cache translations for 5 minutes, with stale-while-revalidate allowing background refreshes for up to 1 hour.