# Localized labels

> English, German, Chinese and Arabic labels, clocks and digits, with Arabic right to left.

A shadcn/ui block from the [@reui](https://reui.io) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/reui/c-time-picker-11).

- Page, with a live preview: https://shadcn.exchange/r/reui/c-time-picker-11
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/reui/c-time-picker-11-light-6727d9bc04a3482e.png
- Registry item: https://reui.io/r/new-york-v4/c-time-picker-11.json
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://reui.io/r/new-york-v4/c-time-picker-11.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `card`, `tabs`, `@reui/time-picker`

## Files

### `c-time-picker-11.tsx`

```tsx
"use client"

import { useState } from "react"
import {
  TimePicker,
  TimePickerPanel,
  type TimePickerHourCycle,
  type TimePickerI18nOverrides,
  type TimePickerPeriodPosition,
} from "@/components/reui/time-picker"

import { Card } from "@/components/ui/card"
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from "@/components/ui/tabs"

type PickerLocale = {
  lang: string
  name: string
  dir: "ltr" | "rtl"
  hourCycle: TimePickerHourCycle
  periodPosition?: TimePickerPeriodPosition
  i18n?: TimePickerI18nOverrides
}

const ARABIC_DIGITS = "٠١٢٣٤٥٦٧٨٩"

/* Module scope keeps each `i18n` object stable, so the picker merges it
   with the English defaults once, not on every render. English is the
   default config, so it passes none. */
const LOCALES: PickerLocale[] = [
  { lang: "en", name: "English", dir: "ltr", hourCycle: 12 },
  {
    lang: "de",
    name: "Deutsch",
    dir: "ltr",
    /* A 24-hour clock has no period column, so `period`, `am` and `pm` are
       left out. */
    hourCycle: 24,
    i18n: {
      labels: {
        placeholder: "Uhrzeit wählen",
        hour: "Stunde",
        minute: "Minute",
        second: "Sekunde",
        now: "Jetzt",
        clear: "Löschen",
        confirm: "OK",
        panelLabel: "Uhrzeit wählen",
        openPicker: "Zeitauswahl öffnen",
      },
    },
  },
  {
    lang: "zh",
    name: "中文",
    dir: "ltr",
    hourCycle: 12,
    /* 上午 and 下午 come before the time, so the period column leads. */
    periodPosition: "start",
    i18n: {
      labels: {
        placeholder: "选择时间",
        hour: "时",
        minute: "分",
        second: "秒",
        period: "上午/下午",
        am: "上午",
        pm: "下午",
        now: "现在",
        clear: "清除",
        confirm: "确定",
        panelLabel: "选择时间",
        openPicker: "打开时间选择器",
      },
    },
  },
  {
    lang: "ar",
    name: "العربية",
    dir: "rtl",
    hourCycle: 12,
    i18n: {
      labels: {
        placeholder: "اختر الوقت",
        hour: "الساعة",
        minute: "الدقيقة",
        second: "الثانية",
        period: "ص/م",
        am: "ص",
        pm: "م",
        now: "الآن",
        clear: "مسح",
        confirm: "تم",
        panelLabel: "اختر الوقت",
        openPicker: "فتح منتقي الوقت",
      },
      functions: {
        /* A string map rather than Intl, so the server and the browser print
           the same digits. Column typeahead accepts both digit sets. */
        formatSegment: (value) =>
          String(value)
            .padStart(2, "0")
            .replace(/\d/g, (digit) => ARABIC_DIGITS[Number(digit)]),
      },
    },
  },
]

export function Pattern() {
  /* One value for every tab: the language changes the labels and the
     clock, never the stored `HH:mm`. */
  const [value, setValue] = useState<string | null>("14:30")

  return (
    <div className="mx-auto flex w-full max-w-sm flex-col gap-3">
      <Tabs defaultValue="en">
        <TabsList>
          {/* Each tab names its language in that language; `lang` lets a
              screen reader pronounce it. */}
          {LOCALES.map((locale) => (
            <TabsTrigger
              key={locale.lang}
              value={locale.lang}
              lang={locale.lang}
            >
              {locale.name}
            </TabsTrigger>
          ))}
        </TabsList>
        {LOCALES.map((locale) => (
          <TabsContent key={locale.lang} value={locale.lang}>
            {/* Arabic mirrors the header and footer; the columns keep hour first. */}
            <div dir={locale.dir} lang={locale.lang}>
              <Card className="w-fit py-0">
                <TimePicker
                  value={value}
                  onValueChange={setValue}
                  hourCycle={locale.hourCycle}
                  periodPosition={locale.periodPosition}
                  i18n={locale.i18n}
                >
                  <TimePickerPanel />
                </TimePicker>
              </Card>
            </div>
          </TabsContent>
        ))}
      </Tabs>
      <p role="status" className="text-muted-foreground text-sm">
        {value ? `Stored as ${value} in every language` : "No time stored"}
      </p>
    </div>
  )
}
```
