Skip to content

Internationalization (i18n.star)

Pixlet ships with a small internationalization helper that lets you format strings for a specific locale and swap in translations at runtime. The module keeps your source strings in Starlark, while translation files live next to the applet in a locales directory.

Creating locale files

  1. Create a locales/ directory in the root of your applet.
  2. Add one JSON file per locale using a BCP 47 tag in the filename. Dashes and underscores are both accepted (en-US.json and en_US.json load the same locale).
  3. Each file contains a flat object that maps the message keys you pass to tr to their translations. % verbs follow the normal Go fmt.Sprintf rules, so your translations must keep the same verbs. If the word order changes in a translation, use positional verbs such as %[2]s or %[1]d to pull arguments out of order.

When Pixlet loads an applet it scans locales/*.json, parses each file, and adds the translations to a message catalog. Locales that are missing or do not define a string simply fall back to the original source string.

Example Locale: locales/es.json

{
  "hello_user": "Hola, %s",
  "unread_count": "%d mensajes sin leer"
}

Translating strings in Starlark

Load i18n.star and use the tr helper wherever you need localized text. Pass the message key first, followed by any formatting arguments:

load("i18n.star", "tr")
load("render.star", "render")

def main(config):
    user = config.get("user", "Tronbyt")
    return render.Root(
        child = render.Text(
            content = tr("hello_user", user),
        ),
    )

You can use any valid fmt.Sprintf verbs (%s, %d, %0.1f, etc). Numbers are formatted using the active locale, so tr("unread_count", count) will render digit grouping appropriate for the selected language.

Choosing a locale at runtime

The pixlet CLI and API let you tell the runtime which locale to use:

  • pixlet render path/to/app.star --locale es
  • pixlet serve path/to/app --locale es
  • The /api/render endpoint accepts a locale field in the JSON body.

When no locale is provided Pixlet defaults to English. Any missing translation falls back to the source string, so you can safely call tr() even before a string has been translated.

Example

examples/i18n/main.star contains a minimal end-to-end example that loads i18n.star, defines translations in locales/es.json, and renders localized output with pixlet render examples/i18n --locale es.

Once a locale is selected it applies to the entire render. Built-in modules such as humanize.star automatically pick up the same locale information, so date and number formatting stay in sync with your translations.