Packages
ex_cldr_numbers
2.1.0
2.38.3
2.38.2
2.38.1
2.38.0
2.37.0
2.36.0
2.35.2
2.35.1
2.35.0
2.34.1
2.34.0
2.33.6
2.33.5
2.33.4
2.33.3
2.33.2
2.33.1
2.33.0
2.32.4
2.32.3
2.32.2
2.32.1
2.32.0
retired
2.31.3
retired
2.31.2
2.31.1
2.31.0
2.30.1
2.30.0
2.29.0
2.28.0
2.27.3
2.27.2
2.27.1
2.27.0
2.26.0
2.25.2
2.25.1
2.25.0
2.24.0
2.23.3
2.23.2
2.23.1
2.23.0
2.23.0-rc.4
2.23.0-rc.3
2.23.0-rc.2
2.23.0-rc.1
2.23.0-rc.0
2.22.1
2.22.0
2.21.0
2.20.0
2.19.0
2.18.4
2.18.3
2.18.2
2.18.1
2.18.0
2.17.0
2.17.0-rc.1
2.17.0-rc.0
2.16.1
2.16.0
2.16.0-rc.0
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.0
2.13.2
2.13.1
2.13.0
2.13.0-rc.0
2.12.1
2.12.0
2.11.0
2.10.0
2.9.0
2.8.0
2.7.2
2.7.1
2.7.0
2.6.4
2.6.3
2.6.2
2.6.1
2.6.0
2.5.0
2.4.4
2.4.3
2.4.2
2.4.1
2.4.0
2.3.0
2.2.0
2.1.1
2.1.0
2.0.0
2.0.0-rc.0
1.6.0
1.5.2
1.5.1
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.1
1.3.0
1.3.0-rc.1
1.3.0-rc.0
retired
1.2.0
1.1.0
1.0.1
1.0.0
1.0.0-rc.0
retired
0.3.3
0.3.2
retired
0.3.1
retired
0.3.0
retired
0.2.3
0.2.2
0.2.1
0.2.0
0.1.0
Number and currency localization and formatting functions for the Common Locale Data Repository (CLDR).
Current section
Files
Jump to
Current section
Files
lib/number/format/options.ex
defmodule Cldr.Number.Format.Options do
defstruct [
:currency, :currency_digits, :currency_spacing, :format, :locale,
:minimum_grouping_digits, :number_system, :pattern,
:rounding_mode, :fractional_digits
]
@short_format_styles [
:currency_short,
:currency_long,
:decimal_short,
:decimal_long
]
alias Cldr.Number.System
alias Cldr.Number.Format.Compiler
alias Cldr.Number.Format
def validate_options(backend, options) do
with {:ok, options} <- merge_default_options(backend, options),
{:ok, options} <- validate_locale(backend, options),
{:ok, options} <- validate_number_system(backend, options),
{:ok, options} <- normalize_options(backend, options),
{:ok, options} <- validate_currency_options(backend, options) do
{:ok, struct(__MODULE__, options)}
end
end
def short_format_styles do
@short_format_styles
end
defp validate_locale(backend, options) do
with {:ok, locale} <- backend.validate_locale(options[:locale]) do
options = Map.put(options, :locale, locale)
{:ok, options}
end
end
defp validate_number_system(backend, options) do
locale = options[:locale]
number_system = options[:number_system]
with {:ok, system} <- System.system_name_from(number_system, locale, backend) do
options = Map.put(options, :number_system, system)
{:ok, options}
end
end
defp validate_currency_options(backend, options) do
format = options[:format]
currency = options[:currency]
currency_format? = currency_format?(format)
with {:ok, _currency} <- currency_format_has_code(format, currency_format?, currency) do
options = Map.put(options, :currency_spacing, currency_spacing(backend, options))
{:ok, options}
end
end
defp currency_spacing(backend, options) do
module = Module.concat(backend, Number.Format)
module.currency_spacing(options[:locale], options[:number_system])
end
# Merge options and default options with supplied options always
# the winner. If :currency is specified then the default :format
# will be format: currency
defp merge_default_options(backend, options) do
new_options =
Module.concat(backend, Number).default_options()
|> merge(options, fn _k, _v1, v2 -> v2 end)
|> adjust_for_currency(options[:currency], options[:format])
{:ok, new_options}
end
defp normalize_options(backend, options) do
options =
options
|> Map.new()
|> set_currency_digits
|> resolve_standard_format(backend)
|> adjust_short_forms
{:ok, options}
end
defp merge(defaults, options, fun) when is_list(options) do
defaults
|> Keyword.merge(options, fun)
|> Cldr.Map.from_keyword()
end
defp merge(defaults, options, fun) when is_map(options) do
defaults
|> Cldr.Map.from_keyword()
|> Map.merge(options, fun)
end
@doc false
def resolve_standard_format(%{format: format} = options, _backend)
when format in @short_format_styles do
options
end
def resolve_standard_format(options, backend) do
format =
options
|> Map.get(:format)
|> lookup_standard_format(backend, options)
Map.put(options, :format, format)
end
defp adjust_short_forms(options) do
options
|> check_options(:short, options[:currency], :currency_short)
|> check_options(:long, options[:currency], :currency_long)
|> check_options(:short, !options[:currency], :decimal_short)
|> check_options(:long, !options[:currency], :decimal_long)
end
# If no format is specified but a currency is,
# force the format to be :currency
defp adjust_for_currency(options, currency, nil) when not is_nil(currency) do
Map.put(options, :format, :currency)
end
defp adjust_for_currency(options, _currency, _format) do
options
end
# We use the option `:cash` to decide if we
# want to use cash digits or accounting digits
defp set_currency_digits(%{cash: true} = options) do
options
|> Map.delete(:cash)
|> Map.put(:currency_digits, :cash)
end
defp set_currency_digits(%{cash: false} = options) do
options
|> Map.delete(:cash)
|> Map.put(:currency_digits, :accounting)
end
defp set_currency_digits(%{currency_digits: _mode} = options) do
options
end
defp set_currency_digits(options) do
options
|> Map.put(:currency_digits, :accounting)
end
@doc false
def lookup_standard_format(format, backend, options) when is_atom(format) do
locale = Map.get(options, :locale)
number_system = Map.get(options, :number_system)
options_format = Map.get(options, :format)
with {:ok, formats} <- Format.formats_for(locale, number_system, backend) do
Map.get(formats, format) || options_format
end
end
def lookup_standard_format(format, _backend, _options) when is_binary(format) do
format
end
# if the format is :short or :long then we set the full format name
# based upon whether there is a :currency set in options or not.
defp check_options(options, format, check, finally) do
if options[:format] == format && check do
Map.put(options, :format, finally)
else
options
end
end
defp currency_format_has_code(format, true, nil) do
{
:error,
{
Cldr.FormatError,
"currency format #{inspect(format)} requires that " <> "options[:currency] be specified"
}
}
end
defp currency_format_has_code(_format, true, currency) do
Cldr.validate_currency(currency)
end
defp currency_format_has_code(_format, _boolean, currency) do
{:ok, currency}
end
defp currency_format?(format) when is_atom(format) do
format == :currency_short
end
defp currency_format?(format) when is_binary(format) do
format && String.contains?(format, Compiler.placeholder(:currency))
end
defp currency_format?(_format) do
false
end
def validate_other_format(other_type, backend, options) do
format_module = Module.concat(backend, Number.Format)
with {:ok, formats} <- format_module.formats_for(options.locale, options.number_system) do
if format = Map.get(formats.other, other_type) do
{:ok, format}
else
locale_name = options.locale.cldr_locale_name
{
:error,
{
Cldr.UnknownFormatError,
"The locale #{inspect(locale_name)} with number system " <>
"#{inspect(options[:number_system])} does not define a format " <>
"#{inspect(other_type)}."
}
}
end
end
end
end