Skip to main content

v2 Β· React 19-ready Β· TypeScript 6

React i18n,
without the weight.

localize-react is a tiny, type-safe React i18n library built on Context and hooks. Under a kilobyte brotli, zero runtime dependencies, dual-published ESM + CJS.

< 1 kB
gzip
916 B ESM, brotli
0
runtime deps
100%
test coverage
stmt/func/lines
ESM + CJS
dual published
app.tsx
import { LocalizationProvider, useLocalize } from 'localize-react';

const translations = {
en: { hello: 'Hi {{name}}!' },
es: { hello: 'Β‘Hola {{name}}!' },
ja: { hello: '{{name}}さん、こんにけは!' },
};

function Greeting() {
const { translate } = useLocalize();
return <h1>{translate('hello', { name: 'Alex' })}</h1>;
}

export default function App() {
return (
<LocalizationProvider locale="en" translations={translations}>
<Greeting />
</LocalizationProvider>
);
}

What you get

Tiny on the outside, careful on the inside.

Every byte and every type is intentional. Here's what you can rely on.

Microscopic

One provider, one hook, one component. The whole runtime is under a kilobyte brotli β€” small enough to leave in your critical path.

Type-safe by default

Strict TypeScript 6 source. Types ship inside the package. A 10-line helper turns descriptor strings into a literal union.

Boring on purpose

No ICU, no extraction, no async runtime, no plugins. Just nested JSON, dot-paths, and {{mustache}} tokens. The kind of API you don't reread the docs for.

Plays well with React 19

Server-safe usage, Suspense-friendly lazy loading, hooks-era peer range (>=16.8). Tested in CI through React 19.

Safe to ship

Verbatim string substitution β€” values with regex metachars render correctly. Missing keys warn and fall back instead of throwing.

Modern packaging

Dual ESM + CJS exports with correct `types` conditions. Validated by publint and arethetypeswrong on every PR.

How it works

From install to translated UI in 30 seconds.

1

Install

# pick one
npm install localize-react
pnpm add localize-react
yarn add localize-react
bun add localize-react
2

Define translations

export const translations = {
en: { greeting: { hello: 'Hi {{name}}!' } },
es: { greeting: { hello: 'Β‘Hola {{name}}!' } },
} as const;
3

Mount the provider

<LocalizationProvider
locale="en"
translations={translations}
>
<App />
</LocalizationProvider>
4

Translate

const { translate } = useLocalize();
return <h1>{translate('greeting.hello', { name: 'Alex' })}</h1>;

Honest scope

What's intentionally not in the box.

If you need any of these, prefer a heavier library. We deliberately stay small so you can compose what you need on top.

  • No ICU MessageFormat (use Intl on top, if you need it)
  • No automated message extraction
  • No locale negotiation (BCP 47 matching)
  • No date/number/plural formatting (the platform already ships them)

See Why localize-react? for the full reasoning, and the Intl recipe for plurals/currency/dates with platform APIs.

Ready in two minutes.

Translate one component first. Add more languages whenever.