Appearance
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
- Dictionary through
ConfigProvider: sets the strings for the whole subtree (the main way). - 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)
| Key | Default (en) | Used in |
|---|---|---|
close | Close | Dialog/drawer/toast/alert |
clear | Clear | Field clear button |
showOptions | Show options | SSelect searchable |
selectEmpty | No results found | SSelect searchable |
decrement | Decrease | SNumberField |
increment | Increase | SNumberField |
openCalendar | Open calendar | SDatePicker/SDateRangePicker |
prevMonth | Previous month | Calendars |
nextMonth | Next month | Calendars |
prevPage | Previous page | SPagination |
nextPage | Next page | SPagination |
page | Page | SPagination (page number) |
removeTag | Remove tag | STag, SInput/SSelect with use-tags |
rating | Rating | SRating (item name) |
colorSwatches | Color swatches | SColorPicker |
dialogLabel | Dialog | Hidden name of a dialog without a title |
drawerLabel | Panel | Hidden name of a drawer without a title |
alertDialogLabel | Confirmation | Hidden name of an alert dialog |
confirm | Confirm | SAlertDialog (default button) |
cancel | Cancel | SAlertDialog (default button) |
breadcrumb | Breadcrumb | SBreadcrumb (navigation name) |
colorPicker | Color picker | SColorPicker (panel) |
pickColor | Pick a color | SColorPicker (trigger button) |
stepCompleted | Completed | SStepper (completed step mark) |
notifications | Notifications | ToastProvider (notification region) |
rangeStart | start | SSlider (range start thumb) |
rangeEnd | end | SSlider (range end thumb) |
autocompleteEmpty | Nothing found | SAutocomplete (no suggestions) |
loading | Loading | SAutocomplete (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.