ESC
Type to search...
S
Soli Docs

I18n Functions

Internationalization with translations, pluralization, and locale-aware formatting.

Locale Management

I18n.locale()

Get the current locale.

Returns

String - The current locale code (e.g., "en", "fr", "de")
println(I18n.locale())  # "en"
I18n.set_locale(locale)

Set the current locale.

Parameters

locale : String - The locale code to set
I18n.set_locale("fr")
I18n.set_locale("de")

Translations

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

Translate a key to the specified locale.

Parameters

key : String - The translation key
locale : String? - Optional locale (uses current if not specified)
translations : Hash? - Optional translations hash
let translations = {
    "en.greeting": "Hello",
    "fr.greeting": "Bonjour",
    "de.greeting": "Hallo",
    "en.welcome": "Welcome, {name}!"
}

I18n.translate("greeting", "fr", translations)  # "Bonjour"
I18n.translate("greeting", "en", translations)  # "Hello"
I18n.plural(key, count, locale?, translations?)

Handle pluralization based on count.

Plural Forms

Use suffixes: _zero, _one, _other
let translations = {
    "en.items_zero": "No items",
    "en.items_one": "1 item",
    "en.items_other": "{count} items"
}

I18n.plural("items", 0, "en", translations)   # "No items"
I18n.plural("items", 1, "en", translations)   # "1 item"
I18n.plural("items", 5, "en", translations)   # "5 items"

Loading from External Files

Load translations from external JSON files at application startup. This is typically done in app.sl to make translations available globally.

JSON File Format

{
    "app": {
        "title": "My Application",
        "welcome": "Welcome!"
    },
    "nav": {
        "home": "Home",
        "about": "About"
    },
    "common": {
        "save": "Save",
        "cancel": "Cancel"
    }
}

Helper Functions

Create a helper to load translations from JSON files. This flattens nested JSON into dot-notation keys.

let i18n_translations = {};

def flatten_dict(dict, prefix) -> Hash
    let result = {};
    for (pair in entries(dict)) {
        let key = pair[0];
        let value = pair[1];
        let full_key = prefix + "." + key;
        if (type(value) == "Hash") {
            let nested = flatten_dict(value, full_key);
            for (np in entries(nested)) {
                result[np[0]] = np[1];
            }
        } else {
            result[full_key] = value;
        }
    }
    return result;
end

def i18n_load_translations(locale, dict)
    let flat = flatten_dict(dict, locale);
    for (pair in entries(flat)) {
        i18n_translations[pair[0]] = pair[1];
    }
end

Loading in app.sl

Load all translation files at application startup. They'll be available globally.

# Load translation files from locales/ directory
let en_data = json_parse(slurp("locales/en.json"));
let fr_data = json_parse(slurp("locales/fr.json"));
let de_data = json_parse(slurp("locales/de.json"));

i18n_load_translations("en", en_data);
i18n_load_translations("fr", fr_data);
i18n_load_translations("de", de_data);

# Set default locale
I18n.set_locale("en");

# Define routes
http_server_get("/", "home#index");
http_server_listen(3000);

Using Translations in Controllers

Once loaded in app.sl, use translations anywhere in your controllers.

def home_index(req)
    let welcome = I18n.translate("app.welcome", null, i18n_translations);
    let home_link = I18n.translate("nav.home", null, i18n_translations);
    
    return render("home/index", {
        "welcome": welcome,
        "nav_home": home_link
    });
end

Locale-Aware Formatting

I18n.format_number(number, locale?)

Format a number according to locale conventions.

I18n.format_number(1234.56, "en")  # "1,234.56"
I18n.format_number(1234.56, "fr")  # "1 234,56"
I18n.format_number(1234.56, "de")  # "1.234,56"
I18n.format_currency(amount, currency, locale?)

Format a currency amount.

Parameters

amount : Float - The amount
currency : String - Currency code (USD, EUR, etc.)
locale : String? - Optional locale
I18n.format_currency(1234.56, "USD", "en")  # "$1,234.56"
I18n.format_currency(1234.56, "EUR", "de")  # "1.234,56 €"
I18n.format_currency(1234.56, "GBP", "en")  # "£1,234.56"
I18n.format_date(timestamp, locale?)

Format a date according to locale conventions.

let ts = __datetime_parse("2024-01-15T10:30:00Z")

I18n.format_date(ts, "en")  # "01/15/2024"
I18n.format_date(ts, "fr")  # "15/01/2024"
I18n.format_date(ts, "de")  # "15.01.2024"

Complete Example

# Define translations
let translations = {
    "en.welcome": "Welcome!",
    "en.cart_items_zero": "Your cart is empty",
    "en.cart_items_one": "You have 1 item in your cart",
    "en.cart_items_other": "You have {count} items in your cart",
    "en.total": "Total: {amount}",

    "fr.welcome": "Bienvenue!",
    "fr.cart_items_zero": "Votre panier est vide",
    "fr.cart_items_one": "Vous avez 1 article",
    "fr.cart_items_other": "Vous avez {count} articles",
    "fr.total": "Total: {amount}"
}

# Set locale based on user preference
I18n.set_locale(user["preferred_locale"] ?? "en")

# Use translations
let welcome = I18n.translate("welcome", null, translations)
let cart_msg = I18n.plural("cart_items", cart_count, null, translations)
let total = I18n.format_currency(cart_total, "USD")