React
Use @better-translate/react when React components need translations and locale switching.
1. Install the packages
npm install @better-translate/core @better-translate/react2. Create the shared translator
Create src/i18n.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:
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:
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:
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:
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:
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:
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