Icu.Number (icu v0.6.0)

Locale-aware decimal formatting.

format/2 delegates to the ICU4X number formatter using the application locale (:icu, :default_locale). Use the convenience API for one-off conversions or build a persistent formatter via Icu.Number.Formatter.new/1 when you need to reuse the same configuration.

Examples

iex> Icu.Number.format(1234.5)
{:ok, "1,234.500"}

iex> Icu.Number.format(1234.5, maximum_fraction_digits: 1)
{:ok, "1,234.5"}

Options

  • :grouping – toggle locale-driven grouping rules (:auto, :always, :min2, :never).
  • :sign_display – control sign rendering (:auto, :always, :never, :except_zero, :negative).
  • :minimum_integer_digits – left-pad with zeros to hit a minimum integer width.
  • :minimum_fraction_digits – right-pad with zeros to ensure fractional precision.
  • :maximum_fraction_digits – clamp or round fractional precision.
  • :style:decimal (default) or :percent. Percent follows Intl.NumberFormat semantics: the input is a ratio and is multiplied by 100 (0.5"50%"), with locale-correct placement (tr"%50", fr"50 %"). Cannot be combined with notation: :compact.
  • :notation:standard (default) or :compact for locale-aware abbreviations (194438"194K", Japanese/Chinese group by 万). See format_compact/2.
  • :compact_display:short (default, e.g. "194K") or :long (e.g. "194 thousand"), only meaningful with notation: :compact.
  • :rounding_mode:half_even (default) or :trunc. With :trunc, compact output never overstates the value (6_718"6K", never "7K").
  • :locale – override the locale for this invocation.

:minimum_integer_digits, :minimum_fraction_digits and :maximum_fraction_digits only apply to :standard notation; compact precision is locale-driven.

Summary

Types

Controls the width of compact affixes.

The formatted compact string alongside the exact numeric it represents.

Opaque reference to an ICU4X number formatter.

Controls digit grouping behavior.

Selects standard or compact (abbreviated) notation.

Map form of the supported options.

Keyword form of the supported options.

Controls how values are rounded to the displayed precision.

Controls how positive/negative signs are displayed.

Selects plain decimal or percent formatting.

Functions

Formats a number.

Formats a number and raises on error.

Formats a number in compact notation, returning both the string and the exact numeric value it represents.

Formats a number in compact notation and raises on error.

Formats a number to parts using an existing formatter.

Formats a number to parts and raises on error.

Types

compact_display()

@type compact_display() :: :short | :long

Controls the width of compact affixes.

compact_result()

@type compact_result() :: %{formatted: String.t(), displayed_value: Decimal.t()}

The formatted compact string alongside the exact numeric it represents.

:displayed_value is a Decimal — what the abbreviation stands for (e.g. Decimal.new("194000") for "194K") — so callers can Decimal.compare/2 it against the input and append a localised "+" when it understates.

format_error()

@type format_error() ::
  :invalid_formatter | :invalid_number | :invalid_locale | :invalid_options

formatter()

@type formatter() :: Icu.Number.Formatter.t()

Opaque reference to an ICU4X number formatter.

grouping()

@type grouping() :: :auto | :always | :min2 | :never

Controls digit grouping behavior.

notation()

@type notation() :: :standard | :compact

Selects standard or compact (abbreviated) notation.

options()

@type options() :: %{
  optional(:grouping) => grouping(),
  optional(:sign_display) => sign_display(),
  optional(:minimum_integer_digits) => pos_integer(),
  optional(:minimum_fraction_digits) => non_neg_integer(),
  optional(:maximum_fraction_digits) => non_neg_integer() | nil,
  optional(:style) => style(),
  optional(:notation) => notation(),
  optional(:compact_display) => compact_display(),
  optional(:rounding_mode) => rounding_mode(),
  optional(:locale) => Icu.LanguageTag.t() | String.t() | nil
}

Map form of the supported options.

options_input()

@type options_input() :: options() | options_list() | nil

options_list()

