Time & Language

Localization

Dates, times and numbers follow the locale through Intl. The text of the interface comes from a label pack, so you ship only the languages you use. Right to left layouts mirror the whole scheduler, including the drag gestures and the arrow keys.

Two Settings

locale is a BCP 47 tag and drives every format: the day names, the month title, the hour gutter, the time on a chip, the digits. It defaults to en-US. labels is the text the scheduler writes itself: Today, Week, All day, and what it announces to a screen reader. The two are independent, so Vietnamese dates under English labels is a valid combination.

<script lang="ts">
  import { Scheduler } from '@sv5ui/scheduler';
  import { vi } from '@sv5ui/scheduler/locales';
</script>

<!-- locale formats dates, times and numbers through Intl.
     labels is the text of the interface. They are independent. -->
<Scheduler bind:events locale="vi-VN" labels={vi} hour12={false} weekStartsOn={1} />

Pick a Language

Thirteen packs ship with the package. Arabic switches the direction as well.

19 – 25 thg 10, 2026

GMT+7
Thứ 2 19
Thứ 3 20
Thứ 4 21
Thứ 5 22
Thứ 6 23
Thứ 7 24
CN 25
Cả ngày
Lunch break
<script lang="ts">
  import { Scheduler } from '@sv5ui/scheduler';
  import { vi } from '@sv5ui/scheduler/locales';
</script>

<!-- locale formats dates, times and numbers through Intl.
     labels is the text of the interface. They are independent. -->
<Scheduler bind:events locale="vi-VN" labels={vi} hour12={false} weekStartsOn={1} />

Loading Packs

Packs are named exports of @sv5ui/scheduler/locales. A static import keeps only the packs you name. The entry is a single module, so a dynamic import defers all of them together rather than one per language; at a few hundred bytes each that is rarely worth splitting further.

// Each pack is a named export, so the bundler keeps only what you import
import { en, vi, ja } from '@sv5ui/scheduler/locales';

const packs = { en, vi, ja };
const labels = packs[user.language] ?? en;

// Or load one when the language is picked. The entry is one module, so
// this defers all thirteen together rather than one at a time.
const { de } = await import('@sv5ui/scheduler/locales');

Bundled packs

ExportLanguage
enEnglish
viTiếng Việt
arالعربية
deDeutsch
esEspañol
frFrançais
itItaliano
ja日本語
ko한국어
nlNederlands
ptPortuguês
ruРусский
zh中文

Overriding Single Strings

labels accepts any subset. Keys you leave out fall back to English, and announce merges key by key too, so changing one spoken sentence keeps the other eight. To override on top of another language, spread the pack first.

<!-- Any subset. Missing keys fall back to English; announce merges key by key -->
<Scheduler bind:events labels={{ today: 'Now', newEvent: 'Untitled' }} />

<!-- Override on top of another pack -->
<Scheduler bind:events locale="vi-VN" labels={{ ...vi, today: 'Bây giờ' }} />

<!-- Change what a screen reader hears -->
<Scheduler
  bind:events
  labels={{ announce: { moved: (event, start) => `${event.title} is now at ${start}` } }}
/>

Writing a Pack

A complete pack is a SchedulerLabels: thirty one keys and ten announcements. Keys that carry a count are functions, so a language can form its plurals its own way. Type the object and a missing key is a compile error. Every pack in the package is written this way, so any of them serves as a template. The file lives in your app, not in the package: put it next to your other translations, import it, and pass it to labels the same way as a bundled pack.

src/lib/locales/sv.ts
// src/lib/locales/sv.ts, or wherever your app keeps translations.
// Nothing registers it: you import it and pass it to labels.
import type { SchedulerLabels } from '@sv5ui/scheduler';

// A complete pack, typed so a missing key is a compile error.
export const sv: SchedulerLabels = {
  today: 'Idag',
  previous: 'Föregående',
  next: 'Nästa',
  month: 'Månad',
  week: 'Vecka',
  day: 'Dag',
  agenda: 'Agenda',
  year: 'År',
  allDay: 'Heldag',
  views: 'Vy',
  menu: 'Visa eller dölj sidopanelen',
  sidebar: 'Kalender',
  actions: 'Fler åtgärder',
  noEvents: 'Inga händelser',
  calendars: 'Mina kalendrar',
  searchEvents: 'Sök händelser',
  unscheduled: 'Oplanerat',
  newEvent: 'Ny händelse',
  createEvent: 'Skapa händelse',
  openEvent: 'Öppna detaljer',
  close: 'Stäng',
  deleteEvent: 'Ta bort händelse',
  // Counts are functions, so a language can handle plurals its own way
  more: (count) => `+${count} till`,
  dayCell: (date, count) => (count === 0 ? `${date}, inga händelser` : `${date}, ${count} händelser`),
  holidayDate: (date, holiday) => `${date}, ${holiday}`,
  weekNumber: (week) => `V${week}`,
  weekNumberLabel: (week) => `Vecka ${week}`,
  eventCount: (count) => `${count} händelser`,
  duration: (hours, minutes) => [hours > 0 ? `${hours} h` : '', minutes > 0 ? `${minutes} min` : ''].filter(Boolean).join(' '),
  grid: (view) => `Kalender, ${view}`,
  event: (event, start, end) => `${event.title}, ${start} till ${end}`,
  announce: {
    created: (event) => `Skapade ${event.title}`,
    moved: (event, start) => `Flyttade ${event.title} till ${start}`,
    resized: (event, end) => `${event.title} slutar nu ${end}`,
    deleted: (event) => `Tog bort ${event.title}`,
    updated: (event) => `Uppdaterade ${event.title}`,
    selected: (event) => `Valde ${event.title}`,
    cancelled: 'Avbrutet',
    reverted: (event) => `Kunde inte spara ${event.title}, ändringen ångrades`,
    conflict: (event) => `${event.title} ändrades någon annanstans`,
    notEditable: (event) => `${event.title} kan inte ändras`
  }
};
src/routes/+page.svelte
<!-- src/routes/+page.svelte -->
<script lang="ts">
  import { Scheduler } from '@sv5ui/scheduler';
  import { sv } from '$lib/locales/sv';
