Skip to content

Internationalization Examples

Choose a language to see complete messages and controls translated, then compare application defaults with a component override.

Try translated components

Select a language to translate the empty-state message, file picker, pagination, and copy feedback. The first preview follows your selection; the comparisons below keep their own settings.

Your selected language

Nothing here yet

Items will appear here when they are available.

or drag and drop here

Page 3 of 5

Request preview
message := "Hello from Goshtoso"

Portuguese application defaults

A renderer configured with Portuguese expressions supplies this empty state’s title and description.

Ainda não há nada aqui

Os itens aparecerão aqui quando estiverem disponíveis.

Spanish component override

This empty state supplies its own Spanish expressions. Its sibling below keeps the default English text.

Todavía no hay nada aquí

Los elementos aparecerán aquí cuando estén disponibles.

English sibling

Nothing here yet

Items will appear here when they are available.

Choose a language per request

The live previews load their expression sets from embedded YAML files at startup. The selector submits a new request with a language parameter. The handler chooses the matching expressions and renders the preview again. In your application, the language could come from a user profile or session instead. This shorter example translates the copy control; the live preview also supplies empty-state, file-picker, and pagination expressions.

Choose a language per request
func userExpressions(language string) expressions.Set {
    labels := map[string]expressions.CodeBlock{
        "en": {CopyLabel: "Copy", CopiedLabel: "Copied!", ErrorText: "Unable to copy"},
        "pt": {CopyLabel: "Copiar", CopiedLabel: "Copiado!", ErrorText: "Não foi possível copiar"},
        "es": {CopyLabel: "Copiar", CopiedLabel: "¡Copiado!", ErrorText: "No se pudo copiar"},
        "zh": {CopyLabel: "复制", CopiedLabel: "已复制!", ErrorText: "无法复制"},
        "de": {CopyLabel: "Kopieren", CopiedLabel: "Kopiert!", ErrorText: "Kopieren fehlgeschlagen"},
    }
    return expressions.Set{CodeBlock: labels[language]}
}

// In your handler, render your application's Page template.
ctx := expressions.With(r.Context(), userExpressions(r.URL.Query().Get("language")))
err := Page().Render(ctx, w)

Use the same preferences for HTMX

Wrap your routes with middleware to make the same expressions available to full pages and HTMX fragments. Here, the application reads a language cookie and layers the user’s choice over its system defaults. The mux and systemExpressions values belong to your application.

Use the same preferences for HTMX
func withExpressions(system expressions.Set, next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        // Replace this cookie lookup with your session or user-config lookup.
        language := ""
        if cookie, err := r.Cookie("language"); err == nil {
            language = cookie.Value
        }
        ctx := expressions.With(r.Context(), system)
        ctx = expressions.With(ctx, userExpressions(language))
        next.ServeHTTP(w, r.WithContext(ctx))
    })
}

// Wrap the application's mux, including HTMX endpoints.
handler := withExpressions(systemExpressions, mux)

For the full precedence rules, component overrides, and messages with counts, see the Internationalization guide.