Runtime registry for user-defined units backed by :persistent_term.
Custom units are stored in a single map keyed by unit name. The registry
is checked by Localize.Unit.Data, Localize.Unit.BaseUnit,
Localize.Unit.Conversion, and the unit formatter to overlay
runtime definitions on top of the compile-time CLDR data.
Definition structure
Each definition is a map with the following keys:
:base_unit(required) — the CLDR base unit this custom unit converts to (e.g.,"meter","kilogram","second").:factor(required) — the conversion factor:1 custom_unit = factor * base_unit.:offset(optional) — additive offset for the conversion. Defaults to0.0.:category(required) — the unit category (e.g.,"length","mass").:display(optional) — locale-specific display patterns. A nested map oflocale => style => plural_patterns.
Summary
Functions
Returns all registered custom units as a map of name to definition.
Removes all custom unit registrations. Primarily for testing.
Returns the definition for a custom unit, or nil if not registered.
Loads custom unit definitions from an .exs file.
Registers a custom unit definition.
Registers multiple custom units in a single persistent_term update.
Returns whether a unit name is registered in the custom registry.
Functions
Returns all registered custom units as a map of name to definition.
@spec clear() :: :ok
Removes all custom unit registrations. Primarily for testing.
Returns the definition for a custom unit, or nil if not registered.
Arguments
unit_name— the unit identifier string.
Returns
- A definition map or
nil.
@spec load_file(String.t()) :: {:ok, non_neg_integer()} | {:error, String.t()}
Loads custom unit definitions from an .exs file.
The file must evaluate to a list of maps, each with a :unit key
and the standard definition fields.
Security
This function uses Code.eval_file/1 to evaluate the given
file, which executes arbitrary Elixir code. Only load files
from trusted sources. Never call this function with unsanitised
user input or paths derived from external data.
Arguments
path— path to the.exsfile.
Returns
{:ok, count}with the number of units loaded.{:error, reason}on failure.
Registers a custom unit definition.
Arguments
name— the unit identifier string.definition— a map with:base_unit,:factor, and:categorykeys.
Returns
:okon success.{:error, reason}if validation fails.
@spec register_batch(%{required(String.t()) => map()}) :: {:ok, non_neg_integer()}
Registers multiple custom units in a single persistent_term update.
This is significantly more memory-efficient than calling register/2
in a loop, because it avoids creating intermediate persistent_term
snapshots for each unit. Each snapshot is stored in the BEAM's literal
area and is not freed until a global garbage collection sweep, so
bulk registration via register/2 can exhaust literal memory.
Arguments
definitions— a map of%{name => definition}where each definition has:base_unit,:factor, and:categorykeys.
Returns
{:ok, count}with the number of units registered.{:error, reason}if any validation fails. No units are registered on error (the operation is atomic).
Returns whether a unit name is registered in the custom registry.