Conventions and a small behaviour shared by structured Localize exceptions.
The :reason field
Exceptions that distinguish between multiple failure categories
carry a :reason field whose value is a documented atom from
a closed set. Callers can pattern-match on :reason to branch on
category without parsing the rendered message; message/1 is the
single place a user-facing sentence is assembled.
Modules that adopt this convention declare @behaviour Localize.Exception and implement reason_atoms/0, returning the
exhaustive list of valid :reason values for that struct. This
lets tooling — including the structural-exception test suite —
iterate the documented reasons and verify that message/1 has a
clause for each.
The :cause field
When a higher layer must report a lower layer's failure, the outer
exception carries the inner one in a :cause field of type
Exception.t() | nil. The convention is:
:causeis set when, and only when, the outer exception is a wrapper. A direct error sets:causetonil.The outer
message/1may delegate to the inner viaException.message(cause), possibly with a leading context phrase.Programmatic callers can pattern-match on the outer struct for the operation context, and call
Exception.message/1on:causefor the original detail.
This convention is used by Localize.FormatError,
Localize.LocaleDownloadError, and Localize.ParseError.
Why no prose in structural fields
Fields like :reason, :expected, :path, and :detail must
hold structured values — atoms, paths, short labels, struct
references — not free-form sentences with interpolated values.
Putting a sentence in a structural field defeats pattern matching,
duplicates content into message/1, and prevents translation.
Summary
Callbacks
Returns the closed set of atoms permitted in this exception's
:reason field.
Functions
Render an MF2-format Gettext message safely for use inside an
exception's message/1 callback.
Callbacks
@callback reason_atoms() :: [atom()]
Returns the closed set of atoms permitted in this exception's
:reason field.
Used by tests to verify that message/1 has a rendering clause
for each documented reason atom. The list MUST be exhaustive —
any atom assigned to :reason at runtime must appear here.
Functions
Render an MF2-format Gettext message safely for use inside an
exception's message/1 callback.
Exception.message/1 is called from raise, Exception.format/2,
log handlers, and inspect paths — none of which can tolerate a
raise. This helper wraps Gettext.dpgettext/5 so that any failure
in the message formatter (a NIF crash, a hostile String.Chars or
Inspect impl on a bound value, a future regression) falls back
to the raw msgid rather than propagating.
Use this only in defexception message/1 callbacks. General MF2
formatting should call Gettext.dpgettext/5 (or the higher-level
macros) directly so callers see the underlying formatter error.
Arguments
msgctxtis the gettext context string (e.g."locale").msgidis the source-language MF2 message string.bindingsis a keyword list of variable bindings for the message. The default is[].
Returns
- The interpolated message string, or
msgidunchanged if interpolation failed.