Skip to content

v12.0.0: Locale via ThemeProvider Migration Guide

Breaking changes when upgrading to the locale-via-ThemeProvider version of Casper UI

Casper UI previously required you to pass a locale (or localeString) prop to each localized component individually - and different components supported different, inconsistent sets of locales. As of v12.0.0, locale is provided once, centrally, via ThemeProvider, and every localized component reads it from there instead. See the Localization guide for full usage.

Why? Locale was previously duplicated across 8 components, each with its own prop, its own locale union type, and its own hand-rolled translation file. This meant components could silently diverge - one supporting a language another didn’t - and a page using several localized components had to pass the same locale value to every one of them individually. Centralizing it in ThemeProvider removes the duplication and the drift risk in one move.

Component Change
ThemeProvider New locale prop - set this instead
DatePicker localeString prop removed
Combobox locale prop removed
PhoneInput locale option removed from usePhoneInput()
Table localeString prop removed
Collapsible locale prop removed
RichTextEditor locale prop removed from RichTextEditor.Root
Paginator locale prop removed (was required)
ImageUpload locale prop removed
Types / hooks See Removed exports

Add a locale prop to your app’s ThemeProvider (or wherever you render one closest to the root):

<ThemeProvider>
<ThemeProvider locale="sv-SE">
<App />
</ThemeProvider>

Then remove the now-unused locale / localeString prop from every component below.

<DatePicker localeString="sv-SE" selectedDate={date} onDateChange={setDate} />
<DatePicker selectedDate={date} onDateChange={setDate} />

This also applies to DateRangePicker, DateMultiPicker, and DateWeekPicker.

<Combobox locale="sv-SE" id="fruit" items={items} selectedItems={selected} onChange={setSelected} />
<Combobox id="fruit" items={items} selectedItems={selected} onChange={setSelected} />
const phone = usePhoneInput({ defaultCountry: "SE", locale: "sv-SE" });
const phone = usePhoneInput({ defaultCountry: "SE" });
<Table data={data} columns={columns} localeString="sv-SE">
<Table data={data} columns={columns}>

If you were also passing a matching locale to a Paginator next to the Table, that is no longer necessary - both now read the same value from ThemeProvider.

<Collapsible collapsedHeight={80} locale="sv-SE">
<Collapsible collapsedHeight={80}>
<RichTextEditor.Root editor={editor} locale="sv-SE">
<RichTextEditor.Root editor={editor}>
<Paginator locale="sv-SE" pageSize={pageSize} itemCount={itemCount} onPageChange={setPageIndex} />
<Paginator pageSize={pageSize} itemCount={itemCount} onPageChange={setPageIndex} />

locale was previously a required prop on Paginator - it is now removed entirely, not made optional.

<ImageUpload locale="sv-SE" aspectRatio={ImageUploadAspectRatio.OneByOne} onSave={handleSave} />
<ImageUpload aspectRatio={ImageUploadAspectRatio.OneByOne} onSave={handleSave} />

The per-component locale types are replaced by a single AppLocale type:

import type { Locales, RichTextEditorLocale } from "@caspeco/casper-ui-library";
import type { AppLocale } from "@caspeco/casper-ui-library";

Context hooks no longer expose the locale - read it with useLocale() instead:

const { localeString } = useTableContext();
const { locale } = useRichTextEditorContext();
const locale = useLocale();

Rendering the same page in multiple locales

Section titled “Rendering the same page in multiple locales”

If you need different locales in different parts of a single page, wrap that part in a LocaleProvider:

<ThemeProvider locale="sv-SE">
<TableInSwedish />
<LocaleProvider locale="fr-FR">
<TableInFrench />
</LocaleProvider>
</ThemeProvider>