Skip to content
CodeAtlas UI
On this page SSR apps: I18nProvider

Getting started

Internationalization

Every string the components render comes from a catalog. English is the default, Brazilian Portuguese ships built in, and any phrase can be overridden.

Every visible string the package generates (aria-labels, placeholders, empty states, “Copy”, “On this page”, toast and dialog buttons) comes from a message catalog. The default language is English; Brazilian Portuguese ships built in and any other language can be registered. There are two ways to choose the language.

SSR apps: I18nProvider

On the server, wrap the tree in I18nProvider. The locale lives in Svelte context, so each request renders in its own language and concurrent requests never share state:

<!-- src/routes/+layout.svelte -->
<script>
  import { I18nProvider } from "@codeatlasdev/ui";
  let { data, children } = $props();
</script>

<I18nProvider locale={data.locale}>
  {@render children()}
</I18nProvider>

locale is reactive: change the prop and every component inside re-renders. Pass messages to override phrases for that subtree (see below).

Client-only apps: setLocale

SPAs and Astro islands have no per-request concern, so one module-level locale shared by every island is enough:

<script>
  import { setLocale } from "@codeatlasdev/ui";

  setLocale("pt-BR");
</script>

Add a language

Locales are any BCP 47 tag. Register a dictionary once, at module load. You only translate the keys you need; the rest fall back to English:

// src/lib/i18n.ts
import { registerLocale } from "@codeatlasdev/ui";

registerLocale("es", {
  common: { close: "Cerrar", back: "Atrás" },
  docs: { toc: "En esta página" },
});

Then use it with <I18nProvider locale="es"> or setLocale("es"). Region tags resolve to the base language (es-MX uses es), and unknown tags fall back to English. The exported Messages type describes the full shape and MessagesOverride the partial one.

Override phrases

I18nProvider’s messages prop and setLocale’s second argument are a deep partial of the catalog, merged over the chosen locale:

<I18nProvider locale="en" messages={{ docs: { toc: "In this article" }, common: { copy: "Copy link" } }}>
  {@render children()}
</I18nProvider>

A later setLocale call replaces the previous overrides. Message functions (strings with runtime values) keep their signature:

setLocale("en", {
  notificationBell: { label: (unread) => `Inbox, ${unread} new` },
});

Explicit props win

A text prop always beats the catalog. Components that take text (label, placeholder, confirmLabel, emptyText, …) fall back to the catalog only when the prop is omitted:

<TableOfContents {headings} label="Neste artigo" />

Reactive locale

With setLocale, the locale is shared module state, so every component and every island on the page re-renders when it changes. Read it with locale.value:

<script>
  import { locale, setLocale } from "@codeatlasdev/ui";
</script>

<button onclick={() => setLocale(locale.value === "en" ? "pt-BR" : "en")}>
  {locale.value}
</button>

Inside an I18nProvider, read the active locale and messages from context with useLocale() and useT(), called at the top level of a component <script>:

<script>
  import { useLocale, useT } from "@codeatlasdev/ui";
  const locale = useLocale();
  const t = useT();
</script>

<p lang={locale()}>{t().common.close}</p>

Catalog

The catalog is grouped by component, for example docs.search.placeholder, dialog.close, pagination.next, fileUpload, dataTable and toast. English (en.ts) is the source of truth; pt-BR.ts is typed as Messages, so a missing key is a type error. A test checks that both locales have identical keys.

Server errors

createErrorHandler never reads global locale state. Give it the language of the fallback message, fixed or per request:

// src/hooks.server.ts
import { createErrorHandler } from "@codeatlasdev/ui/kit";

export const handleError = createErrorHandler({ locale: (event) => event.locals.locale as string });

Dates, numbers and masks are separate

The UI language does not change date or number formatting. Pass locale to the components that format values, for example DatePicker, which defaults to pt-BR:

<DatePicker locale="en-US" label="Start date" />

Formatting helpers such as formatCurrency, formatDate and formatNumber take their own locale too.

In tests

The default is English. In browser tests, call setLocale("pt-BR") where a test asserts Portuguese text and reset with setLocale("en") in afterEach, so the module state does not leak between tests. In server-render tests, wrap the component in I18nProvider instead.