Localization
Form, Please has no locale setting. Each part of the form gets its text from a different source:
- Field labels and other definition text come from your definition. Read the
locale from the runtime
context. - Validation messages come from the schema library. Configure its messages.
- Array action labels and the file button label come from the slots and
controls of the form kit. Give the kit an
i18nobject.
Translate labels with context
Put the locale in the kit context. A label function gets the context in its
second argument. When you give useForm a new context object, Form, Please
resolves the labels again. Memoize the object, so that it changes only when the
locale changes.
type Locale = "en" | "fr"
type LocaleContext = {
readonly locale: Locale
}
const labels = {
en: { email: "Email", newsletter: "Send product news" },
fr: { email: "E-mail", newsletter: "Recevoir les nouveautés" },
} as const
const signupSchema = z.object({
email: z.string(),
newsletter: z.boolean(),
})
const localeKit = nativeFormKit.forContext<LocaleContext>()
const signupDefinition = localeKit.defineForm(signupSchema, (ui) => [
ui.field("email", {
control: "text",
label: (_values, { context }) => labels[context.locale].email,
}),
ui.field("newsletter", {
control: "checkbox",
label: (_values, { context }) => labels[context.locale].newsletter,
}),
])
function SignupForm({ locale }: { readonly locale: Locale }) {
const context = useMemo(() => ({ locale }), [locale])
const form = localeKit.useForm(signupDefinition, {
defaultValues: { email: "", newsletter: false },
context,
})
return <localeKit.AutoForm form={form} />
}A custom control gets the same context in its props, so it can read
context.locale. Read Resolver values for the
arguments of property functions.
Translate validation messages
Form, Please displays the messages that the Standard Schema returns. Configure the schema library once, before form validation runs. Do not configure it during a component render, because the configuration is global.
A message that you give to one schema or one check has priority over the global messages.
Zod
Load a Zod locale with z.config(). Add customError to replace the message of
one issue type. Return undefined to use the locale message.
z.config(z.locales.fr())
z.config({
customError: (issue) => {
if (issue.code === "too_small" && issue.origin === "string") {
return `Saisissez au moins ${issue.minimum} caractères`
}
return undefined
},
})Valibot
Set the language with setGlobalConfig. Then set the messages for that
language with setGlobalMessage and setSpecificMessage.
v.setGlobalConfig({ lang: "fr" })
v.setGlobalMessage("Valeur non valide", "fr")
v.setSpecificMessage(
v.minLength,
(issue) => `Saisissez au moins ${issue.requirement} caractères`,
"fr",
)Yup
Call setLocale before you create the schemas. Yup reads the default message
when a schema method runs, so a schema created earlier keeps the old message.
setLocale({
mixed: { required: "Ce champ est obligatoire" },
string: { min: ({ min }) => `Saisissez au moins ${min} caractères` },
})Translate the form kit labels
The default slots and the Material UI preset use different i18n key names
for the same actions. Their callbacks also get different arguments.
| Label | createDefaultSlots key | createMuiFormKit key | English default |
|---|---|---|---|
| Append an array item | arrayAdd | addItem | Add item |
| Remove an array item | arrayRemove | removeItem | Remove item 1 |
| Move an array item up | arrayMoveUp | moveItemUp | Move item 1 up |
| Move an array item down | arrayMoveDown | moveItemDown | Move item 1 down |
| Choose a file | — | chooseFile | Choose file |
- A
createDefaultSlotsvalue is a string or a callback. ThearrayAddcallback gets the arraylabel. The item callbacks get the zero-basedindexand the one-basedposition. - A
createMuiFormKitvalue for an item action is a callback that gets the one-based position as a number.addItemandchooseFileare strings. - All keys are optional. A missing key keeps the English default.
Default slots
nativeFormKit uses the English default slots. To translate them, create the
kit with createFormKit, createNativeControls, and createDefaultSlots.
const frenchSlots = createDefaultSlots({
i18n: {
arrayAdd: ({ label }) => {
if (typeof label === "string") return `Ajouter : ${label}`
return "Ajouter un élément"
},
arrayRemove: ({ position }) => `Supprimer l'élément ${position}`,
arrayMoveUp: ({ position }) => `Monter l'élément ${position}`,
arrayMoveDown: ({ position }) => `Descendre l'élément ${position}`,
},
})
const frenchNativeKit = createFormKit({
controls: createNativeControls(),
slots: frenchSlots,
})Read Default slots for the i18n types.
Material UI preset
Give createMuiFormKit an i18n object.
const frenchMuiKit = createMuiFormKit({
i18n: {
addItem: "Ajouter un élément",
removeItem: (position) => `Supprimer l'élément ${position}`,
moveItemUp: (position) => `Monter l'élément ${position}`,
moveItemDown: (position) => `Descendre l'élément ${position}`,
chooseFile: "Choisir un fichier",
},
})Read Material UI preset for the preset options.