</script>

<Scheduler bind:events locale="sv-SE" labels={sv} />

Labels

KeyEnglish
todayToday
previousPrevious
nextNext
monthMonth
weekWeek
dayDay
yearYear
agendaAgenda
allDayAll day
viewsView
menuToggle sidebar
sidebarCalendar
actionsMore actions
noEventsNo events
calendarsMy calendars
searchEventsSearch events
unscheduledUnscheduled
newEventNew event
createEventCreate event
openEventOpen details
closeClose
deleteEventDelete event
more+3 more
dayCellMonday, September 14, 2026, 2 events
holidayDateMonday, September 14, 2026, Founders day
weekNumberW38
weekNumberLabelWeek 38
eventCount3 events
duration2h 30m
gridCalendar, Week view
eventStandup, 9:00 AM to 9:15 AM

Announcements

Read to screen readers through a live region after an action. The event's title is inserted as is.

KeyEnglish
createdCreated Standup
movedMoved Standup to 10:00 AM
resizedStandup now ends at 9:30 AM
deletedDeleted Standup
updatedUpdated Standup
selectedSelected Standup
cancelledCancelled
revertedCould not save Standup, change reverted
conflictStandup was updated elsewhere
notEditableStandup cannot be edited

Clocks

hour12 forces a 12 or 24 hour clock in the hour gutter, on chips, in the agenda, in the details and in every announcement. Left unset, the locale decides: en-US reads 2:00 PM, vi-VN reads 14:00.

First Day of the Week

weekStartsOn takes 0 for Sunday through 6 for Saturday and defaults to Monday. It shapes the week view, the month grid, the year grid and the DateNavigator, and it is the week a weekly recurrence rule counts from when the rule sets no weekStart of its own. It is not read from the locale, because the two often disagree in practice.

Right to Left

Set dir="rtl" on the scheduler, or on any ancestor: left unset, it reads the computed direction of the page when it mounts. The sidebar and panels dock on the other side, the arrows flip, resize edges swap, and the left and right keys move the other way. Event titles are set to dir="auto" so a Latin title inside an Arabic calendar still truncates at its end. The same events, in Japanese and then in Arabic; the toolbar, the weekday order and the +N counts all mirror.

2026年10月

月曜日
火曜日
水曜日
木曜日
金曜日
土曜日
日曜日
28
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1

أكتوبر ٢٠٢٦

الاثنين
الثلاثاء
الأربعاء
الخميس
الجمعة
السبت
الأحد
٢٨
٢٩
٣٠
١
٢
٣
٤
٥
٦
٧
٨
٩
١٠
١١
١٢
١٣
١٤
١٥
١٦
١٧
١٨
١٩
٢٠
٢١
٢٢
٢٣
٢٤
٢٥
٢٦
٢٧
٢٨
٢٩
٣٠
٣١
١
<script lang="ts">
  import { ar } from '@sv5ui/scheduler/locales';
</script>

<!-- dir flips the layout, the arrows, the resize edges and the left/right keys.
     Left unset, the scheduler reads the direction of the page when it mounts. -->
<Scheduler bind:events locale="ar-EG" labels={ar} dir="rtl" />

Custom View Names

The five built-in views take their switcher text from the pack. A view you register names itself through ViewDefinition.label, so translate that string yourself. See Custom Views & Layouts.

Building Blocks Take Labels Too

Used inside the scheduler, the sidebar parts read its labels. Used on their own they read a few keys each from a labels prop: today for DateNavigator, searchEvents for SearchBox, calendars for CalendarList, unscheduled and duration for DragSourceList. mergeLabels turns a partial set into a complete one.

<script lang="ts">
  import { mergeLabels, CalendarList, SearchBox, DateNavigator } from '@sv5ui/scheduler';
  import { vi } from '@sv5ui/scheduler/locales';

  // The standalone parts read a few keys each; hand them a complete set
  const labels = mergeLabels({ ...vi, searchEvents: 'Tìm nhanh' });
</script>

<DateNavigator {date} onSelect={(day) => (date = day)} {labels} locale="vi-VN" />
<SearchBox bind:value={search} {labels} />
<CalendarList {calendars} bind:hiddenCalendars {labels} />

Props

The five settings of this page.

PropTypeDefault
localestring'en-US'
labelsPartialLabelsEnglish
hour12booleanfrom locale
weekStartsOnWeekDay1
dir'ltr' | 'rtl'inherited