//! Friendly error layer and i18n message catalog (ADR-0019). //! //! Single chokepoint for user-visible message text. Engine //! errors flow through `translate()` into a structured //! [`FriendlyError`] payload that the renderer (in //! `output_render`) composes into final output. Every other //! user-visible string in the codebase migrates to this //! catalog over time via the [`t!`] macro (ADR-0019 §9). //! //! ## Catalog //! //! The catalog lives in `strings/.yaml`, embedded at //! compile time and parsed once on first access. Today the only //! locale is `en-US`; runtime selection is deferred (ADR-0019 //! §8.2). Hierarchical YAML keys flatten to dot-paths //! internally — `error.unique.insert.verbose` is the path the //! `t!()` macro and the translator look up. //! //! ## The `t!()` macro //! //! ```ignore //! use rdbms_playground::t; //! let s = t!("error.unique.insert.verbose", //! table = "Customers", column = "id"); //! ``` //! //! Placeholder values implement `Display`. Format specifiers //! (`{name:08.2}`, `{name:>10}`, …) are explicitly rejected at //! substitution time — see ADR-0019 §8.4. pub mod error; pub mod format; pub mod keys; pub mod translate; pub use error::{DiagnosticTable, FriendlyError}; pub use format::{catalog, Catalog}; pub use translate::{FailureContext, Operation, TranslateContext, Verbosity}; // `translate::translate` and `format::translate` are different // callables — the former is the structured DbError → FriendlyError // classifier (the H1 entry point); the latter is the lower-level // catalog lookup the `t!()` macro expands to. Re-export both // under non-conflicting names. pub use format::translate; pub use translate::translate as translate_error; /// Look up `key` in the catalog and substitute named arguments. /// /// Panics if the key is missing, if the template has malformed /// placeholders, or if the args don't supply every name the /// template references. The catalog validator unit test (Step 7, /// ADR-0019 §8.6) catches these at build time so they should /// never fire at runtime. #[macro_export] macro_rules! t { ($key:literal $(, $name:ident = $value:expr)* $(,)?) => {{ $crate::friendly::translate( $key, &[$( (stringify!($name), &$value as &dyn ::std::fmt::Display) ),*], ) }}; }