i18n
Reactive icon

I18n

Stable version 1.1.3 (Compatible with OutSystems 11)
Uploaded
 on 30 Jul (11 hours ago)
 by 
0.0
 (0 ratings)
i18n

I18n

Documentation
1.1.0

1. Overview

I18n Library provides multi-language support for OutSystems Reactive Web and Mobile apps through client actions. Translations are loaded from JSON files at runtime — no redeployment needed to add or update languages.

How it works:

App starts → InitTranslation loads default JSON → Screen opens → LoadScreenResource loads screen JSON → Translate expressions render text

2. Prerequisites

ItemDetails
Module dependencyReference I18n_Lib in your application
JSON filesHosted under a /locales/ folder (app resources or CDN)

3. File Structure

/locales/
├── default/              ← shared keys (nav, footer, common)
│   ├── en-US.json
│   └── ar-SA.json
├── dashboard/            ← screen-specific keys
│   ├── en-US.json
│   └── ar-SA.json
├── profile/
│   ├── en-US.json
│   └── ar-SA.json
└── settings/
    ├── en-US.json
    └── ar-SA.json

Rule: The default/ folder is loaded automatically at app start. Screen folders are loaded on-demand.


4. Client Actions Reference

Client ActionWhere to CallPurpose
InitTranslationApplication OnReadyInitialize library, load default translations
LoadScreenResourceScreen OnReadyLoad screen-specific translations
TranslateExpressions (Function)Get translated text by key
SwitchLocaleLocale switcher buttonChange active language
SetConfigAnywhere (optional)Override config at runtime
GetConfigDebug/testingRead current config values

5. InitTranslation

Where: Application → OnReady (runs once on app load)

Input Parameters

ParameterTypeMandatoryDescription
BasePathText✅ YesURL to the /locales/ folder. Relative or absolute (CDN).
TranslationMapTranslationMapItem ListNoMaps screen names → JSON folder names
ResourceVersionTextNoCache-bust string (e.g., "v1.3"). Appended as ?t=v1.3
LocalesText ListNoLocale codes to preload. Empty = ["en-US"]

TranslationMapItem Structure

TranslationMapItem (Record)
├── Key   : Text    → OutSystems screen name (exact match)
└── Value : Text    → JSON folder name under basePath

How to Build

Step 1 — Create TranslationMap list:

// Assign → TranslationMapList
ListAppend(TranslationMapList, {Key: "Dashboard",  Value: "dashboard"})
ListAppend(TranslationMapList, {Key: "Profile",    Value: "profile"})
ListAppend(TranslationMapList, {Key: "Settings",   Value: "settings"})
ListAppend(TranslationMapList, {Key: "Transfers",  Value: "transfers"})

Step 2 — Create Locales list:

// Assign → LocalesList
ListAppend(LocalesList, "en-US")
ListAppend(LocalesList, "ar-SA")

Step 3 — Call InitTranslation:

InitTranslation(
    BasePath:         "/MyApp/locales/",
    TranslationMap:   TranslationMapList,
    ResourceVersion:  "v1.3", (optional)
    Locales:          LocalesList
)

What Happens

  1. Library initializes with config
  2. Fetches default/en-US.json and default/ar-SA.json
  3. Stores translations in memory
  4. Library is ready for loadForScreen() and t() calls

Timing Note

InitTranslation is async — it starts fetching but doesn't block the app. If a screen calls LoadScreenResource before init completes, the library auto-queues and executes after init resolves. No error, no timing issue.


6. LoadScreenResource

Where: Each Screen → OnReady event

Input Parameters

ParameterTypeMandatoryDescription
ScreenNameText✅ YesThe OutSystems screen name (must match a TranslationMap key)

Output Parameters

ParameterTypeDescription
IsLoadedBooleanTrue if translations loaded (including fallback). False only if default locale also failed.

How to Use

// Screen OnReady:
LoadScreenResource(ScreenName: "Dashboard")

// Then assign:
TranslationRevision = TranslationRevision + 1

Behaviour

ScenarioIsLoadedWhat Renders
en-US.json + ar-SA.json both foundTrueTranslated text
Only en-US.json found (ar-SA 404)Trueen-US text (fallback)
All files 404FalseDefaultValue from Translate
Screen not in TranslationMapTrueOnly default/ keys available

When Screen Name Is Not Mapped

If ScreenName doesn't exist in TranslationMap, no screen-specific JSON is loaded — but default/ translations are still available. This is not an error.


7. Translate (Expression)

Where: Any Expression widget — set Function = Yes

Input Parameters

ParameterTypeMandatoryDescription
KeyText✅ YesTranslation key (e.g., "dashboard.title")
DefaultValueTextNoFallback text if key not found in any locale
ArgsTextNoComma-separated values for interpolation

Output

ParameterTypeDescription
TranslatedTextTextThe resolved translation

Expression Formula

Translate(
    "dashboard.title",
    "Dashboard",
    ""
)

Important: Include CurrentLocale and TranslationRevision as trailing parameters. They aren't used by the function logic — they are ghost dependencies that force OutSystems to re-evaluate the expression when locale changes or translations load.

Args — Interpolation

JSON:

{ "welcome": "Hello, %{opt1}. You have %{opt2} notifications." }

Expression:

Translate("common.welcome", "Hello", "Gokula,5")

Output: "Hello, Gokula. You have 5 notifications."

Args Valueopt1opt2opt3
"Gokula"Gokula
"Gokula,5"Gokula5
"Gokula,5,New"Gokula5New
""(no interpolation)

Resolution Priority