@type options_list() :: [
  grouping: grouping(),
  sign_display: sign_display(),
  minimum_integer_digits: pos_integer(),
  minimum_fraction_digits: non_neg_integer(),
  maximum_fraction_digits: non_neg_integer() | nil,
  style: style(),
  notation: notation(),
  compact_display: compact_display(),
  rounding_mode: rounding_mode(),
  locale: Icu.LanguageTag.t() | String.t() | nil
]

Keyword form of the supported options.

rounding_mode()

@type rounding_mode() :: :half_even | :trunc

Controls how values are rounded to the displayed precision.

sign_display()

@type sign_display() :: :auto | :always | :never | :except_zero | :negative

Controls how positive/negative signs are displayed.

style()

@type style() :: :decimal | :percent

Selects plain decimal or percent formatting.

Functions

format(number, options \\ [])

@spec format(number(), options_input()) ::
  {:ok, String.t()} | {:error, format_error()}

Formats a number.

Accepts any numeric type (integer, float, or decimal-like struct that implements the required protocol). Returns {:ok, String.t()} or an error tuple when the input or options are invalid.

Examples

iex> Icu.Number.format(-123.45)
{:ok, "-123.450"}

iex> Icu.Number.format(42, sign_display: :always)
{:ok, "+42.000"}

iex> Icu.Number.format(194_438, notation: :compact)
{:ok, "194K"}

iex> Icu.Number.format(0.5, style: :percent)
{:ok, "50%"}

format!(number, options \\ [])

@spec format!(number(), options_input()) :: String.t()

Formats a number and raises on error.

Examples

iex> Icu.Number.format!(42, sign_display: :always)
"+42.000"

format_compact(number, options \\ [])

@spec format_compact(number(), options_input()) ::
  {:ok, compact_result()} | {:error, format_error()}

Formats a number in compact notation, returning both the string and the exact numeric value it represents.

Always uses notation: :compact (any :notation in options is ignored). Accepts the same inputs as format/2 (integers, floats, Decimals, including fractional values); :compact_display and :rounding_mode are the relevant knobs.

:displayed_value is a Decimal giving the exact numeric the abbreviation denotes. Compare it against the input to detect when the display understates the value (e.g. to append a localised "+"):

iex> {:ok, %{formatted: formatted, displayed_value: displayed}} =
...>   Icu.Number.format_compact(6_718, locale: "en", rounding_mode: :trunc)
iex> formatted
"6K"
iex> Decimal.compare(displayed, 6_718)
:lt

Under rounding_mode: :trunc the abbreviation never overstates the input, so Decimal.compare(displayed_value, input) is always :lt or :eq.

Examples

iex> {:ok, result} = Icu.Number.format_compact(194_438, locale: "en", rounding_mode: :trunc)
iex> {result.formatted, Decimal.to_string(result.displayed_value)}
{"194K", "194000"}

iex> {:ok, result} = Icu.Number.format_compact(780, locale: "en")
iex> {result.formatted, Decimal.to_string(result.displayed_value)}
{"780", "780"}

iex> # fractional inputs are accepted; the Decimal denotes the string exactly
iex> {:ok, result} = Icu.Number.format_compact(5.5, locale: "en")
iex> {result.formatted, Decimal.to_string(result.displayed_value)}
{"5.5", "5.5"}

format_compact!(number, options \\ [])

@spec format_compact!(number(), options_input()) :: compact_result()

Formats a number in compact notation and raises on error.

Examples

iex> result = Icu.Number.format_compact!(194_438, locale: "en", rounding_mode: :trunc)
iex> {result.formatted, Decimal.to_string(result.displayed_value)}
{"194K", "194000"}

format_to_parts(number, options \\ [])

@spec format_to_parts(number(), options_input()) ::
  {:ok, [map()]} | {:error, format_error()}

Formats a number to parts using an existing formatter.

Returns tagged pieces (integer, decimal separator, fraction, etc.) so callers can add markup around specific components.

Examples

iex> {:ok, parts} = Icu.Number.format_to_parts(123.5)
iex> Enum.map(parts, & &1.part_type)
[:integer, :decimal, :fraction]

format_to_parts!(number, options \\ [])

@spec format_to_parts!(number(), options_input()) :: [map()]

Formats a number to parts and raises on error.

Examples

iex> parts = Icu.Number.format_to_parts!(123.5)
iex> Enum.count(parts)
3