Translating Forms

If a form has been set up, all elements will use the labels, placeholders and so forth as configured. To have the form translated depending on the current locale, you need to configure a package to load the translations from and add the translations as XLIFF files.

Configuration

The package to load the translations from is configured in the form preset being used. The simplest way to configure it is this:

Neos:
  Form:
    presets:
      default:
        formElementTypes:
          'Neos.Form:Base':
            renderingOptions:
              translationPackage: 'AcmeCom.SomePackage'

Of course it can be set in a custom preset in the same way.

The translation of validation error messages uses the Neos.Flow package by default, to avoid having to copy the validation errors message catalog to all packages used for form translation. If you want to adjust those error messages as well, copy ValidationErrors.xlf to your package and set the option validationErrorTranslationPackage to your package key.

XLIFF files

The XLIFF files follow the usual rules, the Main catalog is used. The Form package comes with the following catalog (Main.xlf):

<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file original="" product-name="Neos.Form" source-language="en" datatype="plaintext">
        <body>
            <trans-unit id="forms.navigation.previousPage" xml:space="preserve">
                <source>Previous page</source>
            </trans-unit>
            <trans-unit id="forms.navigation.nextPage" xml:space="preserve">
                <source>Next page</source>
            </trans-unit>
            <trans-unit id="forms.navigation.submit" xml:space="preserve">
                <source>Submit</source>
            </trans-unit>
        </body>
    </file>
</xliff>

It should be copied to make sure the three expected units are available and can then be amended by your own units.

For most reliable translations, the units should be given id properties based on the form configuration. The schema is as follows:

forms.navigation.nextPage
In multi-page forms this is used for the navigation.
forms.navigation.previousPage
In multi-page forms this is used for the navigation.
forms.navigation.submitButton
In forms this is used for the submit button.

Forms and sections can have their labels translated using this, where where {identifier} is the identifier of the page or section itself:

forms.pages.{identifier}.label
The label used for a form page.
forms.sections.{identifier}.label
The label used for a form section.

The actual elements of a form have their id constructed by appending one of the following to forms.elements.{identifier}., where {identifier} is the identifier of the form element itself:

label
The label for an element.
placeholder
The placeholder for an element, if applicable.
description
dkjsadhsajk
text
The text of a StaticText element.
confirmationLabel
Used in the PasswordWithConfirmation element.
passwordDescription
Used in the PasswordWithConfirmation element.

The labels of radio buttons and select field options can be translated using the following schema, where {identifier} is the identifier of the form element itself and value is the value assigned to the option:

forms.elements.{identifier}.options.{value}
Used to translate labels of radio buttons and select field entries.

Complete example

This is the example form used elsewhere in this documentation:

  • Contact Form (Form)
    • Page 01 (Page)
      • Name (Single-line Text)
      • Email (Single-line Text)
      • Message (Multi-line Text)

Assume it is configured like this using YAML:

type: 'Neos.Form:Form'
identifier: 'contact'
label: 'Contact form'
renderables:
  -
    type: 'Neos.Form:Page'
    identifier: 'page-one'
    renderables:
      -
        type: 'Neos.Form:SingleLineText'
        identifier: name
        label: 'Name'
        validators:
          - identifier: 'Neos.Flow:NotEmpty'
        properties:
          placeholder: 'Please enter your full name'
      -
        type: 'Neos.Form:SingleLineText'
        identifier: email
        label: 'Email'
        validators:
          - identifier: 'Neos.Flow:NotEmpty'
          - identifier: 'Neos.Flow:EmailAddress'
        properties:
          placeholder: 'Enter a valid email address'
      -
        type: 'Neos.Form:MultiLineText'
        identifier: message
        label: 'Message'
        validators:
          - identifier: 'Neos.Flow:NotEmpty'
        properties:
          placeholder: 'Enter your message here'

Note

You may leave out label and placeholder if you use id-based matching for the translation. Be aware though, that you will get empty labels and placeholders in case the translation fails or is not available.

The following XLIFF would allow to translate the form:

<?xml version="1.0" encoding="UTF-8"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
    <file original="" product-name="Neos.Form" source-language="en" datatype="plaintext">
        <body>
            <trans-unit id="forms.navigation.previousPage" xml:space="preserve">
                <source>Previous page</source>
            </trans-unit>
            <trans-unit id="forms.navigation.nextPage" xml:space="preserve">
                <source>Next page</source>
            </trans-unit>
            <trans-unit id="forms.navigation.submit" xml:space="preserve">
                <source>Submit</source>
            </trans-unit>

            <trans-unit id="forms.pages.page-one" xml:space="preserve">
                <source>Submit</source>
            </trans-unit>

            <trans-unit id="forms.elements.name.label" xml:space="preserve">
                <source>Name</source>
            </trans-unit>
            <trans-unit id="forms.elements.name.placeholder" xml:space="preserve">
                <source>Please enter your full name</source>
            </trans-unit>

            <trans-unit id="forms.elements.email.label" xml:space="preserve">
                <source>Email</source>
            </trans-unit>
            <trans-unit id="forms.elements.email.placeholder" xml:space="preserve">
                <source>Enter a valid email address</source>
            </trans-unit>

            <trans-unit id="forms.elements.message.label" xml:space="preserve">
                <source>Message</source>
            </trans-unit>
            <trans-unit id="forms.elements.message.placeholder" xml:space="preserve">
                <source>Enter your message here</source>
            </trans-unit>
        </body>
    </file>
</xliff>

Copy it to your target language and add the target-language attribute as well as the needed <target>…</target> entries.