1. Current locale (e.g., ar-SA)  → found? → return
2. Parent locale (e.g., ar)      → found? → return
3. Default locale (e.g., en-US)  → found? → return
4. Parent of default (e.g., en)  → found? → return
5. DefaultValue parameter        → return
6. Empty string ""               → return

8. SwitchLocale

Where: Language switcher button/dropdown OnClick

Input Parameters

ParameterTypeMandatoryDescription
LocaleText✅ YesTarget locale code (e.g., "ar-SA")

Full Switcher Flow (Button OnClick)

1. SwitchLocale(Locale: "ar-SA")
2. Assign → Client.CurrentLocale = "ar-SA"
3. LoadScreenResource(ScreenName: GetCurrentScreen())

9. SetConfig

Where: Anywhere at runtime (optional — for advanced use)

Input Parameters

ParameterTypeMandatoryDescription
BasePathTextNoOverride base URL
ResourceVersionTextNoOverride cache-bust string
LocalesTextNoComma-separated locale list
DefaultLocaleTextNoOverride default fallback locale
CacheStrategyTextNo"force-cache", "no-cache", "default"
EnableFallbackBooleanNoTrue/False

Rule: Empty String = Keep Current Value

SetConfig(
    BasePath:        "",          ← unchanged
    ResourceVersion: "v2.0",     ← updated
    Locales:         "",          ← unchanged
    DefaultLocale:   "",          ← unchanged
    CacheStrategy:   "no-cache", ← updated
    EnableFallback:  True         ← unchanged
)

When to Use

  • Switch CDN endpoint mid-session
  • Force cache refresh after deployment
  • Enable/disable fallback for testing

10. GetConfig

Where: Debug screens, developer tools

Output Parameters

ParameterTypeDescription
BasePathTextCurrent base path
ResourceVersionTextCurrent version string
LocalesTextComma-separated active locales
DefaultLocaleTextCurrent default locale
CacheStrategyTextCurrent cache strategy
EnableFallbackBooleanWhether fallback is active

Usage

GetConfig()
// Use outputs for debug display or conditional logic

11. Common Patterns

Pattern 1 — Simple Text

Translate("common.save", "Save", "")

Pattern 2 — Text With Variables

// JSON: "Last updated: %{opt1}"
Translate("dashboard.lastUpdated", "Last updated", FormatDateTime(Now(), "dd MMM yyyy"))

Pattern 3 — Multiple Args

// JSON: "%{opt1} — %{opt2} on %{opt3}"
Translate("dashboard.list.item", "", "John,Transfer,15 Jul")

Pattern 4 — Conditional Default

Translate("premium.feature", If(IsPremiumUser, "Unlock", "Upgrade to access"), "")

Pattern 5 — Inside a List/Table

// In a Table Records expression:
Translate("status." + GetRecordList.Current.Status, GetRecordList.Current.Status, "")

JSON structure:

{
    "status": {
        "active": "نشط",
        "inactive": "غير نشط",
        "pending": "قيد الانتظار"
    }
}

Pattern 6 — Dynamic Screen Name

// Reusable across screens:
LoadScreenResource(ScreenName: GetCurrentScreenName())

12. JSON File Format

Rule: Use ONE Format Per File

✅ Pure Flat✅ Pure Nested❌ Mixed (Error)
All values are stringsObjects contain objectsNested object with dot-in-key

✅ Pure Flat Example

{
    "dashboard.title": "Dashboard",
    "dashboard.subtitle": "Your overview",
    "dashboard.summary.total": "Total",
    "dashboard.alerts.empty": "No active alerts."
}

✅ Pure Nested Example

{
    "dashboard": {
        "title": "Dashboard",
        "subtitle": "Your overview",
        "summary": {
            "total": "Total"
        },
        "alerts": {
            "empty": "No active alerts."
        }
    }
}

❌ This Will Throw Error

{
    "dashboard": {
        "title": "Dashboard",
        "summary.total": "Total"
    }
}

Error: [I18n_Lib] Invalid JSON structure at key: "dashboard.summary.total". Use either pure flat or pure nested format.


13. Troubleshooting

Error: "Invalid or missing I18n instance"

Cause: LoadScreenResource called before InitTranslation resolved.
Fix: Already handled in v1.3.0+ — the library auto-queues. If you still see this error, ensure InitTranslation is in Application OnReady (not Screen OnReady).


Expressions show DefaultValue, not translation

Check:

  1. Is CurrentLocale included in the Translate expression? (ghost dependency)
  2. Is TranslationRevision included in the Translate expression? (ghost dependency)
  3. Is TranslationRevision incremented after LoadScreenResource?
  4. Is the screen name in TranslationMap?
  5. Does the JSON file exist at the expected URL?

Locale switched but text didn't change

Check:

  1. Did you call LoadScreenResource after SwitchLocale?
  2. Did you increment TranslationRevision?
  3. Does the JSON file exist for the new locale?

RTL not flipping

Check:

  1. Did you set dir attribute on <html> after switch?
  2. Is the locale in the rtlLocales list? (default: ar-SA, ar-EG, he-IL, ur-PK, fa-IR)
  3. Are you using logical CSS properties or [dir="rtl"] selectors?

Console: 404 for some locale files

This is normal. If you have 5 locales configured but only 2 JSON files for a screen, the missing ones 404 silently. The fallback locale (en-US) is used instead.


Translation shows [missing "en-US.some.key" translation]

Cause: Key doesn't exist in any loaded JSON file.
Fix:

  1. Check spelling of key in JSON file
  2. Check that the correct module JSON is loaded for this screen
  3. Add a DefaultValue to the Translate call as safety net