ESC
Type to search...
S
Soli Docs

Internationalization

Build multilingual applications with ease. Soli provides built-in i18n support for translations, number formatting, currency, dates, and pluralization.

Global by Design

The I18n class provides everything you need to localize your application: string translations with interpolation, pluralization rules, locale-aware number and currency formatting, and date localization.

Setting the Locale

Use I18n.locale() to get the current locale and I18n.set_locale() to change it.

Locale Management
// Get the current locale (defaults to "en")
let current = I18n.locale();
print(current);  // "en"

// Set locale to French
I18n.set_locale("fr");
print(I18n.locale());  // "fr"

// Set locale to German
I18n.set_locale("de");

Basic Translation

Translate strings using I18n.translate(key, locale?, translations?). The function looks up the key in your translations hash.

String Translation
// Define translations
let translations = {
    "en.greeting" => "Hello",
    "fr.greeting" => "Bonjour",
    "de.greeting" => "Hallo",
    "es.greeting" => "Hola",
    "en.welcome" => "Welcome to our app!",
    "fr.welcome" => "Bienvenue dans notre application!"
};

// Translate using current locale
I18n.set_locale("fr");
let msg = I18n.translate("greeting", null, translations);
print(msg);  // "Bonjour"

// Translate with explicit locale
let hello = I18n.translate("greeting", "de", translations);
print(hello);  // "Hallo"

// Falls back to key if not found
let missing = I18n.translate("unknown_key", null, translations);
print(missing);  // "unknown_key"

Pluralization

Handle singular and plural forms with I18n.plural(key, n, locale?, translations?). Use _zero suffix for zero, _one for singular, and _other for plural.

Pluralization
let translations = {
    "en.item_zero" => "No items",
    "en.item_one" => "1 item",
    "en.item_other" => "{count} items",
    "fr.item_zero" => "Aucun article",
    "fr.item_one" => "1 article",
    "fr.item_other" => "{count} articles"
};

I18n.set_locale("en");

// Zero form
let none = I18n.plural("item", 0, null, translations);
print(none);  // "No items"

// Singular form
let single = I18n.plural("item", 1, null, translations);
print(single);  // "1 item"

// Plural form
let multiple = I18n.plural("item", 5, null, translations);
print(multiple);  // "{count} items"

// French plural
let fr_plural = I18n.plural("item", 3, "fr", translations);
print(fr_plural);  // "{count} articles"

Number Formatting

Format numbers according to locale conventions using I18n.format_number(n, locale?).

Number Formatting
let value = 1234.56;

// English format (dot as decimal separator)
let en_num = I18n.format_number(value, "en");
print(en_num);  // "1234.56"

// French format (comma as decimal separator)
let fr_num = I18n.format_number(value, "fr");
print(fr_num);  // "1234,56"

// German format
let de_num = I18n.format_number(value, "de");
print(de_num);  // "1234,56"

Currency Formatting

Format monetary amounts with I18n.format_currency(amount, currency, locale?). Supports common currency codes.

Currency Formatting
let price = 1999.99;

// US Dollars
let usd = I18n.format_currency(price, "USD", "en");
print(usd);  // "$1,999.99"

// Euros with French locale
let eur = I18n.format_currency(price, "EUR", "fr");
print(eur);  // "€1.999,99"

// British Pounds
let gbp = I18n.format_currency(price, "GBP", "en");
print(gbp);  // "£1,999.99"

// Japanese Yen
let jpy = I18n.format_currency(2500, "JPY", "en");
print(jpy);  // "¥2,500"

Date Formatting

Format dates using I18n.format_date(timestamp, locale?). Different locales use different date formats.

Date Formatting
// Unix timestamp for January 15, 2026
let timestamp = 1768521600;

// US format: MM/DD/YYYY
let us_date = I18n.format_date(timestamp, "en");
print(us_date);  // "01/15/2026"

// French format: DD/MM/YYYY
let fr_date = I18n.format_date(timestamp, "fr");
print(fr_date);  // "15/01/2026"

// German format: DD.MM.YYYY
let de_date = I18n.format_date(timestamp, "de");
print(de_date);  // "15.01.2026"

// ISO format (default for other locales)
let iso_date = I18n.format_date(timestamp, "ja");
print(iso_date);  // "2026-01-15"

Translation Files

Organize translations in JSON files and load them at startup.

config/locales/en.json
{
    "en.app_name": "My Application",
    "en.nav.home": "Home",
    "en.nav.about": "About Us",
    "en.nav.contact": "Contact",
    "en.messages.success": "Operation completed successfully!",
    "en.messages.error": "An error occurred. Please try again.",
    "en.user.greeting": "Hello, {name}!",
    "en.items_one": "You have 1 item",
    "en.items_other": "You have {count} items"
}
Loading Translations
// Load translations from JSON file
let en_json = file_read("config/locales/en.json");
let en_translations = json_decode(en_json);

let fr_json = file_read("config/locales/fr.json");
let fr_translations = json_decode(fr_json);

// Merge translations
let all_translations = hash_merge(en_translations, fr_translations);

// Use in your application
let greeting = I18n.translate("nav.home", "en", all_translations);
print(greeting);  // "Home"

Supported Locales

The I18n class provides built-in formatting support for these locales:

Locale Code Language Number Format Date Format
en English 1,234.56 MM/DD/YYYY
fr French 1.234,56 DD/MM/YYYY
de German 1.234,56 DD.MM.YYYY
es Spanish 1.234,56 YYYY-MM-DD
it Italian 1.234,56 YYYY-MM-DD

Method Reference

I18n.locale()

Returns the current locale string. Defaults to "en" if not set.

I18n.set_locale(locale)

Sets the current locale. Returns the locale string.

I18n.translate(key, locale?, translations?)

Translates a key. Uses current locale if not specified. Falls back to the key itself if no translation found.

I18n.plural(key, n, locale?, translations?)

Returns zero (_zero), singular (_one), or plural (_other) form based on count.

I18n.format_number(n, locale?)

Formats a number according to locale conventions (decimal separator).

I18n.format_currency(amount, currency, locale?)

Formats a monetary amount with currency symbol. Supports USD, EUR, GBP, JPY.

I18n.format_date(timestamp, locale?)

Formats a Unix timestamp as a date string according to locale conventions.

Best Practice

Set the locale early in your request lifecycle, typically in a before filter or middleware. You can detect the user's preferred language from the Accept-Language header or from user preferences stored in your database.