Translations
Translate the text that components show on their own, and format dates, numbers and money for each language.
locale: en-GB
import * as React from "react"
import { HelConfigProvider } from "@hel/ui/config"How it works#
Some text belongs to the component, not to your page: the label on a clear button, the name of a navigation landmark, "Previous" on a pagination, "Today" in a calendar. Hel UI ships this text in English only, and you add every other language yourself, in one place: the messages of the config.
There are two separate settings, and they do different jobs:
localedecides how dates, times, numbers and money are written. It is a full tag such as"de-DE"or"ar-EG".messagesholds the translated text, by language:de,ar,de-CH.
In the preview, the buttons change both together. Choose Arabic, and the digits, the date and the currency follow the locale, the words on the pagination and the label of the clear button come from the messages, and DirectionProvider and dir turn the layout around. These are three small pieces that you switch together when the language changes.
Add a language#
List the components that you translate under the language. You write only what differs from English.
import { defineConfig } from "@hel/ui/config"
export const helConfig = defineConfig({
locale: "de-DE",
messages: {
de: {
pagination: { navigation: "Seitenwahl", previous: "Zurück", next: "Weiter" },
searchField: { clear: "Suche löschen" },
},
},
})A language that you do not list shows English. A component that you do not list shows English, even in a language that you do. A single missing text also shows English, so you can translate a little at a time, and a half-finished language still works.
Each component has a key, and the type of the config tells you its texts as you type. The keys are: actionBar, alert, asyncContent, attachments, autocomplete, breadcrumb, colorPicker, combobox, commandMenu, commandPalette, creatableSelect, date, dialog, drawer, dropdownMenu, errorState, link, masks, pagination, popover, qrCode, resizable, searchField, sidebar, skeleton, spinner, table, tagInput, timeline, toast and tree. The date key holds the text of the calendar and the date and time pickers.
Some texts are functions, because they hold a value. For example, the calendar's weekNumber takes the week and returns the text, so you can put the number where your language wants it.
Which text wins#
From the weakest to the strongest:
- The English text that the component ships.
- Your text for the language, such as
ar. - Your text for the language and region, such as
ar-IQ, which wins overarfor that region. - The
messagesprop of the component.
The language comes from the locale prop of the component if it has one, then the locale of the config, then the lang of the page, then the language of the browser.
Examples#
Text for one component#
Every component that has built-in text takes a messages prop, and most take a locale as well. Use it to change a word for one place, such as a button that should say "Show earlier events" in a single timeline. It wins over everything in the config.
The built-in text
- Invoice sent
Reworded for this timeline only
- Invoice sent
import { Stack } from "@hel/ui/stack"
import { Text } from "@hel/ui/text"
import {Languages that browsers cannot format#
Some languages have no data in some browsers. Chrome, for example, has none for Central Kurdish, and writes a date in English. fallbackLocales writes the language in another locale, and the default is { ckb: "ar-IQ" }. The mapping always applies, so the server and every browser write the same thing. It changes only how numbers and dates are written. The texts still come from the entry for the language you asked for, so your ckb messages are used.
defineConfig({
fallbackLocales: { ckb: "ar-IQ" },
messages: { ckb: { pagination: { next: "دواتر" } } },
})Right-to-left#
The language does not set the direction for you. Wrap the app in DirectionProvider and set dir on the same element, as the preview does. The provider tells the components how to move with the arrow keys and where to open a popup, and dir turns the layout and the logical CSS around. Popups that render outside the page, such as menus and dialogs, read the direction themselves. See the page on fonts for how the font changes with the direction.
<DirectionProvider direction="rtl">
<Stack dir="rtl" lang="ar">...</Stack>
</DirectionProvider>Read the text in your own components#
useMessages gives your own components the same system. Pass the key, the English defaults, and optionally a locale and overrides.
import { useMessages } from "@hel/ui/locale"
const messages = useMessages("pagination", { navigation: "Pagination", previous: "Previous", next: "Next" })useLocale(locale?, numberingSystem?) returns the locale that a component should format with, after the config and the fallbacks.
Props#
Config#
| Key | Type | Default |
|---|---|---|
locale | a BCP 47 tag | the page lang, then the browser |
fallbackLocales | Record<string, string> | { ckb: "ar-IQ" } |
messages | Record<language, { [component]: texts }> | English only |
On a component#
| Prop | Type | Default |
|---|---|---|
locale | a BCP 47 tag | from the config |
messages | the texts of that component, partial | from the config |