Yugen UI

Interface language

Text built into components (the close button, screen reader labels, empty states) is English by default. One messages prop on YugenProvider switches all of it to Vietnamese or to another language.

Switch to Vietnamese

English is the default. messagesVi holds the Vietnamese version of every built-in string; locale changes how dates, times and numbers are formatted.

import { Toaster, YugenProvider, messagesVi } from "yugen-ui";

export function App({ children }: { children: React.ReactNode }) {
  return (
    <YugenProvider applyToDocument messages={messagesVi} locale="vi-VN">
      <Toaster />
      {children}
    </YugenProvider>
  );
}

Built-in strings are the text a component shows or reads to screen readers without you passing it: the close button label, “Loading…”, “No results found”, chart descriptions, aria-live announcements. Content you pass in (titles, children, a Field label) is not changed.

messagesVi is a plain object. Bundlers only include it when you import it, so an English-only app pays nothing for it.messagesEn (the English set, same as the defaults) is still exported, as a base for other languages.

Change a few strings

messages takes a partial object: by component namespace, only the strings to change.

// Change only the strings you need; the rest keep their defaults
<YugenProvider messages={{ dialog: { close: "Close dialog" } }}>…</YugenProvider>

// A nested provider inherits messages and locale from the outer one, then overrides
<YugenProvider messages={messagesVi} locale="vi-VN">
  <YugenProvider messages={{ toast: { dismiss: "Ẩn" } }}>…</YugenProvider>
</YugenProvider>

// A component's own label prop still wins over messages
<SearchBox dismissLabel="Clear keywords" />

Priority: the component's own label prop (such as SearchBox dismissLabel), then messages from the nearest provider, then outer providers, then the English default. Editors suggest namespace and key names from the types, and the Messages section at the end of each component page lists every key with its English and Vietnamese text.

Dates, times and numbers

The locale on YugenProvider is the default Intl locale for components.

Charts, DatePicker, TimePicker, NotificationCenter and Rating format numbers, dates and times with the provider locale (default "en-US"). A component's own locale prop still wins. Calendar uses a react-day-picker locale, set in messages.calendar.locale; messagesVi already sets Vietnamese.

Text direction is handled separately by the dir prop, see RTL.

Other languages

Write a full YugenMessages object, usually starting from messagesEn.

import { messagesEn, type YugenMessages } from "yugen-ui";

// The full YugenMessages type: a missing namespace is a type error
export const messagesJa: YugenMessages = {
  ...messagesEn,
  dialog: { close: "閉じる" },
  toast: { region: "通知", regionHotkey: "通知 ({hotkey})", dismiss: "通知を閉じる" },
  // …
};

<YugenProvider messages={messagesJa} locale="ja-JP">…</YugenProvider>

Strings that contain values (step numbers, notification counts, file names) are functions, so each language can handle plurals and word order. When an upgrade adds a string, the type checker shows what is missing.

Copied source

Each component has a messages.ts file next to it.

// Source copied with the CLI or shadcn: each component has its own messages.ts, English by default
import { dialogMessagesVi } from "@/components/ui/Dialog/Dialog";
import { toastMessagesVi } from "@/components/ui/Toast/Toast";

const messages = { dialog: dialogMessagesVi, toast: toastMessagesVi };

<YugenProvider messages={messages} locale="vi-VN">…</YugenProvider>

messagesVi is only in the npm package. With source copied by @yugen-ui/cli or shadcn, combine the …MessagesVi objects of the components you have; the YugenMessages type only lists those components too. To change a default for good, edit messages.ts directly.

Do
  • Set messages and locale once on the root YugenProvider.
  • Use a component's label prop when one place needs different text from the rest of the app.
Don't
  • Create a new messages object on every render: declare it outside the component or use useMemo.
  • Translate your own content with messages; it is only for the components' built-in text.