OutSystems ships a multilingual feature, but it bakes every translation into the module at publish time — add a language or fix a typo and you redeploy. I wanted translations that live in JSON files and load at runtime, so anyone can drop in fr-FR.json and the app picks it up without a rebuild. That's what the I18n component on the Forge does.

It's about 1.7 KB of core JavaScript. Translation JSON loads lazily, per screen. Missing keys walk a fallback chain (ar-SAaren-US) so the UI never renders blank. RTL flips automatically — including for ur-PK, he-IL, and fa-IR, which OutSystems does not treat as right-to-left on its own. And it re-renders your expressions on locale change without you wiring up a client variable. Here's the whole path from Forge to a working multilingual screen.

1. Find it on the Forge

Search the Forge for i18n. It's the component by Gokula Kannan P — the one described as lightweight runtime i18n with lazy per-screen JSON.

Forge search results for i18n

2. Download and install in Service Studio

Open the listing and hit Try now, or Download to install it into your environment. The current stable version is 1.1.8, compatible with OutSystems 11 Reactive.

I18n Forge listing page

3. Reference the actions you need

In your app module, open Manage Dependencies, select I18n_Lib, and check the public elements you'll use. Three actions are mandatory:

  • InitTranslation — one-time setup at app start
  • Translate — the expression that returns translated text
  • SwitchLocale — changes the active language

You'll usually also take LoadScreenResource (lazy per-screen loading), GetLocale, the TranslationMapItem structure, and the I18nLib script.

Manage Dependencies — selecting I18n_Lib actions

4. Initialize on Application OnReady

Call InitTranslation once, in the application's OnApplicationReady. Point BasePath at your locales folder, list the locales you support, and map screens to their JSON folders with TranslationMap.

InitTranslation configured in OnApplicationReady

In the demo that's BasePath = "/I18nDemo/locales/", a TranslationMap entry of home → dashboard, and Locales of en-US, ar-SA, fr-FR, ur-PK, zh-CN. ResourceVersion is an optional cache-buster you bump on deploy; DefaultLocale and CacheStrategy fall back to sensible defaults.

The JSON sits under BasePath like this:

CODE
/I18nDemo/locales/
  default/        (loaded at app start)
    en-US.json
    ar-SA.json
  dashboard/      (loaded per screen)
    en-US.json
    ar-SA.json

Each file is flat or nested JSON, with %{opt1} placeholders for interpolation:

json
{ "welcome": "Welcome, %{opt1}", "notifications": "You have %{opt1} notifications." }

You only ship files for locales you actually translated — a missing fr-FR.json 404s silently and falls back.

5. Translate text with an expression

Anywhere you render text, use a Translate expression (set Function = Yes):

CODE
Translate("home.welcome", "Welcome", UserName)

Key, then a DefaultValue shown if the key is missing, then comma-separated Args that fill %{opt1}, %{opt2}, and so on. There is no revision variable and no ghost dependency to pass — the component re-renders these expressions when a screen's JSON finishes loading or the locale changes. On first paint you briefly see the DefaultValue, then it swaps to the translation.

6. Switch language with SwitchLocale

Wire a language button to a client action that calls SwitchLocale, passing the target locale as its input:

CODE
SwitchLocale(Locale: "ar-SA")

SwitchLocale action with Locale input

That one call sets the active locale, applies text direction, and re-renders the screen. Nothing else to do — no manual Assign, no direction toggling in your own JavaScript.

See it live

There's a running demo with en-US, ar-SA, ur-PK, fr-FR, and zh-CN:

https://developergeekay.outsystemscloud.com/I18nDemo/

English renders left-to-right:

Demo screen in English, left-to-right

Switch to Arabic and the entire layout mirrors to right-to-left — navigation, buttons, and text:

Demo screen in Arabic, right-to-left

That's the full loop: install from Forge, reference three actions, init once, translate with an expression, switch with one call. After that, translations are just JSON files — add a language by adding a folder, no redeploy.