mrkeyoor.com_
Sat 08 Aug 21:01 UTC
npmWeb Frontendupdated 08 Aug 2026

use-intl

use-intl is the framework-neutral React core of next-intl. An `IntlProvider` supplies a locale, ICU message catalog, timezone, named formats, current time, and error policy; hooks then translate messages and format numbers, dates, relative times, lists, and display names. Messages support variables, plural and select branches, and rich React elements. The package uses JavaScript Intl and FormatJS internals, ships type declarations, and supports React 17 through 19. It does not provide Next.js routing, locale detection, catalog fetching, or a translation-management service.

Verdict

A strong React-only i18n core if you like ICU messages and want explicit, typeable formatting without the rest of next-intl. Do not mistake it for a localization platform or routing solution, and budget for catalog loading, ICU training, fallbacks, timezone consistency, and runtime Intl support.

API stability4/5The public model is compact and consistent: IntlProvider supplies configuration, while useTranslations, useFormatter, useLocale, useTimeZone, useMessages, and useNow read it. Core exports also support non-hook translation and formatting. The package is on major 4 and current exports are explicit, but ESM-only packaging, experimental extraction work in the wider monorepo, ICU compiler changes, and type-system improvements mean major upgrades should be tested against every catalog rather than treated as dependency-only changes.
Docs4/5The package README includes a complete provider setup, nested message example, interpolation, date formatting, and plural syntax, then links to a working generic React example and a dedicated core-library guide. The wider next-intl site thoroughly explains messages, dates, numbers, TypeScript, and error handling. Discovery is the main weakness: most branding and search results say next-intl, so readers must keep generic use-intl capabilities separate from Next.js-only routing, middleware, and server-component APIs.
Maintenance5/5Version 4.13.5 was published on August 4, 2026 and the monorepo was pushed on August 7. The changelog shows frequent fixes for ICU escaping, plural branches, prototype safety, TypeScript compatibility, and precompilation, while the repository is not archived. GitHub reports 48 open issues and pull requests across the larger next-intl project, so the queue includes more than this core package but also reflects an actively reviewed and rapidly released codebase.
Ecosystem4/5The npm last-week endpoint recorded 4,899,066 downloads, and the shared repository has 4,336 stars. The package builds on platform Intl, intl-messageformat, FormatJS memoization, ICU syntax, and React 17 through 19, while its API transfers directly to next-intl for teams that later adopt Next.js. It lacks the backend and plugin breadth of i18next and intentionally omits routing, detection, catalog transport, editors, and vendor integrations, so its ecosystem score comes from interoperability and adoption rather than breadth.

Use it if

  • You want next-intl's hook and ICU-message model in React without adopting Next.js or locale-aware routing
  • Your product needs plural rules, select branches, rich text, number and date formatting, and shared named formats from one provider
  • You want message-key autocompletion and value checking through TypeScript module augmentation
  • You need explicit locale, timezone, current-time, fallback, and error inputs so server and client formatting can agree
Skip it if

Setup reality

Install `use-intl` and provide compatible React 17, 18, or 19. Version 4.13.5 is ESM-only, exports separate `use-intl/core`, `use-intl/react`, and message-format subpaths, and includes TypeScript declarations. The minimum working tree wraps consumers in `IntlProvider` with a valid Unicode locale tag and a messages object. There is no required config file, native build, credential, loader, or translation service, but there is also no automatic locale detection or message fetching. Your application must decide the locale, load the right catalog, handle a failed catalog request, and remount or update the provider when the user switches languages. Components outside the provider throw when they use hooks. Message keys are nested by namespace and strings use ICU MessageFormat, so literal braces and apostrophes require ICU-aware escaping; plural messages should include `other`, and values must match the message variables. Provider values matter for rendering consistency. If `timeZone` is absent, formatting uses the user's zone; server-rendered HTML can then disagree with the browser. Supply an IANA timezone and a stable `now` when deterministic server and client output matters. `useNow()` is static when the provider supplies `now` unless an `updateInterval` is requested; an interval creates recurring renders and must be chosen according to the visible precision. The provider memoizes its context, but newly created `messages`, `formats`, callback, or Date objects can still re-render every consumer, so load catalogs once and memoize derived configuration. Missing or invalid messages default to console errors while rendering a key-like fallback, which is convenient in development but too easy to overlook in production. Set `onError` for reporting and `getMessageFallback` for deliberate user-facing output. Rich messages execute component functions supplied by your code, not HTML from the catalog, which avoids treating translator text as markup but requires each expected tag to be mapped. Type-safe keys are opt-in through module augmentation against the catalog shape; very large inferred catalogs can increase TypeScript work. Because use-intl does not bundle locale data beyond the platform Intl implementation, older or constrained runtimes may need FormatJS polyfills for the exact Intl APIs used. Catalog extraction and the Next.js plugin workflow live elsewhere in the monorepo, so do not assume installing this core package creates or updates translation files.

