Internationalization
Locale and messages are two independent settings: the locale formats dates, numbers and plurals, the messages translate the text the library owns.
An application can change either one without the other: German dates with English labels, or French messages with the locale of the request. The library ships English only.
| Name | Type | Default | Description |
|---|---|---|---|
| Locale | locale | — | Month and weekday names, week start and weekend, date and time layout, numbers and plural rules. |
| Messages | messages | — | The text of the library: accessible names, visible words, placeholders, hints and announcements. |
A translation is a typed object that your application owns, or a community package provides. KuiMessages is the contract for it and KUI_ENGLISH_MESSAGES is the complete English pack.
Set the locale and a partial messages layer in the root provider. Only the keys you write change; every other key keeps its English default.
import { provideKikitaUi, type KuiMessagesLayer } from '@kikita-labs/ui';
const german: KuiMessagesLayer = {
pagination: { next: 'Weiter', previous: 'Zurueck' },
calendar: { today: 'Heute' },
};
provideKikitaUi({ locale: 'de-DE', messages: german });A message is a string, or a function with one named parameter object for text that depends on values. A group you leave out stays English.
Pass a Signal or a function. The library re-renders its labels when the signal changes and nothing is recreated.
provideKikitaUi({
locale: () => inject(LanguageService).locale, // Signal<string>
messages: () => inject(LanguageService).messages, // Signal<KuiMessagesLayer>
});localeandmessagesalso accept a plain function; it runs in an injection context, so it caninject()services.- Angular
LOCALE_IDis not read implicitly, because it cannot tell "unset" fromen-US. Use the last tab to follow it.
Levels and per-instance inputs let one part of the page differ without affecting another.
@Component({
providers: [
provideKuiI18n({ locale: 'fr-FR', messages: { calendar: { today: "Aujourd'hui" } } }),
],
})
export class BookingComponent {}provideKuiI18n,provideKuiLocaleandprovideKuiMessagesadd a level to a component, a route or an environment injector. A level inherits the locale and messages of its parent and changes only what it names; two subtrees never affect each other.- Explicit label inputs (
ariaLabel,closeLabel,label,swatchLabel,errorLabel,placeholder,emptyText,removeLabeland similar) keep working and win over messages. - The
messagesinput exists on the components that own four or more messages: Calendar, Calendar Range, Carousel, the charts, Color Input, Command Palette, Date Picker, File Upload, Pagination and Time Picker. Calendar and Calendar Range also take alocaleinput. - Per-call data does the same for the imperative openers:
kuiMediaViewer({ messages })andkuiConfirm({ confirmLabel, cancelLabel }). For every other component use a subtree level. - Precedence: explicit label input, then
messagesinput, then the nearest level, then outer levels, thenprovideKikitaUi, then English. Merging is per group and per key;undefinedinherits and an empty string is a real value.
Copy KUI_ENGLISH_MESSAGES, translate the values and let the compiler check every key.
| Name | Type | Default | Description |
|---|---|---|---|
| ctx.locale | string | — | The resolved locale tag. |
| ctx.formatNumber(n) | string | — | A number with the grouping and decimal separators of the locale, in Latin digits. |
| ctx.plural(n, { one, ... }) | string | — | The form Intl.PluralRules selects: zero, one, two, few, many or other. |
fileUpload: {
tooMany: ({ max }, { formatNumber, plural }) =>
`Maksymalnie ${formatNumber(max)} ${plural(max, { one: 'plik', few: 'pliki', many: 'plikow', other: 'pliku' })}`,
},- Messages are text only; do not put HTML in them. Text that you pass to a component (titles, option and tab labels, error text, tooltip content,
acceptLabel) is yours and is never translated by the library. - Messages are plain functions, so any translator fits without a library dependency: wrap it in a function and keep it reactive. This documentation site keeps the Kikita UI messages in its own catalogues and converts them with a short adapter, which is a reference implementation and not a library API.
The locale is resolved from the nearest source and checked against the runtime Intl.
- Order: Calendar
localeinput, nearest level,provideKikitaUi({ locale }), thenKUI_LOCALE. KUI_LOCALEresolves to the first usableAccept-Languagelanguage of the request on the server, hands it to the browser throughTransferStateso the first client render matches the server HTML, and falls back tonavigator.languageand thenen-US. The host locale is never read on the server.- Responses vary by
Accept-Language: a cache in front of the server must sendVary: Accept-Language, or pin a locale withprovideKuiLocale. - A requested tag is canonicalized and checked against the runtime
Intl; the fallback chain is the full tag, then language and script, then language, thenen-US. Development builds warn once on a fallback. The server needs full ICU data (the default in Node 13 and later), otherwise a locale such asru-RUcan fall back on the server and render differently from the browser. - Locale and messages are plain data held per injector, and the formatter caches live in the
KuiI18ninstance, so one request never sees another. ASignalsource that loads asynchronously should resolve before the first render or be provided with the transfer cache.
Each area below follows the resolved locale.
| Name | Type | Default | Description |
|---|---|---|---|
| Calendar | locale | — | Month and weekday names; heading order; first day and weekend from Intl.Locale getWeekInfo (static fallback for older engines); every day button named with its full date. |
| Date Picker | locale | — | Field order and separator of the numeric date (10/03/2026, 03.10.2026). Parsing reads digit groups and needs a four digit year; format pins a layout. |
| Time Picker | locale | — | Default 12 or 24 hour cycle, the separator, the day period text and its position; typing accepts the locale AM/PM text and ASCII am/pm. |
| Pagination, Carousel, Media Viewer, OTP | locale | — | Counts and positions are formatted with the locale. |
| Charts | locale | — | The default value format is the compact notation of the locale (1.2K in English, 1,5 Mio. in German). |
| File Upload | locale | — | Sizes use Intl units (2.5 MB, 340 kB) and progress uses a percent format. |
- Dates are formatted in the Gregorian calendar with Latin digits whatever the locale default is, and calendar names are taken from UTC midnight, so the time zone never moves a day.
- Right-to-left layouts, native non-Latin numerals and non-Gregorian calendars are not supported in 2.0. Text remains translatable in those languages, but layout and digits follow the left-to-right Latin rules.
Accessible names come from the same messages as the visible text.
- A translation changes visible text and accessible names together, and every name is non-empty by default.
- The library does not set
langordir. When the language of the messages differs from the page language, mark the document or the subtree that carries the scope withlang(WCAG 2.2 SC 3.1.2). - Calendar day buttons are named with the full localized date and the grid, month and year controls with messages, so a screen reader gets the context a bare day number lacks.
- To test a translation, wrap every message of the English pack in a marker and render your screens: an accessible name without the marker bypasses the message map.
The public API of the locale and messages layer.
| Name | Type | Default | Description |
|---|---|---|---|
| provideKikitaUi({ locale, messages }) | Provider | — | Root locale and messages. |
| provideKuiI18n({ locale, messages }) | Provider[] | — | A level for a subtree. |
| provideKuiLocale(locale) | Provider[] | — | Locale only. Accepts a tag, a Signal or a function. |
| provideKuiMessages(messages) | Provider[] | — | Messages only. |
| KuiI18n | service | — | locale, messages, context, get(group), setLocale and setMessages. |
| KuiMessages, KuiMessagesLayer | types | — | The full message map and its partial override. |
| KuiMessageContext, KuiPluralForms | types | — | Helpers passed to function messages. |
| KUI_ENGLISH_MESSAGES | KuiMessages | — | The complete English pack. |
| KUI_LOCALE | InjectionToken | — | Root locale source: request, transfer state, navigator. |
| getKuiCalendarLocaleText(locale) | function | — | Month and weekday names, first day and weekend for a locale (pure, no cache). |