Better TranslateHome
GitHub
Getting Started
  • Introduction
  • Mission
  • Installation
  • CLI
  • Skills
  • RTL
  • Changelog
Adapters
  • Core
  • React
  • Expo
  • Astro
  • MD & MDX
  • Next.js
  • TanStack Router

React

Use @better-translate/react when React components need translations and locale switching.

1. Install the packages

npm install @better-translate/core @better-translate/react

2. Create the shared translator

Create src/i18n.ts:

ts
1import { configureTranslations } from "@better-translate/core";23const en = {4  home: {5    title: "Hello",6  },7} as const;89const es = {10  home: {11    title: "Hola",12  },13} as const;1415export const translator = await configureTranslations({16  availableLocales: ["en", "es"] as const,17  defaultLocale: "en",18  fallbackLocale: "en",19  messages: { en, es },20});

3. Wrap your app

Create or update src/main.tsx:

tsx
1import React from "react";2import ReactDOM from "react-dom/client";34import { BetterTranslateProvider } from "@better-translate/react";56import { App } from "./app";7import { translator } from "./i18n";89ReactDOM.createRoot(document.getElementById("root")!).render(10  <React.StrictMode>11    <BetterTranslateProvider translator={translator}>12      <App />13    </BetterTranslateProvider>14  </React.StrictMode>,15);

4. Create a typed provider + hook pair

If you want useTranslations() to autocomplete keys and locales without repeating generics or adding a declaration file, bind your translator once:

Create src/i18n-react.ts:

ts
1import { createBetterTranslateReact } from "@better-translate/react";23import { translator } from "./i18n";45export const { BetterTranslateProvider, useTranslations } =6  createBetterTranslateReact(translator);

Then update src/main.tsx to import the app-local provider:

tsx
1import React from "react";2import ReactDOM from "react-dom/client";34import { App } from "./app";5import { BetterTranslateProvider } from "./i18n-react";67ReactDOM.createRoot(document.getElementById("root")!).render(8  <React.StrictMode>9    <BetterTranslateProvider>10      <App />11    </BetterTranslateProvider>12  </React.StrictMode>,13);

5. Read translations inside a component

Create src/header.tsx:

tsx
1import { useTranslations } from "./i18n-react";23export function Header() {4  const { locale, setLocale, t } = useTranslations();56  return (7    <header>8      <h1>{t("home.title")}</h1>9      <button onClick={() => setLocale("en")} disabled={locale === "en"}>10        English11      </button>12      <button onClick={() => setLocale("es")} disabled={locale === "es"}>13        Espanol14      </button>15    </header>16  );17}

Explicit generics still work, so you can keep using useTranslations<typeof translator>() where that fits your codebase better:

tsx
1import { useTranslations } from "@better-translate/react";23import { translator } from "./i18n";45export function Header() {6  const { t } = useTranslations<typeof translator>();78  return <h1>{t("home.title")}</h1>;9}

If you prefer to keep importing directly from @better-translate/react, module augmentation is still supported:

ts
1import { translator } from "./i18n";23declare module "@better-translate/react" {4  interface BetterTranslateReactTypes {5    translator: typeof translator;6  }7}

When to use React only

Use only @better-translate/core + @better-translate/react when:

  • your app is a React SPA
  • your app is an Expo app
  • locale changes happen in client components

If you are in Next.js App Router, keep this package for client hooks and add the Next.js adapter for routing and server helpers.

Generate locale files automatically

Instead of writing every translation by hand, use the CLI to extract strings and generate locale files: CLI guide

Continue with

  • Expo setup
  • Next.js setup

Examples

  • react-vite-example
  • expo-example