Pure key-existence checker for compile-time catalogs.
Compares the literal msgids of a project's facade call sites (as
deduplicated by rebar3_erli18n_common:extract_project/1) against the
per-domain key universe of the compiled catalogs, and reports every call
site whose {Context, Msgid} has no matching compiled key. Each missing key
is reported exactly ONCE: the universe is the locale-invariant UNION of every
compiled locale's keys for a domain, and the call sites are already
deduplicated to one logical message each, so a msgid used in three locales
(or from three source files) yields a single diagnostic carrying all of its
call sites.
The module is PURE: no file or process I/O, no codegen, and no
persistent_term access. The reference universe is built by the caller
(the compile provider) by keying each parsed .po/.pot entry through
rebar3_erli18n_common:entry_key/1; check/3 only consults the resulting
sets. Domain scoping (restricting the check to domains that
actually have a compiled catalog) is also the CALLER's responsibility: a call
site whose domain is ABSENT from the universe map is never flagged, so the
checker stays silent about domains the project did not opt into compiling.
Policy
check/3 is policy-driven: off short-circuits to ok without inspecting
anything; warn and strict both perform the comparison and return the same
{violations, [diag()]} when keys are missing (or ok when none are). The
distinction between warn (log and continue) and strict (fail the build) is
mapped by the provider that calls this function, not here — keeping the
checker a deterministic pure predicate.
Determinism
The returned diagnostics are sorted by {Domain, File, Line} (then context
and msgid as tie-breakers), and each diagnostic's call sites are themselves
sorted and de-duplicated, so the output is byte-stable across runs and
machines. format_diag/1 renders a diagnostic to a byte-pinnable message that
carries the exact rebar3 erli18n extract then rebar3 erli18n compile
remediation commands.
Summary
Types
One missing-key diagnostic: a logical message that a facade call site references but the compiled catalog does not define.
The check policy.
Functions
Compare call sites against the compiled key universe under Policy.
Render a diag() to a byte-pinnable, remediation-carrying message.
Types
-type call_sites() :: #{atom() => [rebar3_erli18n_common:dedup_entry()]}.
-type diag() :: {Domain :: atom(), Ctx :: undefined | binary(), Msgid :: binary(), Sites :: [{file:filename(), pos_integer()}]}.
One missing-key diagnostic: a logical message that a facade call site references but the compiled catalog does not define.
Domain is the gettext domain; Ctx the message context (undefined for the
bare, context-less form); Msgid the literal message id; and Sites the
sorted, de-duplicated {SourceFile, Line} call sites that reference it.
-type policy() :: off | warn | strict.
The check policy.
off disables the check entirely (always ok); warn and strict both run
the comparison and return any {violations, _} identically — the caller maps
warn to a logged warning and strict to a build failure.
Functions
-spec check(universe(), call_sites(), policy()) -> ok | {violations, [diag()]}.
Compare call sites against the compiled key universe under Policy.
When Policy is off, returns ok without inspecting either map. Otherwise,
for every domain that is present in BOTH Universe and CallSites, each call
site whose {Context, Msgid} key is not an element of that domain's universe
set becomes a diagnostic. Domains in CallSites but ABSENT from Universe are
skipped (the caller's domain scoping). Returns ok when nothing is missing, or
{violations, Diags} with the diagnostics sorted by {Domain, File, Line}.
Render a diag() to a byte-pinnable, remediation-carrying message.
The output is deterministic for a given diagnostic and names the exact
rebar3 erli18n extract then rebar3 erli18n compile commands that
regenerate the compiled catalog so the missing key is defined.