Skip to Content
⭐️ Leave a star →
InternationalizationNew

Internationalization

Wire UI is i18n-library agnostic. It ships no translation runtime and bundles no locale data — instead it exposes two integration points and lets your existing i18n library drive them. You keep one source of translations for your whole app; Wire UI just reads from it.

There are exactly two things to wire up:

Locale — a BCP 47 tag (en-US, de-DE) that drives Intl-based formatting in Calendar, DatePicker, NumberInput, and Timeago.
Messages — the handful of user-facing strings components render internally (aria-labels, live-region announcements, placeholders).

Both are passed through one provider. Use the framework switcher above to see the syntax for your stack:

import { WireUIProvider } from '@wire-ui/react' <WireUIProvider locale="de-DE" messages={{ calendar: { nextMonth: 'Nächster Monat' } }}> <App /> </WireUIProvider>

The provider is optional — without it, components fall back to en-US and their English defaults. messages is a deep-partial: override only the strings you want; the rest stay default. Nested providers inherit and merge, so you can switch locale for a subtree.

What’s translatable

Every internal string lives in a typed catalog (WireUIMessages), grouped by component. Most are plain strings; a few are functions that interpolate runtime values — those are the ones to watch when bridging a library. This catalog is identical across React, Vue, and Solid.

NamespaceKeysInterpolated (function) keys
calendarpreviousMonth, nextMonth
numberInputincrement, decrement
timeagojustNow, todaytoday(time)
paginationlabel, previous, next, pagepage(page)
carouselprevious, next, slideslide(current, count)
passwordshow, hide
comboboxtoggle
ratinglabel, valueText, starTextvalueText(value, max), starText(star, max)
otpdigitdigit(index)
toastregion, close

The PartialMessages type makes overrides type-safe — your editor autocompletes the namespaces and flags typos. The full English catalog is defaultMessages, exported for reference.

Just need locale-aware formatting?

If your UI is single-language but you want Wire UI’s dates/numbers formatted for a locale, pass locale alone and skip messages entirely:

<WireUIProvider locale="fr-FR"> <DatePicker /> {/* months, weekday names, number formatting follow fr-FR */} </WireUIProvider>

Wire UI also exports the Intl-backed formatters it uses internally — formatDate, formatNumber, formatRelativeTime, getMonthNames, getDayNames, and friends — so you can format your own values with the same locale rules.

Recipes

The pattern is always the same: a small component reads the active locale and translations from your i18n library and passes them to WireUIProvider. Define it once near your app root. Pick your framework above.

next-intl

In an App Router app, add a wireui namespace to your message catalog (messages/de.json):

{ "wireui": { "calendar": { "previousMonth": "Vorheriger Monat", "nextMonth": "Nächster Monat" }, "pagination": { "label": "Seitennummerierung", "previous": "Zurück", "next": "Weiter", "page": "Gehe zu Seite {page}" }, "carousel": { "previous": "Vorherige Folie", "next": "Nächste Folie", "slide": "Folie {current} von {count}" } } }

Then bridge it in a client component mounted inside NextIntlClientProvider:

'use client' import { useLocale, useTranslations } from 'next-intl' import { WireUIProvider, type PartialMessages } from '@wire-ui/react' export function WireUIIntlProvider({ children }: { children: React.ReactNode }) { const locale = useLocale() const t = useTranslations('wireui') const messages: PartialMessages = { calendar: { previousMonth: t('calendar.previousMonth'), nextMonth: t('calendar.nextMonth'), }, pagination: { label: t('pagination.label'), previous: t('pagination.previous'), next: t('pagination.next'), // Function key → call next-intl with the ICU argument. page: (page) => t('pagination.page', { page }), }, carousel: { previous: t('carousel.previous'), next: t('carousel.next'), slide: (current, count) => t('carousel.slide', { current, count }), }, // …fill in the remaining namespaces from the catalog above. } return ( <WireUIProvider locale={locale} messages={messages}> {children} </WireUIProvider> ) }

react-intl (FormatJS)

react-intl exposes the locale and formatMessage through useIntl(). Give your Wire UI strings wireui.* IDs with standard ICU syntax, e.g. "wireui.pagination.page": "Go to page {page}".

import { useIntl } from 'react-intl' import { WireUIProvider, type PartialMessages } from '@wire-ui/react' export function WireUIIntlProvider({ children }: { children: React.ReactNode }) { const intl = useIntl() const m = (id: string, values?: Record<string, string | number>) => intl.formatMessage({ id }, values) const messages: PartialMessages = { calendar: { previousMonth: m('wireui.calendar.previousMonth'), nextMonth: m('wireui.calendar.nextMonth'), }, rating: { label: m('wireui.rating.label'), valueText: (value, max) => m('wireui.rating.valueText', { value, max }), starText: (star, max) => m('wireui.rating.starText', { star, max }), }, } return ( <WireUIProvider locale={intl.locale} messages={messages}> {children} </WireUIProvider> ) }

Lingui

Lingui is macro-based. Declare your Wire UI strings with the msg macro (so the extractor picks them up) and resolve them through the active i18n instance.

import { useLingui } from '@lingui/react' import { msg } from '@lingui/core/macro' import { WireUIProvider, type PartialMessages } from '@wire-ui/react' export function WireUIIntlProvider({ children }: { children: React.ReactNode }) { const { i18n } = useLingui() const messages: PartialMessages = { calendar: { previousMonth: i18n._(msg`Previous month`), nextMonth: i18n._(msg`Next month`), }, pagination: { previous: i18n._(msg`Previous`), next: i18n._(msg`Next`), // Interpolation lives inside the macro template. page: (page) => i18n._(msg`Go to page ${page}`), }, } return ( <WireUIProvider locale={i18n.locale} messages={messages}> {children} </WireUIProvider> ) }

Run lingui extract and the msg strings land in your catalogs alongside the rest of your app.

Notes

Define the bridge once and place it near the root — every Wire UI component below it is localized. Re-rendering on locale change is handled by your i18n library’s reactivity.
You don’t have to translate everything at once. Override only the namespaces you use; unspecified strings stay at their English defaults.
Lingui is the one library that spans all three frameworks (@lingui/react / @lingui/vue / @lingui/solid) with the same bridging shape — useful for a shared design system across stacks.

Message overrides are set through the provider. The four formatting components — Calendar, DatePicker, NumberInput, and Timeago — additionally accept a locale prop directly, handy for rendering a one-off widget in a different locale without nesting another provider:

<DatePicker locale="ja-JP" />
Last updated on

MIT License © 2026 wire-ui

Internationalization – Wire UI