The one place an error reason becomes a sentence a person reads.
Contexts return atoms and tuples ({:error, :stale}, {:error, {:forbidden_characters, ["#"]}}); the LiveViews call message/1 at the
flash boundary. Keeping the copy here means the vault page and the notes
panel say the same thing about the same failure, and translators have one
file to work from.
A reason nothing here knows is logged, not shown: an inspect/1-ed term
in a flash tells the person nothing and the developer less than the log line
does.
Summary
Functions
Every error on a changeset, as one sentence.
An error reason, fit for a log line.
A translated, user-facing sentence for an error reason.
Functions
@spec changeset_message(Ecto.Changeset.t()) :: String.t()
Every error on a changeset, as one sentence.
Messages go through core's error translation — the same one <.input>
uses — so Ecto's own ("can't be blank") read the same here as on a form.
An error reason, fit for a log line.
A changeset is reduced to its messages: it carries the note's whole content, which has no business in a log. Anything else is inspected, bounded.
A translated, user-facing sentence for an error reason.