# 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>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.uibakery.io/how-tos/data/connect-external-js-library/internationalization-i18n-and-localization-translating-ui-bakery-apps.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
