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]
            end
        else
            result[full_key] = value
        end
    end
    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
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")