---
title: "Languages and localization"
description: "Translate your form's copy and override every built-in renderer string."
group: "Customize"
order: 4
type: "feature"
keywords:
  - "localization"
  - "translation"
  - "strings"
  - "language"
updated: "2026-07-14"
---

Localizing a Fillo form is two things: translated copy in the schema, plus a `strings` override for everything the built-in renderer says.

## In the dashboard

Translate the form title, description, page titles, field labels, option labels, help text, and completion copy directly in the editor. These strings live in the schema — they aren't translated automatically.

There's no per-form locale selector, translation table, or automatic language detection in the dashboard today. One published schema holds one set of authored labels.

## In code

Pass translated schema copy, then override the renderer chrome and field messages with `strings`:

```tsx
<FilloForm
  form={germanContactForm}
  client={client}
  strings={{
    back: "Zurück",
    next: "Weiter",
    submit: "Absenden",
    submitting: "Wird gesendet...",
    optional: " (optional)",
    required: "Dieses Feld ist erforderlich",
    requiredForField: (field) =>
      field.kind === "file_upload"
        ? "Fügen Sie eine Datei hinzu"
        : "Geben Sie Ihre Antwort ein",
    successTitle: "Danke!",
    successMessage: "Ihre Antwort wurde gespeichert.",
    uploadRetry: "Erneut versuchen",
  }}
/>
```

The `FilloRendererStrings` type covers navigation, submission, error, resume, duplicate-response, Other-option, dropdown, and upload copy. Upload strings can be functions — they receive the count or file-size limit so your translation can place it wherever the grammar needs it.

Required errors are field-aware by default (`Add a file`, `Enter an email address`, and so on). `requiredForField` receives the complete field, so a translation can choose its grammar from the kind, label, or other schema details. Existing integrations can keep overriding only `required`; that deliberately switches every required error back to the same generic translated message.

## Pick the language in your app

If your product already knows the locale, pick the matching schema and strings before rendering. Give each language its own stable form handle when its labels need to be edited and reported on independently. A single code form works only when your app owns all translation selection and downstream teams can read the shared field IDs.

Headless layouts can render all text themselves, but core validation still returns a small set of raw messages. The React renderer maps the required-field sentinel through `strings.requiredForField`, with `strings.required` as the generic fallback; custom components have to localize their own richer errors.

## Related

- [Styling](/docs/styling): Look up the full renderer string and appearance contracts.
- [Code-defined forms](/docs/authoring): Keep translated labels beside stable field IDs.
- [Custom UI](/docs/custom-ui): Own every visible string in a headless layout.
