Framework.I18n (Framework v0.5.0)

View Source

Internationalization (i18n) support for Framework.

Provides locale resolution, translation helpers, and i18n infrastructure for all framework components including:

  • Transaction DSL operations (pure translation helpers)
  • Effects system (locale-aware email/webhook dispatch)
  • Template system (locale-specific template resolution)
  • AppSpec routes (optional locale-prefixed routing)

Configuration

config :framework, Framework.I18n,
  default_locale: "en-US",
  supported_locales: ["en-US", "es-ES", "fr-FR", "de-DE"],
  gettext_backend: Framework.I18n.Gettext

Locale Resolution Priority

  1. Explicit locale in operation input
  2. User preference from ctx.user.locale (if available)
  3. Session locale from ctx.session.locale (if available)
  4. Accept-Language header from ctx.headers["accept-language"]
  5. Default locale from configuration

Usage in Transaction DSL

use Framework.Transaction

operation :greet_user do
  plan fn input, ctx ->
    user = get(:users, input.user_id)

    result = compute fn ->
      %{
        # Pure translation - no I/O, reads from ctx
        greeting: Framework.I18n.t(ctx, "user.greeting", name: user.name),
        title: Framework.I18n.t(ctx, "dashboard.title")
      }
    end

    return result
  end
end

Usage in Effects

effect :email, "welcome",
  to: user.email,
  locale: ctx.locale  # Locale flows to effect

Gettext Integration

Framework uses Gettext for compile-time translations. Translation files are stored in priv/gettext/<locale>/LC_MESSAGES/:

priv/gettext/
  en-US/LC_MESSAGES/
    default.po
    errors.po
  es-ES/LC_MESSAGES/
    default.po
    errors.po

Summary

Functions

Get the default locale from configuration.

Check if a locale is supported.

Parse Accept-Language header and return best matching supported locale.

Resolve locale from multiple sources with priority ordering.

Get list of supported locales from configuration.

Translate a message key with optional bindings.

Translate a message key with pluralization support.

Validate and normalize a locale string.

Functions

get_default_locale()

Get the default locale from configuration.

Examples

iex> Framework.I18n.get_default_locale()
"en-US"

locale_supported?(locale)

Check if a locale is supported.

Examples

iex> Framework.I18n.locale_supported?("en-US")
true

iex> Framework.I18n.locale_supported?("invalid")
false

parse_accept_language_header(header)

Parse Accept-Language header and return best matching supported locale.

Examples

iex> Framework.I18n.parse_accept_language_header("es-ES,es;q=0.9,en;q=0.8")
"es-ES"

iex> Framework.I18n.parse_accept_language_header("fr-FR,fr;q=0.9")
"fr-FR"

iex> Framework.I18n.parse_accept_language_header("invalid")
"en-US"  # falls back to default

resolve_locale(input, ctx)

Resolve locale from multiple sources with priority ordering.

Priority Order

  1. Explicit input locale
  2. User preference (ctx.user.locale)
  3. Session locale (ctx.session.locale)
  4. Accept-Language header
  5. Default locale

Examples

iex> Framework.I18n.resolve_locale(%{locale: "es-ES"}, %{})
"es-ES"

iex> Framework.I18n.resolve_locale(%{}, %{user: %{locale: "fr-FR"}})
"fr-FR"

iex> Framework.I18n.resolve_locale(%{}, %{})
"en-US"  # default locale

supported_locales()

Get list of supported locales from configuration.

Examples

iex> Framework.I18n.supported_locales()
["en-US", "es-ES", "fr-FR", "de-DE"]

t(ctx, key, bindings \\ [])

Translate a message key with optional bindings.

This is a pure function that reads locale from context and delegates to the configured Gettext backend. No I/O is performed.

Examples

iex> ctx = %{locale: "en-US"}
iex> Framework.I18n.t(ctx, "user.greeting", name: "Alice")
"Hello, Alice!"

iex> ctx = %{locale: "es-ES"}
iex> Framework.I18n.t(ctx, "user.greeting", name: "Alice")
"¡Hola, Alice!"

Arguments

  • ctx - Context map containing :locale key
  • key - Translation key (e.g., "user.greeting", "errors.not_found")
  • bindings - Keyword list of variable bindings for interpolation

tn(ctx, singular, plural, count, bindings \\ [])

Translate a message key with pluralization support.

Examples

iex> ctx = %{locale: "en-US"}
iex> Framework.I18n.tn(ctx, "item.count", "item.counts", 1)
"1 item"

iex> Framework.I18n.tn(ctx, "item.count", "item.counts", 5)
"5 items"

validate_and_normalize_locale(locale)

Validate and normalize a locale string.

Returns the locale if valid, otherwise returns default locale.

Examples

iex> Framework.I18n.validate_and_normalize_locale("en-US")
"en-US"

iex> Framework.I18n.validate_and_normalize_locale("invalid")
"en-US"  # falls back to default