Frontend documentation

The ‘frontend’ is an ambiguous concept in the context of Open Forms as a combination of software projects and associated code repositories. So, first, let’s clear this up.

  • The Javascript SDK is responsible for the form rendering and interacting with the backend API.

  • The design tokens package contains the design token definitions/values for the (default) theme. It is used by both the SDK and Django backend for consistency in the UI/theme.

  • The formio builder package is used by the Django backend, as part of the form designer user interface.

  • The formio renderer package will replace formiojs/react-formio as the library used by the SDK.

So, this means we can identify the following first party repositories:

  • open-formulieren/open-forms (backend)

  • open-formulieren/open-forms-sdk (SDK)

Which are supported by the following second party repositories:

  • open-formulieren/design-tokens

  • open-formulieren/formio-builder

  • open-formulieren/formio-renderer

Managing translations

We standardize using FormatJS to manage frontend translations across all projects and repositories. For React projects, this manifests as using the react-intl library. See Internationalization (i18n) for day-to-day programming usage.

This section dives deeper in the entire toolchain and conventions to make it all work together without too much friction.

Responsibilities

All user-facing literals should support localization in a translator-friendly format. This means that you should not break up literals in individually translatable blocks, but instead treat them as an atomic unit. The reasoning for this is that different locales often have different sentence structures.

Libraries also need to declare their messages using FormattedMessage, intl.formatMessage or equivalent constructs. Additionally, each library is responsible for extracting its messages so that downstream libraries and projects can incorporate them. They must distribute these message catalogs as part of the NPM package.

Projects are responsible for including the translations of libraries they use in the final message catalog. Using the above library convention, this means that the FormatJS CLI compile command should include the node_modules/@open-formulieren/*/i18n/message/{locale}.json glob path.

Message extraction and distribution

Note

The https://github.com/open-formulieren/formio-builder repository acts as the reference for the best practices here.

Libraries must provide the necessary shell scripts to correctly extract messages:

  • bin/makemessages.sh: script to extract messages from code for all supported locales

  • bin/find_untranslated_messages.py: script to assist in finding untranslated messages

  • npm run compilemessages: optional but recommended - script to compile the messages for react-intl

The convention for libraries is to distribute the (uncompiled) messages in the NPM package. The location must be i18n/messages/{locale}.json. At the minimum, the en and nl locales must be supported.

Additionally, it’s highly recommended to set up message compilation and use the react-intl storybook addon to test and verify translations in isolation.

Example package layout:

.
├─┬ i18n
│ ├─┬ compiled
│ │ ├── en.json
│ │ └── nl.json
│ └─┬ messages
│   ├── en.json
│   └── nl.json
└─┬ lib
  ├── cjs
  └── esm

It’s recommended that projects follow the same structure as libraries, but it’s not required to change existing i18n structures.

Compiling the message catalogs

Projects (backend, SDK) are able to compile in the messages from libraries when:

  • the messages are distributed in the package

  • the messages are in a predictable location (see convention above)

This is easiest achieved through a helper shell script, bin/compilemessages_js.sh.

For reference, the backend script:

#!/bin/bash
#
# Usage, from the root of the repository:
#
#   ./bin/compilemessages_js.sh
#

SUPPORTED_LOCALES=(
  en
  nl
)

for locale in "${SUPPORTED_LOCALES[@]}"; do
  echo "Compiling messages for locale '$locale'"
  npm run compilemessages -- \
    --ast \
    --out-file "src/openforms/js/compiled-lang/$locale.json" \
    "src/openforms/js/lang/$locale.json" \
    "node_modules/@open-formulieren/*/i18n/messages/$locale.json"
done

This script can handle current and future NPM packages published in the @open-formulieren namespace that comply with the package layout conventions.