Better Translation

The T component

Wrap component copy in T and the plugin gives it a stable lookup id at build time.

T component

Use T for source copy that already lives as component children. At build time the Vite plugin turns the source copy into a stable lookup id, so there is usually nothing to name and nothing to keep in sync by hand.

Checkout.tsx
import { T } from "better-translation/react"

export function Checkout() {
  return (
    <button>
      <T>Pay now</T>
    </button>
  )
}

At runtime T looks up the translated value for the active Locale and renders it. If no value exists yet it falls back to the original source copy, so your UI is never blank while translations catch up.

Use T around the smallest complete Message a translator should see. Keep surrounding markup outside when it is only layout, and keep meaningful inline content inside the Message.

ProjectEmptyState.tsx
import { T } from "better-translation/react"

export function ProjectEmptyState() {
  return (
    <section>
      <h1>
        <T>No Projects yet</T>
      </h1>
      <p>
        <T>Create your first Project to start syncing Messages.</T>
      </p>
    </section>
  )
}

Rich text

Rich text is allowed directly inside React and Svelte T markers. Static inline elements and source-owned components stay inside the Message, where Better Translation turns them into numbered Rich-text slots for translators and renders the translated content through the exact authored React element or Svelte Snippet. Props, events, actions, bindings, and component implementations remain source-owned; translated strings are never rendered as arbitrary HTML. The Vite plugin and runtime handle numbering and validation internally, so Consumer apps do not import a validator or register rich-text renderers.

SafetyNotice.tsx
import { T } from "better-translation/react"

export function SafetyNotice() {
  return (
    <T>
      Always make sure <strong>you are safe first</strong> before approaching the casualty.
    </T>
  )
}

Source-owned components are not limited to a built-in registry. Normal identifiers such as B and member components such as Text.Italic work without Better Translation inspecting what they render:

import type { ReactNode } from "react"

function B({ children }: { children: ReactNode }) {
  return <b className="font-semibold">{children}</b>
}

export function CustomSafetyNotice() {
  return (
    <T>
      Always make sure <B>you are safe first</B>.
    </T>
  )
}

Supported native inline tags include strong, b, i, em, span, a, and br, among other text-level elements, and can be nested. Keep unsupported native layout or media elements outside T; wrap source-owned behavior in a component when it belongs to the Message.

Translations may reorder sibling Rich-text slots but must preserve every slot, Variable placeholder, paired/self-closing shape, and authored parent topology. If a Locale value does not preserve that structure, React and Svelte both render the authored source content instead. Use Var for runtime values.

No rich-text setup

Rich text has no parser, validator, renderer registry, or tag map for Consumer apps to import. Author the element or component inside T; the Vite plugin and runtime carry it through automatically.

Context

Use context to tell translation tools what the Message means, where it appears, or what tone it needs. This is especially useful for short copy where the source words are not enough for a good translation.

Context also disambiguates lookup ids. When the same source copy needs different Locale values, give each Message its own context.

ArchiveActions.tsx
import { T } from "better-translation/react"

export function ArchiveActions() {
  return (
    <>
      <button>
        <T context="Verb, archives the current Branch">Archive</T>
      </button>
      <h1>
        <T context="Noun, page title for archived Branches">Archive</T>
      </h1>
    </>
  )
}

The two Archive Messages above can have different Locale values because context is part of the generated lookup id.

Props

T accepts the source component content as children and two optional author-facing props.

Prop

Type

Use id when an integration needs a stable lookup id that does not depend on the source copy.

ExplicitId.tsx
import { T } from "better-translation/react"

export function ExplicitId() {
  return <T id="billing.checkout.submit">Pay now</T>
}

On this page