Skip to content

Internationalization (i18n)

Library components render their own library strings: accessible names of buttons (aria-label), visually hidden labels for screen readers and placeholder texts. They are in English by default. You can translate or override them without an external i18n library: the mechanism is built into @smalt-ui/core.

This covers Smalt UI's internal strings only; your app content is translated by your own i18n system (vue-i18n and the like) independently.

Two levels of overrides

  1. Dictionary through ConfigProvider: sets the strings for the whole subtree (the main way).
  2. Component props: override the dictionary on a specific instance (escape hatch).

Translating the dictionary

English (en) is the only built-in locale and the base for everything else. To switch the library to another language, pass the translated strings in the messages prop of ConfigProvider. Keys you leave out fall back to English:

vue
<script setup lang="ts">
import { ConfigProvider, type SMessages } from '@smalt-ui/core'

const deMessages: Partial<SMessages> = {
  close: 'Schließen',
  clear: 'Leeren',
  showOptions: 'Liste anzeigen',
  selectEmpty: 'Keine Ergebnisse',
  prevPage: 'Vorherige Seite',
  nextPage: 'Nächste Seite',
  page: 'Seite',
}
</script>

<template>
  <ConfigProvider :messages="deMessages">
    <App />
  </ConfigProvider>
</template>

Type the object as SMessages instead of Partial<SMessages> and TypeScript will flag every key that is still missing a translation.

The provider renders only its slot (no DOM of its own), so it can go at any level. The same ConfigProvider also passes down prop defaults, so both are set together.

Below is a searchable SSelect with German strings: the accessible names and the "nothing found" text come from messages (type a query with no matches).

Override props

Every library string of a component is also available as a prop of the same name, which overrides the dictionary for that instance:

vue
<template>
  <SDialog close-label="Close preview" />
  <SSelect
    searchable
    show-options-label="Expand"
    empty-text="No cities found"
  />
  <SPagination
    prev-page-label="Back"
    next-page-label="Forward"
  />
</template>

Nuxt

In the Nuxt module the strings are set with the messages option, and the dictionary is provided to the whole app automatically:

ts
export default defineNuxtConfig({
  modules: ['@smalt-ui/nuxt'],
  sui: {
    messages: {
      close: 'Schließen',
      clear: 'Leeren',
    },
  },
})

The locale option accepts only 'en', the default, so there is no need to set it.

Date and time format

Date and time components (SDateField, STimeField, SCalendar, SDatePicker, SDateRangePicker) format values with the en-US tag by default, so a field shows 8/26/2026. Translating messages does not change the format: the strings and the regional format are set separately.

A component's locale prop takes a BCP 47 tag and sets the format for that instance:

vue
<template>
  <SDatePicker
    v-model="date"
    locale="de-DE"
  />
</template>

To use one regional format across the app, set it once as a prop default. global applies to every component with a locale prop, including the numeric mode of SInput:

ts
app.use(createSUI({ defaults: { global: { locale: 'de-DE' } } }))

The current library locale can be read with the useLocale() composable.

Programmatic setup (without a wrapper)

Outside Nuxt the dictionary can be installed at the app level with installLocale, an alternative to ConfigProvider:

ts
import { createApp } from 'vue'
import { installLocale } from '@smalt-ui/core'
import App from './App.vue'

const app = createApp(App)
installLocale(app, { messages: { close: 'Schließen', clear: 'Leeren' } })
app.mount('#app')

Dictionary keys (SMessages)

KeyDefault (en)Used in
closeCloseDialog/drawer/toast/alert
clearClearField clear button
showOptionsShow optionsSSelect searchable
selectEmptyNo results foundSSelect searchable
decrementDecreaseSNumberField
incrementIncreaseSNumberField
openCalendarOpen calendarSDatePicker/SDateRangePicker
prevMonthPrevious monthCalendars
nextMonthNext monthCalendars
prevPagePrevious pageSPagination
nextPageNext pageSPagination
pagePageSPagination (page number)
removeTagRemove tagSTag, SInput/SSelect with use-tags
ratingRatingSRating (item name)
colorSwatchesColor swatchesSColorPicker
dialogLabelDialogHidden name of a dialog without a title
drawerLabelPanelHidden name of a drawer without a title
alertDialogLabelConfirmationHidden name of an alert dialog
confirmConfirmSAlertDialog (default button)
cancelCancelSAlertDialog (default button)
breadcrumbBreadcrumbSBreadcrumb (navigation name)
colorPickerColor pickerSColorPicker (panel)
pickColorPick a colorSColorPicker (trigger button)
stepCompletedCompletedSStepper (completed step mark)
notificationsNotificationsToastProvider (notification region)
rangeStartstartSSlider (range start thumb)
rangeEndendSSlider (range end thumb)
autocompleteEmptyNothing foundSAutocomplete (no suggestions)
loadingLoadingSAutocomplete (hidden loading state label)

The full type is SMessages; it is exported from @smalt-ui/core along with ConfigProvider and the built-in dictionary enMessages.