Skip to content

Localization

Edit on GitHub

Some components show text or formatting that you don’t pass in. A close button has an accessible label, and a currency input places a currency symbol. Components show these in the language of the page, with no setup.

Each component uses the first valid value in this list:

  1. The locale of the nearest LocaleProvider.
  2. The page language, from <html lang>.
  3. The browser’s preferred language.
  4. English (en).

Set lang on <html> on every page. Browsers and screen readers use it too. Components update when it changes.

Values are normalized, so sv-se becomes sv-SE. Empty and invalid values are skipped.

Built-in labels ship with the packages in more than 40 languages. A component uses the closest match:

  1. The full locale, for example pt-BR.
  2. The language, for example pt.
  3. English.

When a Select or MultiSelect label falls back to English, the component marks it with lang="en" so screen readers pronounce it in English.

Currencies, units and dates use the browser’s Intl formatting. They work for every locale the browser supports.

Text you pass in, such as labels, options and error messages, is shown as written. Translate it in your app.

The server can’t see the page or the browser, so without a provider it renders components in English. When the page becomes interactive (hydrates), components switch to the page language. Users can see the text change.

To avoid the change, render LocaleProvider with the same locale as <html lang>, in a layout that renders on both the server and the browser. LocaleProvider is a client component, so a Next.js server layout can render it:

app/[lang]/layout.tsx
import { LocaleProvider } from '@volvo-cars/react-locale-provider';
import type { ReactNode } from 'react';
export default async function RootLayout({
children,
params,
}: {
children: ReactNode;
params: Promise<{ lang: string }>;
}) {
const { lang } = await params;
return (
<html lang={lang}>
<body>
<LocaleProvider locale={lang}>{children}</LocaleProvider>
</body>
</html>
);
}

In development, the browser console shows a warning when components switch language after hydration.

Without JavaScript, the page keeps the language it was rendered in.

Use LocaleProvider when:

  • Your pages render on the server.
  • Part of a page uses a different language than the rest. Set lang on that part too, so screen readers switch language.

You don’t need it when pages render only in the browser and <html lang> is correct.

A provider affects only the components inside it. The nearest provider wins. CalendarI18nProvider from @volvo-cars/react-calendar is the same provider.

Terminal window
yarn add @volvo-cars/react-locale-provider

Install the package when you use @volvo-cars/react-icons/localized or @volvo-cars/react-messages, even without rendering a provider. They import it.

  • Select: the generated empty option, “Select”.
  • MultiSelect: the empty label, “Select”, and keyboard type-ahead.
  • CurrencyInput: the currency symbol and its position.
  • UnitInput: the unit label and its position.
  • Calendar and RangeCalendar: month and weekday names, and the first day of the week.

useLocale returns the same locale the components use:

import { useLocale } from '@volvo-cars/react-locale-provider';
export function Price({ amount }: { amount: number }) {
const locale = useLocale();
return new Intl.NumberFormat(locale, {
style: 'currency',
currency: 'EUR',
}).format(amount);
}

useLocalizedString(translations) picks a string from an object keyed by locale, with the same fallback as the built-in labels. Include an en entry. Both hooks follow the same server rendering rules as the components.

Components take their direction from the dir attribute, not from the language. Set dir="rtl" on <html> for right-to-left languages.