TranslatableFields
Shows one field in several locales, one tab per locale. A child field with source title reads title.en and title.fr.
Installation
pnpm dlx shadcn@latest add @chelone/translatable-fields<TranslatableFields> is the read-only twin of
TranslatableInputs. List the locales and
give it the fields to repeat. Each locale gets a tab, and each tab renders the
children against that locale's value.
import { TextField, TranslatableFields } from "@chelone/react";
<TranslatableFields locales={["en", "fr"]}>
<TextField source="title" />
</TranslatableFields>The <TextField source="title" /> reads title.en in the first tab and
title.fr in the second, from a record shaped { title: { en, fr } }. See
Translation for how translatable records are
stored.
Inside a <Show> it uses the ambient record and resource. Pass record or
resource to use it elsewhere. Without a record it throws, except under a
<Show> whose record has not loaded yet, where the React component renders
nothing. See Vue for the difference.
Every locale stays mounted
A hidden tab is not unmounted, so the fields of every locale are in the page whichever tab is showing.
The start locale
defaultLocale picks the tab selected first. Without it, or when it is not one
of locales, the start locale is the app locale when that is listed, and the
first locale otherwise.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | |
| className | string | — | |
| defaultLocale | string | — | Ignored when it is not one of `locales`. Defaults to the app locale when listed, else the first locale. |
| groupKey | string | — | Prefix that keeps the ids of two groups apart. Defaults to `""`. |
| locales | readonly string[] | — | |
| record | Record<string, unknown> | — | The record to show. Defaults to the ambient record. |
| resource | string | — | The resource the fields belong to. Defaults to the ambient resource. |
| selector | ReactNode | — | Replaces the default `<TranslatableFieldsTabs>` locale selector. |
The parts
The selector prop replaces <TranslatableFieldsTabs> when you want a
different locale picker.
TranslatableFieldsTabs
The default locale selector: one tab per locale of the ambient translatable context.
| Prop | Type | Default | Description |
|---|---|---|---|
| groupKey | string | — | Prefix that keeps the ids of two groups apart. Defaults to `""`. |
| variant | "default" | "line" | null | — |
TranslatableFieldsTab
The header of one locale. Its label is ra.locales.<locale> from the catalog,
or the capitalised locale code when that key is missing.
| Prop | Type | Default | Description |
|---|---|---|---|
| groupKey | string | — | Prefix that keeps the ids of two groups apart. Defaults to `""`. |
| locale | string | — |
TranslatableFieldsTabContent
The panel of one locale. It renders the children against that locale's value.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | ReactNode | — | |
| className | string | — | |
| groupKey | string | — | Prefix that keeps the ids of two groups apart. Defaults to `""`. |
| locale | string | — |
Reading the selected locale
useTranslatable, TranslatableContextProvider and useTranslatableContext
are the same ones TranslatableInputs
documents. A custom selector reads selectedLocale and calls selectLocale
from useTranslatableContext().
Vue
@chelone/vue ships the same components with these differences:
- The
#selectorslot replaces the default locale selector, in place of theselectorprop. - The tabs are native
<button role="tab">elements, not Radix tabs. provideTranslatable(translatable)takes the place of<TranslatableContextProvider>.- While a
<Show>record is still loading, the component still renders the tab strip, over empty panels, instead of nothing. It throws only when there is no record context at all.
<script setup lang="ts">
import { TextField, TranslatableFields } from "@chelone/vue";
</script>
<template>
<TranslatableFields :locales="['en', 'fr']">
<TextField source="title" />
</TranslatableFields>
</template>