# Messages and languages

A failure's `message` is fixed English for developers and logs. Clients
show text by `code`, which is stable:

```json
{ "error": { "code": "todo_not_found", "message": "Todo not found.", "request_id": "req_0b1e…" } }
```

The text people see is written in the app, keyed by the failure's code,
in its domain's language files
([Translations as messages](translations-as-messages.md)).
The failure's `client: { }` fields are its placeholders. `kind:` and
`message:` aren't translated, and the wording is never written on the
failure type, so all text for people follows one rule.

In `domains/planning/translations/fr_fr.jadpo`:

```text
translations {
    todo_not_found: "Tâche introuvable."
}
```

Every failure that can reach a response has wording in every supported
locale. The compiler knows each route's failures, so it checks this. A
failure that never leaves the server needs none.

Client fields that are dates or numbers are sent as values: an `Instant`
stays an instant on the wire. The client formats them for its own
language before filling the placeholder.

Beside each API's OpenAPI document, the compiler writes one file per
locale, `<api>.failures.<locale>.json`, for client apps to show. It maps
each code to its wording, in the same `{field}` syntax, and says which
placeholders need formatting and how: as a date, a time or a number
([Failures for client apps](failures-for-client-apps.md)).

A library package's failure is worded by the package, and the app can
reword it in its root language files. To show it under a different code,
not just in different words, map it to the app's own failure at the call
with `attempt`.