Patterns

Provide a locale and message catalogconfigure-provider

import { IntlProvider } from 'use-intl';

const messages = { App: { greeting: 'Hello {name}!' } };

root.render(
  <IntlProvider locale="en" messages={messages} timeZone="UTC">
    <App />
  </IntlProvider>
);

The application must load the correct catalog and choose the locale. A fixed timezone avoids server and browser formatting differences.

Translate within a message namespacetranslate-namespaced-message

import { useTranslations } from 'use-intl';

function Header() {
  const t = useTranslations('Header');
  return <h1>{t('title')}</h1>;
}

The component must render below IntlProvider, and the catalog must contain `Header.title` for the active locale.

Insert values into a translated messageinterpolate-values

// messages: { Profile: { greeting: 'Hello, {firstName}!' } }
function Greeting({ firstName }: { firstName: string }) {
  const t = useTranslations('Profile');
  return <p>{t('greeting', { firstName })}</p>;
}

Value names must match the ICU placeholders exactly; module augmentation can make missing values a compile-time error.

Handle plural branches with ICU syntaxformat-plurals

// messages: { Cart: { items: '{count, plural, =0 {Empty} =1 {One item} other {# items}}' } }
const t = useTranslations('Cart');
return <span>{t('items', { count })}</span>;

Always include an `other` branch. The `#` token inserts the locale-formatted plural number.

Choose text with an ICU select messageselect-enum-label

// messages: { Order: { state: '{status, select, paid {Paid} pending {Pending} other {Unknown}}' } }
const t = useTranslations('Order');
return <span>{t('state', { status: order.status })}</span>;

Select keys are exact string matches and still need `other` for unexpected or newly introduced values.

Map trusted rich-message tags to React elementsrender-rich-text

// messages: { Legal: { terms: 'Read the <link>terms</link> before continuing.' } }
const t = useTranslations('Legal');
return t.rich('terms', {
  link: (chunks) => <a href="/terms">{chunks}</a>,
});

The catalog names tags, but application code supplies the actual React elements and destinations; do not inject translator strings as HTML.

Format a currency valueformat-currency

import { useFormatter } from 'use-intl';

const format = useFormatter();
const price = format.number(1299.5, {
  style: 'currency',
  currency: 'EUR',
});

Formatting uses the provider locale. Currency does not convert exchange rates; the number must already represent the requested currency.

Format a date in the provider timezoneformat-date-time

const format = useFormatter();
const label = format.dateTime(order.createdAt, {
  dateStyle: 'medium',
  timeStyle: 'short',
});

Set IntlProvider `timeZone` for consistent server and client output, or pass an explicit timezone in the formatting options.

Keep relative time labels currentformat-relative-time

import { useFormatter, useNow } from 'use-intl';

const format = useFormatter();
const now = useNow({ updateInterval: 60_000 });
return <span>{format.relativeTime(publishedAt, now)}</span>;

An update interval triggers recurring renders. Match it to the displayed precision instead of refreshing every second by habit.

Join a list according to locale rulesformat-list

const format = useFormatter();
const label = format.list(['React', 'Vue', 'Svelte'], {
  type: 'conjunction',
});

This relies on Intl.ListFormat in the runtime; add an appropriate polyfill where the target environment does not supply it.

Report errors and render an intentional fallbackhandle-missing-messages

<IntlProvider
  locale={locale}
  messages={messages}
  onError={(error) => reportI18nError(error)}
  getMessageFallback={({ namespace, key }) =>
    namespace ? `[${namespace}.${key}]` : `[${key}]`
  }
>
  <App />
</IntlProvider>

The default logs formatting errors and returns a key-like value. A custom policy makes production failures visible and predictable.

Enable typed message keys with module augmentationtype-message-catalog

// global.d.ts
import messages from './messages/en.json';

declare module 'use-intl' {
  interface AppConfig {
    Messages: typeof messages;
  }
}

Use one canonical catalog shape. Translation files with missing or structurally different keys still need a separate validation step.

Alternatives

PackageRegistryPick it when
react-intlnpmChoose it when the team prefers FormatJS's established component and imperative API ecosystem directly
react-i18nextnpmChoose it when an existing i18next backend, language detector, plugin, or translation workflow is the deciding factor
i18nextnpmChoose the framework-neutral core when translations must be shared across React, server jobs, and non-React clients