Active Foundation · Example
Language, formats and reading direction
Language, formats and reading directionClient
الطلب 1042
- تاريخ الطلب
- 21/10/2026، 11:30 ص
- المجموع
- 1,234.50 €
Full source examples/i18n/direction.tsx
// apps/docs/examples/i18n/direction.tsx'use client';
import {useState} from 'react';
import {toIanaTimeZone} from '@workspace/active-format';import type {LanguageConfig, LocaleTranslations} from '@workspace/active-i18n';import { fixedTimeZone, I18nProvider, TimeZoneProvider, useFormatters, useLocale, useTranslations,} from '@workspace/active-i18n/react';import {DirectionProvider} from '@workspace/active-ui/components/primitives/direction';import {Slider} from '@workspace/active-ui/components/primitives/slider';import { Tabs, TabsList, TabsTrigger,} from '@workspace/active-ui/components/primitives/tabs';
// The host's language set: the direction of each language is the host's data.const LANGUAGES: readonly LanguageConfig[] = [ {code: 'en', label: 'English', direction: 'ltr'}, {code: 'ar', label: 'العربية', direction: 'rtl'},];
const TRANSLATIONS: Record<string, LocaleTranslations> = { en: { order: { title: 'Order {{id}}', placed: 'Placed on', total: 'Total', progress: 'Progress', }, }, ar: { order: { title: 'الطلب {{id}}', placed: 'تاريخ الطلب', total: 'المجموع', progress: 'التقدم', }, },};
function OrderSummary() { const t = useTranslations(); const locale = useLocale(); const format = useFormatters(); return ( <div className="flex flex-col gap-3"> <p className="font-medium" data-i18n-locale={locale}> {t('order.title', {id: '1042'})} </p> <dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1 text-sm"> <dt className="text-muted-foreground">{t('order.placed')}</dt> <dd>{format.dateTime('2026-10-21T09:30:00Z')}</dd> <dt className="text-muted-foreground">{t('order.total')}</dt> <dd>{format.currency({amount: 1234.5, currency: 'EUR'})}</dd> </dl> <Slider defaultValue={30} aria-label={t('order.progress')} /> </div> );}
/** * The language decides the words and the formats; the host decides the * direction from its language data and sets `dir` and `DirectionProvider`, * so the layout and the arrow keys follow the reading direction. */export default function Direction() { const [code, setCode] = useState('ar'); const language = LANGUAGES.find((entry) => entry.code === code)!; const direction = language.direction ?? 'ltr'; return ( <div className="flex w-full max-w-md flex-col gap-4"> <Tabs value={code} onValueChange={(value) => setCode(String(value))}> <TabsList aria-label="Language"> {LANGUAGES.map((entry) => ( <TabsTrigger key={entry.code} value={entry.code}> {entry.label} </TabsTrigger> ))} </TabsList> </Tabs> {/* A real host navigates to the other language (setLocale); this demonstration remounts the provider instead. */} <I18nProvider key={code} locale={code} translations={TRANSLATIONS[code]!} supportedLanguages={LANGUAGES} allowLocaleSwitching={false} > <TimeZoneProvider value={fixedTimeZone(toIanaTimeZone('Europe/Amsterdam'))} > <DirectionProvider direction={direction}> <div lang={code} dir={direction} className="rounded-lg border p-4" data-i18n-direction={direction} > <OrderSummary /> </div> </DirectionProvider> </TimeZoneProvider> </I18nProvider> </div> );}