// preview in
saved for every page

Languages & RTL

Translate the texts the components bring with them, set the locale of the date components and run any skin right to left.

// you'll learn

  • How MessagesProvider translates built-in texts, and how to change a few of them
  • Every message key, in English and Portuguese
  • Which locale the date components use, and how to set it
  • How DirectionProvider turns a page right to left in every skin

Built-in texts

Most text in a Camaleo interface is yours: labels, titles, button text. A few components also bring texts of their own, like a close button's name, an empty table's message or "Page 3" for a screen reader. Those are English by default.

Put one MessagesProvider near the root to change them. Pick a language below: only the component texts change.

minimal · light · #3fa34d
app/layout.tsx
import { MessagesProvider } from "@camaleo/react";

<MessagesProvider locale="pt-BR">{children}</MessagesProvider>

locale picks a bundled set: "en" (the default) or "pt-BR". A prop on the component always wins over the provider, so <Pagination previousLabel="Back" /> keeps "Back".

Change a few texts

messages takes any subset of the keys. Each group you pass is merged over the set below it, so you only write what changes:

app/layout.tsx
<MessagesProvider
  locale="pt-BR"
  messages={{ drawer: { close: "Fechar painel" }, dataTable: { empty: "Nenhum pedido ainda." } }}
>
  {children}
</MessagesProvider>

Providers nest. An inner provider without locale starts from its parent's texts, which is handy for one area with its own wording:

app/orders/layout.tsx
<MessagesProvider messages={{ dataTable: { empty: "No orders match these filters." } }}>
  {children}
</MessagesProvider>

For a language Camaleo doesn't bundle, write a full set typed as Messages and pass it as messages. The type makes sure no key is missing.

Server or client

Some messages are functions, like pagination.page(3) → "Page 3". React can't pass functions from a Server Component to a client one, so:

app/messages.tsx
"use client";
import { MessagesProvider } from "@camaleo/react";

export function AppMessages({ children }: { children: React.ReactNode }) {
  return (
    <MessagesProvider
      locale="pt-BR"
      messages={{ pagination: { page: (page) => `Ir para a página ${page}` } }}
    >
      {children}
    </MessagesProvider>
  );
}

Read the texts in your own components with useMessages() (client) or <Message pick="spinner.label" /> (server). See Server Components and SSR.

Every message key

This is the Messages interface from packages/react/src/messages.tsx, with the bundled en and ptBR values. Function keys show the result of a sample call.

KeyEnglishPortuguês
breadcrumb.labelBreadcrumbTrilha de navegação
breadcrumb.moreMore pagesMais páginas
carousel.labelCarouselCarrossel
carousel.previousPrevious slideSlide anterior
carousel.nextNext slidePróximo slide
carousel.playPlayReproduzir
carousel.pausePausePausar
carousel.indicatorsChoose slideEscolher slide
carousel.goToSlide(2)Go to slide 2Ir para o slide 2
codeBlock.copyCopyCopiar
codeBlock.copiedCopiedCopiado
codeBlock.labelCodeCódigo
combobox.clearClearLimpar
combobox.showOptionsShow optionsMostrar opções
commandPalette.placeholderType a command or search…Digite um comando ou pesquise…
commandPalette.emptyNo matching commands found.Nenhum comando encontrado.
dataTable.captionData tableTabela de dados
dataTable.emptyNo records found.Nenhum registro encontrado.
dataTable.selectAllSelect all rowsSelecionar todas as linhas
dataTable.selectRow(0)Select row 1Selecionar linha 1
dataTable.paginationTable paginationPaginação da tabela
drawer.closeCloseFechar
fileUpload.chooseChoose filesEscolher arquivos
image.failedFailed to load imageNão foi possível carregar a imagem
image.unavailableUnavailable imageImagem indisponível
inputGroup.showPasswordShow passwordMostrar senha
inputGroup.hidePasswordHide passwordOcultar senha
inputGroup.clearClear searchLimpar busca
numberField.decreaseDecreaseDiminuir
numberField.increaseIncreaseAumentar
otpField.cell(0, 6)Character 1 of 6Caractere 1 de 6
pagination.labelPaginationPaginação
pagination.previousPreviousAnterior
pagination.nextNextPróxima
pagination.page(3)Page 3Página 3
progressCircle.labelProgressProgresso
sidebar.collapseCollapse sidebarRecolher menu lateral
sidebar.expandExpand sidebarExpandir menu lateral
skipLink.labelSkip to contentPular para o conteúdo
spinner.labelLoadingCarregando
splitter.handleResize panelRedimensionar painel
table.scrollTableTabela
tagsInput.remove("design")Remove designRemover design
toast.closeCloseFechar
toggletip.closeClose tipFechar dica
CAREFUL

One text comes from a primitive, not from Camaleo: an indeterminate Progress is announced as "indeterminate progress" by Base UI, in English, whatever the provider says.

Dates and times

MessagesProvider doesn't touch dates. The date components (Calendar, RangeCalendar, DatePicker, DateRangePicker, DateField, TimeField) take a locale prop that sets the segment order, the month and weekday names, the first day of the week and the clock. The same date in three locales:

minimal · light · #3fa34d
11122026
12112026
12112026

Without locale, they use the nearest I18nProvider (re-exported by Camaleo), then the browser's language. Set it on the server, so the server and the browser format the same way:

app/layout.tsx
import { I18nProvider, MessagesProvider } from "@camaleo/react";

<MessagesProvider locale="pt-BR">
  <I18nProvider locale="pt-BR">{children}</I18nProvider>
</MessagesProvider>

Right to left

The skins and the component CSS are written with logical properties (margin-inline-start, inset-inline-end, border-start-start-radius…), so the same CSS works in both directions. To turn a page or a section right to left, do three things together:

  1. dir="rtl" on the element, for the browser's layout.
  2. lang on the same element, so screen readers pick the right voice.
  3. <DirectionProvider direction="rtl"> around it, so the components flip their keyboard (arrows in tabs, sliders, menus) and their popups.

Switch the direction below, then pick other skins in the "preview in" bar: tabs, slider, switch and buttons all mirror, in every skin.

minimal · light · #3fa34d

الإعدادات

app/[lang]/layout.tsx
import { DirectionProvider } from "@camaleo/react";

const dir = lang === "ar" ? "rtl" : "ltr";

<html lang={lang} dir={dir}>
  <body>
    <DirectionProvider direction={dir}>{children}</DirectionProvider>
  </body>
</html>
CAREFUL

A few app-structure rules still use physical sides and don't mirror yet: the Sidebar edge, its active-item bar and counts, shortcut hints in Menubar and CommandPalette, the line of a vertical Stepper and the SkipLink position. Check those parts by eye if you ship a right-to-left app.

Popups opened inside an RTL section stay RTL: the portal wrapper copies the direction. Your own icons that mean "forward" or "back" (arrows, chevrons) need flipping in RTL; icons that show a thing (a bell, a trash can) don't.

Before you ship it

  • One MessagesProvider at the root, with the language of the page
  • Function messages are overridden from a client component
  • Date components get a locale, or sit inside an I18nProvider
  • dir, lang and DirectionProvider change together
  • Arrows and chevrons in your own content flip in RTL
Was this page helpful? · Edit this page on GitHub