# Internationalization (i18n) & Localization: Translating UI Bakery Apps

In this example, we will add the possibility to switch to *German* in the app. Check out the instruction below:point\_down:

{% hint style="success" %}
The feature allows you to translate not only the app content but also text that is not user controlled, such as interaction, hints, selection, pagination, messages, and validation.
{% endhint %}

1. Navigate to the **App triggers** section in the right side panel and create a new action for the *On App Load* trigger.
2. Select the **JavaScript Code** type and specify the following code to initialize all the translations using `i18n.init({...})`:

{% hint style="warning" %}
The **default interpolation** in UI Bakery is `{ prefix: '{', suffix: '}' }`. Therefore, you should use single curly braces to insert your values into the string.
{% endhint %}

```javascript
i18n.init({
  lng: app.locale,
  ns: ['translation', 'uibakery'],
  defaultNs: ['translation'],
  resources: {
    en: {
      translation: {
        english: 'English',
        german: 'German',
        welcome: 'Welcome!',
        total: 'There are {total} users in total',
      },
      uibakery: {
        interactions: {
          ok: 'OK',
          cancel: 'Cancel',
          edit: 'Edit',
          save: 'Save',
          upload: 'Upload',
          now: 'Now',
        },
        text: {
          ampm: 'Am/Pm',
          hours: 'Hr',
          minutes: 'Min',
          seconds: 'Sec',
        },
        hints: {
          add_new_row: 'Add new row',
          cancel_adding_row: 'Cancel adding row',
          cancel_edit: 'Cancel edit',
          cancel_editing_row: 'Cancel row edit',
          cancel_rows_edit: 'Cancel rows edit',
          cancel_row_addition: 'Cancel row addition',
          confirm_and_save_added_row: 'Confirm and save added row',
          confirm_and_save_edited_rows: 'Confirm and save edited rows',
          confirm_and_save_row_edit: 'Confirm and save row edit',
          delete_row: 'Delete row',
          download_data_as: 'Download data as CSV',
          edit_data: 'Edit data',
          edit_multiple_rows: 'Edit multiple rows (Bulk edit)',
          edit_row: 'Edit row',
          reload_data: 'Reload Data',
        },
        selection: {
          clear_selection: 'Clear selection',
          select_all: 'Select all',
          reset_all: 'Reset all',
          selected: 'selected',
        },
        pagination: {
          items: 'items',
          page: 'Page',
          of: 'of',
          show_items: 'Show {value} items',
        },
        messages: {
          no_data_to_display: 'No data to display',
          no_file_selected: 'No file selected',
          not_available: 'N/A',
        },
        validation: {
          this_field_is_required: 'This field is required',
          enter_valid_email_address: 'Enter a valid email address',
          please_match_requested_format: 'Please match the requested format',
          enter_valid_url: 'Enter a valid url',
          color_is_not_valid: 'Color is not valid',
          invalid_json: 'Invalid JSON',
          date_must_be_on_or_after: 'Date must be on or after {date}',
          date_must_be_on_or_before: 'Date must be on or before {date}',
          some_of_uploaded_files_are_larger_than: 'Some of uploaded files are larger than {size}Mb',
          uploaded_file_is_larger_than: 'Uploaded file is larger than {size}Mb',
          invalid_date_format: 'Invalid date: "{value}", date should be in "{dateFormat}" format',
          this_field_must_contain_between_characters: 'This field must contain between {min} and {max} characters',
          this_field_must_contain_at_least_characters: 'This field must contain at least {min} characters',
          this_field_must_be_less_than_or_equal_characters: 'This field must be less than or equal to {max} characters',
          this_field_must_be_between: 'This field must be between {min} and {max}',
          this_field_must_be_greater_than_or_equal: 'This field must be greater than or equal to {min}',
          this_field_must_be_less_than_or_equal: 'This field must be less than or equal to {max}',
          only_user_defined_mime_types_are_allowed: 'Only user-defined MIME types are allowed',
          only_expected_file_types_are_allowed: 'Only {expectedType} files are allowed',
          no_text_selected: 'No text selected',
          the_selected_text_is_already_annotated: 'The selected text is already annotated',
        },
      },
    },
    de: {
      translation: {
        english: 'Englisch',
        german: 'Deutsch',
        welcome: 'Willkommen!',
        total: 'Es gibt insgesamt {total} benutzer',
      },
      uibakery: {
        interactions: {
          ok: 'OK',
          cancel: 'Abbrechen',
          edit: 'Bearbeiten',
          save: 'Speichern',
          upload: 'Hochladen',
          now: 'Jetzt',
        },
        text: {
          ampm: 'Am/Pm',
          hours: 'Std.',
          minutes: 'Min.',
          seconds: 'Sek.',
        },
        hints: {
          add_new_row: 'Neue Zeile hinzufügen',
          cancel_adding_row: 'Zeilenhinzufügen abbrechen',
          cancel_edit: 'Bearbeiten abbrechen',
          cancel_editing_row: 'Zeilenbearbeitung abbrechen',
          cancel_rows_edit: 'Zeilenbearbeitung abbrechen',
          cancel_row_addition: 'Zeilenhinzufügen abbrechen',
          confirm_and_save_added_row: 'Hinzufügen der Zeile bestätigen und speichern',
          confirm_and_save_edited_rows: 'Bearbeitete Zeilen bestätigen und speichern',
          confirm_and_save_row_edit: 'Zeilenbearbeitung bestätigen und speichern',
          delete_row: 'Zeile löschen',
          download_data_as: 'Daten als CSV herunterladen',
          edit_data: 'Daten bearbeiten',
          edit_multiple_rows: 'Mehrere Zeilen bearbeiten (Massenbearbeitung)',
          edit_row: 'Zeile bearbeiten',
          reload_data: 'Daten neu laden',
        },
        selection: {
          clear_selection: 'Auswahl aufheben',
          select_all: 'Alle auswählen',
          reset_all: 'Alle zurücksetzen',
          selected: 'Ausgewählte',
        },
        pagination: {
          items: 'Elemente',
          page: 'Seite',
          of: 'von',
          show_items: '{value} Elemente anzeigen',
        },
        messages: {
          no_data_to_display: 'Keine Daten zum Anzeigen',
          no_file_selected: 'Keine Datei ausgewählt',
          not_available: 'N/A',
        },
        validation: {
          this_field_is_required: 'Dieses Feld ist ein Pflichtfeld',
          enter_valid_email_address: 'Geben Sie eine gültige E-Mail-Adresse ein',
          please_match_requested_format: 'Bitte beachten Sie das gewünschte Format',
          enter_valid_url: 'Geben Sie eine gültige URL ein',
          color_is_not_valid: 'Farbe ist ungültig',
          invalid_json: 'Ungültiges JSON',
          date_must_be_on_or_after: 'Datum muss am oder nach {date} liegen',
          date_must_be_on_or_before: 'Das Datum muss am oder vor {date} liegen',
          some_of_uploaded_files_are_larger_than: 'Einige der hochgeladenen Dateien sind größer als {size} MB',
          uploaded_file_is_larger_than: 'Die hochgeladene Datei ist größer als {size} MB',
          invalid_date_format: 'Ungültiges Datum: "{value}". Das Datum sollte im Format "{dateFormat}" angegeben werden',
          this_field_must_contain_between_characters: 'Dieses Feld muss zwischen {min} und {max} Zeichen enthalten',
          this_field_must_contain_at_least_characters: 'Dieses Feld muss mindestens {min} Zeichen enthalten',
          this_field_must_be_less_than_or_equal_characters: 'Dieses Feld muss kleiner oder gleich {max} Zeichen sein',
          this_field_must_be_between: 'Dieses Feld muss zwischen {min} und {max} liegen',
          this_field_must_be_greater_than_or_equal: 'Dieses Feld muss größer oder gleich {min} sein',
          this_field_must_be_less_than_or_equal: 'Dieses Feld muss kleiner oder gleich {max} sein',
          only_user_defined_mime_types_are_allowed: 'Nur benutzerdefinierte MIME-Typen sind zulässig',
          only_expected_file_types_are_allowed: 'Nur {expectedType}-Dateien sind zulässig',
          no_text_selected: 'Kein Text ausgewählt',
          the_selected_text_is_already_annotated: 'Der ausgewählte Text ist bereits kommentiert',
        },
      },
    },
  },
});
```

