Skip to documentation
DocumentationSDKs and frameworks

React

Add OTA delivery to an i18next app while keeping native resources, translation hooks, and language switching.

Documented SDK 1.6.0

Requirements: React 18+, i18next 23+, react-i18next 14+

Package reference
On this page

Install the package

Terminal

npm install @rerune/react@1.6.0 i18next react-i18next

These examples follow the SDK version shown above. Start with an application that already renders local translations through i18next and react-i18next. Keep at least one bundled fallback language.

Keep your native configuration

TypeScript · existing i18next options

import type { InitOptions } from 'i18next'
import en from './locales/en/translation.json'
import de from './locales/de/translation.json'

const nativeOptions = {
  lng: 'en',
  fallbackLng: 'en',
  ns: ['translation'],
  defaultNS: 'translation',
  resources: { en: { translation: en }, de: { translation: de } },
  interpolation: { escapeValue: false },
} satisfies InitOptions

Use your actual locale file paths and native configuration. ReRune OTA targets the translation namespace. Other namespaces remain owned by your native i18next setup. The native options object can stay in your existing startup module.

Replace initialization and the provider

TypeScript · existing asynchronous startup

import { ReRune } from '@rerune/react'

const client = await ReRune.setup({
  otaPublishId: '<READ_ONLY_OTA_PUBLISH_ID>',
}, nativeOptions)

Keep imports at module scope. Run the awaited setup once in the application startup where you previously initialized i18next, then mount the app. The nativeOptions object is the configuration shown above. Replace the OTA placeholder with your project read-only Publish ID.

TSX · root provider

import { ReRuneProvider } from '@rerune/react'

<ReRuneProvider client={client} defaultNS="translation">
  <App />
</ReRuneProvider>

Replace I18nextProvider with ReRuneProvider and preserve your default namespace. The provider includes native i18next context. Existing translation hooks continue to use the same keys.

TSX · existing component

import { useTranslation } from 'react-i18next'

export function App() {
  const { t } = useTranslation()
  return <h1>{t('headline')}</h1>
}

Keep plugins and an existing instance

If the app owns an i18next instance with detectors, backend loaders, or plugins, supply that instance to setup. Keep plugin registration and native settings in their existing order. External consumers can use client.i18n.

TypeScript · supply your app-owned instance

import { ReRune } from '@rerune/react'

const client = await ReRune.setup({
  i18n,
  otaPublishId: '<READ_ONLY_OTA_PUBLISH_ID>',
}, nativeOptions)

For an already initialized instance, use the attachment form documented by the package and omit the second setup argument. Passing native options again to an initialized instance rejects.

SSR, hydration, and offline startup

Server-rendered translated HTML needs a request-local i18next instance and awaited ReRune.preload before rendering. Pass the matching hydration state to browser setup with the same locale, resources, variant, and syntax. Browser-only setup cannot change HTML or metadata already sent to a crawler.

Awaited native setup does not wait for every asynchronous cache restore or OTA request. First-run offline rendering needs bundled resources; later cached content depends on retained storage. Keep your normal loading and error behavior, and use hydrationReady where the package requires deferred hydration.