Using Localize.Lua with AshLua

Copy Markdown View Source

AshLua embeds Lua scripts in Ash, giving them a consistent actor, tenant and context and a bridge to Ash actions. It is built on the same lua (Luerl) package that Localize.Lua targets, so an AshLua VM is a Lua VM — and Localize.Lua installs onto it directly. There is no separate AshLua binding: the same Localize.Lua.install/1 you use for a plain VM works here.

Installing

AshLua.new/1 returns a Lua.t/0 with Ash bindings installed. Add the localize table with Localize.Lua.install/1:

lua =
  AshLua.new(otp_app: :my_app)
  |> Localize.Lua.install()

{[price], _lua} = Lua.eval!(lua, ~S[return localize.currency(order.total, "EUR", {locale = user.locale})])

AshLua also accepts a pre-built VM through its :lua option, so you can install localize first and let AshLua layer its bindings on top — either order gives you a VM with both:

lua = AshLua.new(otp_app: :my_app, lua: Localize.Lua.install(Lua.new()))

For repeated evaluation, AshLua.eval!/2 takes the same :lua:

AshLua.eval!(script, otp_app: :my_app, lua: Localize.Lua.install(Lua.new()))

Both worlds in one script

Once installed, an Ash-Lua script formats data with localize.* right alongside its Ash calls:

local order = cms.orders.get({ id = order_id })

return "Total: " .. localize.currency(order.total, order.currency, {locale = ctx.locale})
    .. " — " .. localize.relative(order.placed_days_ago, "day", {locale = ctx.locale})

"Fetch the order through Ash, then render its total as currency and its age as relative time in the reader's locale."

Ash owns the data access; Localize.Lua owns the locale-aware formatting. Neither touches the other's globals.

Relationship to ash_cms

ash_cms renders its Lua templates through AshLua, so the same integration applies one layer up — see Using Localize.Lua in Ash CMS for wiring it into the CMS render path specifically.

Locale data and safety

The locale-data and safety notes from Using Localize.Lua in Lua apply unchanged: only the en locale ships with Localize (install others with mix localize.download_locales), and every localize.* call returns a string and falls back gracefully, so a template can never crash the evaluation.