Abstract-form extractor for erli18n facade call sites.
Reads an Erlang source file through epp (NOT text scanning), so every
macro — including the public ?GETTEXT_DOMAIN from include/erli18n.hrl —
is expanded to a literal node BEFORE the walk. It then walks the parsed
forms looking for remote calls erli18n:Fn(Args) whose {Fn, Arity} is in
the keyword spec (rebar3_erli18n_keywords), and pulls the literal
msgid/msgid_plural/msgctxt and the literal-atom Domain.
What is extractable, what is skipped
Only COMPILE-TIME-CONSTANT operands are extracted, exactly as Elixir Gettext documents the dynamic-key caveat:
msgid/msgid_plural/msgctxtmust be a literal string ("...") or a literal binary (<<"...">>/~"..."). A variable, concatenation, or any other expression in those slots SKIPS the whole call site — never errors.Domain(d/dc families) must be a literal atom after expansion. A non-literal Domain SKIPS the call site rather than mis-domaining it. The bare families (no Domain slot) are keyed under the module's?GETTEXT_DOMAIN, whichepphas already expanded to a literal atom.
This is what guarantees the check gate never false-fails on a legitimately
dynamic key: a dynamic operand simply produces no .pot entry.
Output
extract_file/2 returns a list of extracted() records — one per recognized
call site — carrying the source reference {File, Line} so the .pot writer
can emit #: reference lines.
Summary
Types
One extracted catalog entry plus its source location.
Functions
Parse File through epp and extract every recognized erli18n call site,
using the module's own ?GETTEXT_DOMAIN for bare-family calls.
Parse File through epp ONCE, returning both the module's expanded
?GETTEXT_DOMAIN and the extracted call sites.
Types
-type extracted() :: #{domain := atom(), kind := rebar3_erli18n_keywords:kind(), context := undefined | binary(), msgid := binary(), plural := undefined | binary(), reference := {file:filename(), pos_integer()}}.
One extracted catalog entry plus its source location.
domain is the resolved literal atom. kind is singular or plural.
context is undefined or the literal binary msgctxt. msgid is the
literal binary. plural is undefined (singular) or the literal binary
msgid_plural. reference is {RelPath, Line} for the #: line.
Functions
-spec extract_file(file:filename(), [file:filename()]) -> {ok, [extracted()]} | {error, term()}.
Parse File through epp and extract every recognized erli18n call site,
using the module's own ?GETTEXT_DOMAIN for bare-family calls.
A thin wrapper over scan_file/2 that drops the resolved domain. Returns
{ok, [extracted()]} on success, or {error, Reason} if epp cannot open
the file.
-spec scan_file(file:filename(), [file:filename()]) -> {ok, atom(), [extracted()]} | {error, term()}.
Parse File through epp ONCE, returning both the module's expanded
?GETTEXT_DOMAIN and the extracted call sites.
This is the single-pass entry point the provider walk uses: it opens one
epp handle, drains every form (so all -define/-include directives are
applied), reads ?GETTEXT_DOMAIN from the macro table, and walks the
drained forms for facade call sites — avoiding a second parse and the
redundant error branch a two-call sequence would carry.
Returns {ok, Domain, [extracted()]} or {error, Reason} when epp cannot
open the file.