|Labs
Book a DemoPlatform
React (Lingo Compiler)
Alpha
React (MCP)React (i18n)
CLI

Overview

  • @lingo.dev/react

Getting started

  • Quickstart

Reference

  • LingoProvider
  • useLingo
  • Plurals and select
  • Formatting

LingoProvider

Max PrilutskiyMax Prilutskiy·Updated 8 days ago·2 min read

LingoProvider is the React context that holds the active locale and the messages map. Wrap it once at the root of your app — everything inside can call useLingo() to translate strings or read locale metadata.

Basic usage#

tsx
import { LingoProvider } from "@lingo.dev/react";
import messages from "./locales/es.json";

<LingoProvider locale="es" messages={messages}>
  <App />
</LingoProvider>

Props#

PropTypeRequiredWhat it does
localestringyesBCP-47 tag, e.g. "en", "es", "ar-SA". Drives all formatting + RTL detection.
messagesMessagesnoHash-keyed translations. Defaults to {} (everything falls back to source).
childrenReactNodeyesYour app.

Messages is just Record<string, string> — the same shape the CLI writes to locales/<locale>.json.

Nesting providers#

Providers can nest. The rules are different depending on whether the nested provider has the same locale as the parent or a different one.

Same locale — messages merge#

tsx
<LingoProvider locale="es" messages={sharedMessages}>
  {/* Route-scoped messages override shared on collision; missing keys fall through to shared. */}
  <LingoProvider locale="es" messages={dashboardMessages}>
    <Dashboard />
  </LingoProvider>
</LingoProvider>

Use this to split bundles per route while keeping a common "shell" set of translations at the root.

Different locales — standalone#

tsx
<LingoProvider locale="es" messages={esMessages}>
  <Header />
  <LingoProvider locale="ar-SA" messages={arMessages}>
    {/* This subtree is entirely Arabic; the parent's es messages are NOT visible. */}
    <ArabicEmbed />
  </LingoProvider>
</LingoProvider>

Handy for rendering a single component in a fixed language (a quote, an embed, a preview pane) inside an otherwise different app.

Switching locale at runtime#

Treat locale as React state — change it, and every useLingo() consumer below re-renders with the new locale and message bag.

tsx
function AppRoot() {
  const [locale, setLocale] = useState("en");
  const [messages, setMessages] = useState({});

  async function switchTo(next: string) {
    const next_messages = await import(`./locales/${next}.json`);
    setLocale(next);
    setMessages(next_messages.default);
  }

  return (
    <LingoProvider locale={locale} messages={messages}>
      <LocaleSwitcher current={locale} onSelect={switchTo} />
      <App />
    </LingoProvider>
  );
}

On Next.js, prefer useLocaleSwitch() from @lingo.dev/react-next — it handles router-aware locale changes plus persistence.

What you can read from the context#

useLingo() returns the active Lingo object. Beyond text() and rich() it carries:

  • locale — the BCP-47 string you passed in
  • direction — "ltr" or "rtl", computed via Intl.Locale.textInfo with a fallback list of known RTL languages
  • script — e.g. "Latn", "Cyrl", "Arab"
  • region — e.g. "US", "DE", "SA"

These are useful for conditional layout (mirroring icons in RTL) or analytics tagging — no extra parsing required.

Common mistakes#

  • Forgetting <LingoProvider>. useLingo() throws outside one. The error message tells you to add a provider; if you're seeing it in tests, wrap the render in a test-mode provider with empty messages to make assertions stable.
  • Passing async-loaded messages directly. messages must be a synchronous value. Resolve the promise in a parent (with Suspense or state), then pass the result down.
  • Switching locale without updating messages. The provider trusts both props together — change them in the same useState update or you'll briefly render the new locale with the old translations.

Was this page helpful?