For a **Form**, for example, you may also want to add translation for the *Submit* button. Simply add this field to the code above (e.g.: `submit: 'Einreichen'`) and add `{{i18n.t('submit')}}` to the *Submit button text*'s value in the Form settings.

<figure><img src="https://837703843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUX6zPRMFFK0yrTghj7cY%2Fuploads%2FYjrqoMtcybZKFg67LPqQ%2FCleanShot%202025-04-01%20at%2016.08.53%402x-min.png?alt=media&#x26;token=e61a38b3-3bd5-4938-8b02-3973efb13a9d" alt=""><figcaption></figcaption></figure>

3. Add a **Select** component to the working area and add the languages you need to the *Options* field, for example:

```javascript
[
  {
    "value": "en",
    "title": {{i18n.t('english')}}
  },
  {
    "value": "de",
    "title": {{i18n.t('german')}}
  }
]
```

{% hint style="success" %}
`window.i18next.t` is now `i18n.t`.
{% endhint %}

4. In the component's *Value* field, specify `{{i18n.language}}`.
5. Next, navigate to the Select component's *Triggers* section and create a new action for the **On Change** trigger.
6. Select the **JavaScript Code** step and specify the following code:

```javascript
app.setLocale(data)
```

7. Finally, add translations anywhere you need to the text by using the `i18n.t` function.\
   In our example here, we've added translation to the *Heading* component:

`{{i18n.t('welcome')}}`

Done! Now when you select a different language in the Select component, your app will be translated automatically.

{% @arcade/embed flowId="knwlk5ydhQppnUsUQFfE" url="<https://app.arcade.software/share/knwlk5ydhQppnUsUQFfE>" %}

## Date, Time & Number localization

You can also localize Date, Time (including hours, minutes, and seconds), and Numeric formats. You can do this by selecting the *Application locale* in the App settings. English is the default option but you can adjust it to match your language needs.

<figure><img src="https://837703843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUX6zPRMFFK0yrTghj7cY%2Fuploads%2FG6sUEnrvY7ZfICJXl1nj%2FCleanShot%202025-07-21%20at%2011.44.53%402x-min.png?alt=media&#x26;token=dd59223e-be83-4e92-afc6-f3414e604b82" alt=""><figcaption></figcaption></figure>

Also, for such field types as Number, Currency & Percent, there's now the *Application default* option in the **Locale** field (View settings section). It matches the global App locale setting, and is selected by default.

<figure><img src="https://837703843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FUX6zPRMFFK0yrTghj7cY%2Fuploads%2FqDVLqD5Xgvnd1MjtcS7X%2FCleanShot%202025-07-21%20at%2012.21.07%402x-min.png?alt=media&#x26;token=fb4d6b3a-a3f2-49c7-bdb9-09d1783c39a1" alt=""><figcaption></figcaption></figure>
