Internationalization
How react-aria's I18nProvider drives locale-aware behavior in the date and menu components, and how that's separate from chassis-css's own dir-attribute RTL support.
A handful of components read the active locale to decide segment order, weekday names, the
calendar system, weekend styling, or which direction a submenu cascades toward.
DatePicker, DateRangePicker,
Calendar, RangeCalendar,
and MenuSubmenu all read that locale the same way — from
react-aria's I18nProvider, falling back to the browser's own locale when none is set. This page
covers setting that locale and its effect, and how it relates to — but doesn't replace —
chassis-css's separate dir-attribute RTL support.
Setting a locale
Wrap an application, or any subtree, in I18nProvider with a
BCP47 language tag:
import { DatePicker, I18nProvider } from '@chassis-ui/react'
<I18nProvider locale="ar-SA">
<DatePicker label="Departure date" />
</I18nProvider>Every component listed above reads whichever I18nProvider is nearest up the tree, the same way
React context normally resolves — a locale set closer to a specific component overrides one set
higher up. With no I18nProvider in the tree at all, these components fall back to the browser's
own locale.
Setting ar-SA above changes more than translated strings: DatePicker's segment order and
weekday names follow the locale, its calendar system switches from Gregorian to Umm al-Qura, and
Calendar/RangeCalendar shift which days render as the muted "weekend" style. None of this is
configured through a prop on the date components themselves — it all flows from the locale.
Import I18nProvider from @chassis-ui/react, not from react-aria directly. react-aria is
bundled into this package rather than installed as a peer, so its module — including the context
I18nProvider provides — is a separate copy from any react-aria a consuming application
installs on its own. An I18nProvider imported from react-aria sets a different context
instance and silently has no effect on this library's components.
Right-to-left
Two independent mechanisms contribute to RTL support, and setting one doesn't set the other.
I18nProvider's locale determines a react-aria direction ('ltr' or 'rtl') that
MenuSubmenu reads via useLocale() — an RTL locale flips which side a submenu cascades toward
and which arrow key opens versus closes it, matching native OS/browser submenu behavior. This
mechanism is scoped to whichever components actually call useLocale() internally; it doesn't
touch anything else on the page.
Everything else — layout mirroring, icon direction, chassis-css's own components — follows the
dir attribute instead, set on <html> or a scoping ancestor, independently of I18nProvider.
Pagination's Prev/Next chevrons, for example, mirror under
an ancestor dir="rtl" through a plain CSS rule, with no react-aria involvement at all. See
chassis-css's own RTL page for the full
logical-properties story this covers.
A fully consistent RTL experience needs both set together — an RTL locale with no dir="rtl"
gets a correctly-mirrored submenu, an Umm al-Qura calendar, but LTR-oriented icons and layout
everywhere else:
<html lang="ar" dir="rtl">
<I18nProvider locale="ar-SA">
<App />
</I18nProvider>
</html>Date values
Calendar, RangeCalendar, DatePicker, and DateRangePicker accept date values as
@internationalized/date objects rather than Date instances or ISO strings — install it
separately to construct them:
npm install @internationalized/dateimport { Calendar } from '@chassis-ui/react'
import { today, getLocalTimeZone } from '@internationalized/date'
<Calendar value={today(getLocalTimeZone())} />Unlike I18nProvider, there's no module-identity concern here — a CalendarDate is a plain data
object, not something read through React context, so a separately-installed copy of
@internationalized/date works the same as any other dependency. See
Calendar and DatePicker
for the full range of value/selection props.
Labels outside the locale system
Not every user-facing string in these components comes from the active locale. react-aria ships
translations for the strings it owns, but a handful of strings these components render themselves
have no equivalent in those dictionaries. They default to English and are translated with a plain
prop, the same way any other label prop would be — I18nProvider has no effect on them.
Pagination's Prev/Next controls take one prop each:
<Pagination pages={10} activePage={page} onActivePageChange={setPage} previousLabel="Précédent" nextLabel="Suivant" />Breadcrumb names its wrapping <nav> landmark "breadcrumb" by default — override it with
aria-label, which is also how you tell two breadcrumb trails on one page apart:
<Breadcrumb aria-label="Fil d'Ariane" items={items} />The calendar family — Calendar,
RangeCalendar,
DatePicker and
DateRangePicker — groups its own strings under a
single labels prop, because several of them are rendered by internal parts a consumer never
mounts directly (the year view's paging arrows, its live-region announcements, the month/year
header buttons, the clear adornment):
<DatePicker
label="Date de départ"
labels={{
calendar: 'Calendrier',
clear: 'Effacer',
month: 'Mois',
year: 'Année',
selectMonth: 'Choisir le mois',
selectYear: "Choisir l'année",
previousYears: 'Années précédentes',
nextYears: 'Années suivantes'
}}
/>labels is merged over the English defaults, so passing one key leaves the rest alone. A
DatePicker's labels also reaches the Calendar it renders inside its own popover — you don't
set it twice. The CalendarLabels type is exported if you want to define one shared object per
locale:
import type { CalendarLabels } from '@chassis-ui/react'
const fr: Partial<CalendarLabels> = { calendar: 'Calendrier', clear: 'Effacer' }Everything else these components say — month and weekday names, segment order, the calendar
system — still follows I18nProvider's locale and needs no override.