defmodule Cldr.Unit.Backend do
def define_unit_module(config) do
module = inspect(__MODULE__)
backend = config.backend
additional_units = Module.concat(backend, Unit.Additional)
config = Macro.escape(config)
quote location: :keep,
bind_quoted: [
module: module,
backend: backend,
config: config,
additional_units: additional_units
] do
# Create an empty additional units module if it wasn't previously
# defined
unless Code.ensure_loaded?(additional_units) do
defmodule additional_units do
@moduledoc false
def known_locales do
[]
end
def units_for(_locale, _style) do
%{}
end
def additional_units do
[]
end
end
end
defmodule Unit do
@moduledoc false
if Cldr.Config.include_module_docs?(config.generate_docs) do
@moduledoc """
Supports the CLDR Units definitions which provide for the localization of many
unit types.
"""
end
@styles [:long, :short, :narrow]
alias Cldr.Math
defdelegate new(unit, value), to: Cldr.Unit
defdelegate new!(unit, value), to: Cldr.Unit
defdelegate compatible?(unit_1, unit_2), to: Cldr.Unit
defdelegate value(unit), to: Cldr.Unit
defdelegate zero(unit), to: Cldr.Unit
defdelegate zero?(unit), to: Cldr.Unit
defdelegate decompose(unit, list), to: Cldr.Unit
defdelegate measurement_system_from_locale(locale), to: Cldr.Unit
defdelegate measurement_system_from_locale(locale, category), to: Cldr.Unit
defdelegate measurement_system_from_locale(locale, backend, category), to: Cldr.Unit
defdelegate measurement_systems_for_unit(unit), to: Cldr.Unit
defdelegate measurement_system_for_territory(territory), to: Cldr.Unit
defdelegate measurement_system_for_territory(territory, key), to: Cldr.Unit
defdelegate measurement_system?(unit, systems), to: Cldr.Unit
@deprecated "Use #{inspect(__MODULE__)}.measurement_system_for_territory/1"
defdelegate measurement_system_for(territory),
to: Cldr.Unit,
as: :measurement_system_for_territory
@deprecated "Use #{inspect(__MODULE__)}.measurement_system_for_territory/2"
defdelegate measurement_system_for(territory, key),
to: Cldr.Unit,
as: :measurement_system_for_territory
defdelegate known_units, to: Cldr.Unit
defdelegate known_unit_categories, to: Cldr.Unit
defdelegate known_styles, to: Cldr.Unit
defdelegate styles, to: Cldr.Unit, as: :known_styles
defdelegate default_style, to: Cldr.Unit
defdelegate validate_unit(unit), to: Cldr.Unit
defdelegate validate_style(unit), to: Cldr.Unit
defdelegate unit_category(unit), to: Cldr.Unit
defdelegate add(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate sub(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate mult(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate div(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate add!(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate sub!(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate mult!(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate div!(unit_1, unit_2), to: Cldr.Unit.Math
defdelegate round(unit, places, mode), to: Cldr.Unit.Math
defdelegate round(unit, places), to: Cldr.Unit.Math
defdelegate round(unit), to: Cldr.Unit.Math
defdelegate convert(unit_1, to_unit), to: Cldr.Unit.Conversion
defdelegate convert!(unit_1, to_unit), to: Cldr.Unit.Conversion
@doc """
Formats a number into a string according to a unit definition for a locale.
## Arguments
* `list_or_number` is any number (integer, float or Decimal) or a
`t:Cldr.Unit` struct or a list of `t:Cldr.Unit` structs
* `options` is a keyword list
## Options
* `:unit` is any unit returned by `Cldr.Unit.known_units/0`. Ignored if
the number to be formatted is a `t:Cldr.Unit` struct
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
* `:style` is one of those returned by `Cldr.Unit.known_styles`.
The current styles are `:long`, `:short` and `:narrow`.
The default is `style: :long`
* `:grammatical_case` indicates that a localisation for the given
locale and given grammatical case should be used. See `Cldr.Unit.known_grammatical_cases/0`
for the list of known grammatical cases. Note that not all locales
define all cases. However all locales do define the `:nominative`
case, which is also the default.
* `:gender` indicates that a localisation for the given
locale and given grammatical gender should be used. See `Cldr.Unit.known_grammatical_genders/0`
for the list of known grammatical genders. Note that not all locales
define all genders. The default gender is `#{inspect(__MODULE__)}.default_gender/1`
for the given locale.
* `:list_options` is a keyword list of options for formatting a list
which is passed through to `Cldr.List.to_string/3`. This is only
applicable when formatting a list of units.
* Any other options are passed to `Cldr.Number.to_string/2`
which is used to format the `number`
## Returns
* `{:ok, formatted_string}` or
* `{:error, {exception, message}}`
## Examples
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:gallon, 123)
{:ok, "123 gallons"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:gallon, 1)
{:ok, "1 gallon"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:gallon, 1), locale: "af"
{:ok, "1 gelling"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:gallon, 1), locale: "af-NA"
{:ok, "1 gelling"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:gallon, 1), locale: "bs"
{:ok, "1 galon"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:gallon, 1234), format: :long
{:ok, "1 thousand gallons"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:gallon, 1234), format: :short
{:ok, "1K gallons"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:megahertz, 1234)
{:ok, "1,234 megahertz"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:megahertz, 1234), style: :narrow
{:ok, "1,234MHz"}
iex> #{inspect(__MODULE__)}.to_string Cldr.Unit.new!(:megabyte, 1234), locale: "en", style: :unknown
{:error, {Cldr.UnknownFormatError, "The unit style :unknown is not known."}}
"""
@spec to_string(Cldr.Unit.value() | Cldr.Unit.t() | [Cldr.Unit.t(), ...], Keyword.t()) ::
{:ok, String.t()} | {:error, {atom, binary}}
def to_string(number, options \\ []) do
Cldr.Unit.Format.to_string(number, unquote(backend), options)
end
@doc """
Formats a list using `to_string/3` but raises if there is
an error.
## Arguments
* `list_or_number` is any number (integer, float or Decimal) or a
`t:Cldr.Unit` struct or a list of `t:Cldr.Unit` structs
* `options` is a keyword list
## Options
* `:unit` is any unit returned by `Cldr.Unit.known_units/0`. Ignored if
the number to be formatted is a `t:Cldr.Unit` struct
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
* `:style` is one of those returned by `Cldr.Unit.known_styles`.
The current styles are `:long`, `:short` and `:narrow`.
The default is `style: :long`
* `:grammatical_case` indicates that a localisation for the given
locale and given grammatical case should be used. See `Cldr.Unit.known_grammatical_cases/0`
for the list of known grammatical cases. Note that not all locales
define all cases. However all locales do define the `:nominative`
case, which is also the default.
* `:gender` indicates that a localisation for the given
locale and given grammatical gender should be used. See `Cldr.Unit.known_grammatical_genders/0`
for the list of known grammatical genders. Note that not all locales
define all genders. The default gender is `#{inspect(__MODULE__)}.default_gender/1`
for the given locale.
* `:list_options` is a keyword list of options for formatting a list
which is passed through to `Cldr.List.to_string/3`. This is only
applicable when formatting a list of units.
* Any other options are passed to `Cldr.Number.to_string/2`
which is used to format the `number`
## Returns
* `formatted_string` or
* raises an exception
## Examples
iex> #{inspect(__MODULE__)}.to_string! 123, unit: :gallon
"123 gallons"
iex> #{inspect(__MODULE__)}.to_string! 1, unit: :gallon
"1 gallon"
iex> #{inspect(__MODULE__)}.to_string! 1, unit: :gallon, locale: "af"
"1 gelling"
"""
@spec to_string!(Cldr.Unit.value() | Cldr.Unit.t() | [Cldr.Unit.t(), ...], Keyword.t()) ::
String.t() | no_return()
def to_string!(number, options \\ []) do
Cldr.Unit.Format.to_string!(number, unquote(backend), options)
end
@doc """
Formats a number into an iolist according to a unit definition
for a locale.
## Arguments
* `list_or_number` is any number (integer, float or Decimal) or a
`t:Cldr.Unit` struct or a list of `t:Cldr.Unit` structs
* `options` is a keyword list
## Options
* `:unit` is any unit returned by `Cldr.Unit.known_units/0`. Ignored if
the number to be formatted is a `t:Cldr.Unit` struct
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
* `:style` is one of those returned by `Cldr.Unit.known_styles`.
The current styles are `:long`, `:short` and `:narrow`.
The default is `style: :long`
* `:grammatical_case` indicates that a localisation for the given
locale and given grammatical case should be used. See `Cldr.Unit.known_grammatical_cases/0`
for the list of known grammatical cases. Note that not all locales
define all cases. However all locales do define the `:nominative`
case, which is also the default.
* `:gender` indicates that a localisation for the given
locale and given grammatical gender should be used. See `Cldr.Unit.known_grammatical_genders/0`
for the list of known grammatical genders. Note that not all locales
define all genders. The default gender is `#{inspect(__MODULE__)}.default_gender/1`
for the given locale.
* `:list_options` is a keyword list of options for formatting a list
which is passed through to `Cldr.List.to_string/3`. This is only
applicable when formatting a list of units.
* Any other options are passed to `Cldr.Number.to_string/2`
which is used to format the `number`
## Returns
* `{:ok, io_list}` or
* `{:error, {exception, message}}`
## Examples
iex> #{inspect(__MODULE__)}.to_iolist Cldr.Unit.new!(:gallon, 123)
{:ok, ["123", " gallons"]}
"""
@spec to_iolist(Cldr.Unit.value() | Cldr.Unit.t() | [Cldr.Unit.t(), ...], Keyword.t()) ::
{:ok, list()} | {:error, {atom, binary}}
def to_iolist(number, options \\ []) do
Cldr.Unit.Format.to_iolist(number, unquote(backend), options)
end
@doc """
Formats a unit using `to_iolist/3` but raises if there is
an error.
## Arguments
* `list_or_number` is any number (integer, float or Decimal) or a
`t:Cldr.Unit` struct or a list of `t:Cldr.Unit` structs
* `options` is a keyword list
## Options
* `:unit` is any unit returned by `Cldr.Unit.known_units/0`. Ignored if
the number to be formatted is a `t:Cldr.Unit` struct
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
* `:style` is one of those returned by `Cldr.Unit.known_styles/0`.
The current styles are `:long`, `:short` and `:narrow`.
The default is `style: :long`.
* `:grammatical_case` indicates that a localisation for the given
locale and given grammatical case should be used. See `Cldr.Unit.known_grammatical_cases/0`
for the list of known grammatical cases. Note that not all locales
define all cases. However all locales do define the `:nominative`
case, which is also the default.
* `:gender` indicates that a localisation for the given
locale and given grammatical gender should be used. See `Cldr.Unit.known_grammatical_genders/0`
for the list of known grammatical genders. Note that not all locales
define all genders. The default gender is `#{inspect(__MODULE__)}.default_gender/1`
for the given locale.
* `:list_options` is a keyword list of options for formatting a list
which is passed through to `Cldr.List.to_string/3`. This is only
applicable when formatting a list of units.
* Any other options are passed to `Cldr.Number.to_string/2`
which is used to format the `number`
## Returns
* `io_list` or
* raises an exception
## Examples
iex> #{inspect(__MODULE__)}.to_iolist! 123, unit: :gallon
["123", " gallons"]
"""
@spec to_iolist!(Cldr.Unit.value() | Cldr.Unit.t() | [Cldr.Unit.t(), ...], Keyword.t()) ::
list() | no_return()
def to_iolist!(number, options \\ []) do
Cldr.Unit.Format.to_iolist!(number, unquote(backend), options)
end
@doc """
Returns the localized display name
for a unit.
The returned text is generally suitable
for including in UI elements such as
selection boxes.
## Arguments
* `unit` is any `t:Cldr.Unit` or any
unit name returned by `Cldr.Unit.known_units/0`.
* `options` is a keyword list of options.
## Options
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`.
* `:style` is one of those returned by `Cldr.Unit.available_styles`.
The current styles are `:long`, `:short` and `:narrow`.
The default is `style: :long`.
## Examples
iex> #{inspect(__MODULE__)}.display_name :liter
"liters"
iex> #{inspect(__MODULE__)}.display_name :liter, locale: "fr"
"litres"
iex> #{inspect(__MODULE__)}.display_name :liter, locale: "fr", style: :short
"l"
"""
@spec display_name(Cldr.Unit.value() | Cldr.Unit.t(), Keyword.t()) ::
String.t() | {:error, {module, binary}}
def display_name(unit, options \\ []) do
options = Keyword.put(options, :backend, unquote(backend))
Cldr.Unit.display_name(unit, options)
end
@doc """
Localizes a unit according to the current
processes locale and backend.
The current process's locale is set with
`Cldr.put_locale/1`.
See `Cldr.Unit.localize/3` for further
details.
"""
@spec localize(Cldr.Unit.t()) :: [Cldr.Unit.t(), ...]
def localize(%Cldr.Unit{} = unit) do
Cldr.Unit.localize(unit)
end
@doc """
Localizes a unit according to a territory
A territory can be derived from a `t:Cldr.Locale.locale_name`
or `t:Cldr.LangaugeTag`.
Use this function if you have a unit which
should be presented in a user interface using
units relevant to the audience. For example, a
unit `#Cldr.Unit100, :meter>` might be better
presented to a US audience as `#Cldr.Unit<328, :foot>`.
## Arguments
* `unit` is any unit returned by `Cldr.Unit.new/2`
* `options` is a keyword list of options
## Options
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `Cldr.LanguageTag` struct. The default is `backend.get_locale/0`
* `:territory` is any valid territory code returned by
`Cldr.known_territories/0`. The default is the territory defined
as part of the `:locale`. The option `:territory` has a precedence
over the territory in a locale.
* `:usage` is the way in which the unit is intended
to be used. The available `usage` varyies according
to the unit category. See `Cldr.Unit.preferred_units/3`.
## Examples
iex> unit = Cldr.Unit.new!(1.83, :meter)
iex> #{inspect(__MODULE__)}.localize(unit, usage: :person_height, territory: :US)
[
Cldr.Unit.new!(:foot, 6, usage: :person_height),
Cldr.Unit.new!(:inch, "0.04724409448818897637795275598", usage: :person_height)
]
"""
@spec localize(Cldr.Unit.t(), Keyword.t()) :: [Cldr.Unit.t(), ...]
def localize(unit, options \\ []) do
Cldr.Unit.localize(unit, unquote(backend), options)
end
@doc """
Parse a string to create a new unit.
This function attempts to parse a string
into a `number` and `unit type`. If successful
it attempts to create a new unit using
`Cldr.Unit.new/3`.
The parsed `unit type` is aliased against all the
known unit names for a give locale (or the current
locale if no locale is specified). The known
aliases for unit types can be returned with
`MyApp.Cldr.Unit.unit_strings_for/1` where `MyApp.Cldr`
is the name of a backend module.
## Arguments
* `unit string` is any string to be parsed and if
possible used to create a new `t:Cldr.Unit`
* `options` is a keyword list of options
## Options
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `t:Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
## Returns
* `{:ok, unit}` or
* `{:error, {exception, reason}}`
## Examples
iex> #{inspect(__MODULE__)}.parse "1kg"
Cldr.Unit.new(1, :kilogram)
iex> #{inspect(__MODULE__)}.parse "1 tages", locale: "de"
Cldr.Unit.new(1, :day)
iex> #{inspect(__MODULE__)}.parse "1 tag", locale: "de"
Cldr.Unit.new(1, :day)
iex> #{inspect(__MODULE__)}.parse("42 millispangels")
{:error, {Cldr.UnknownUnitError, "Unknown unit was detected at \\"spangels\\""}}
"""
@spec parse(binary) :: {:ok, Cldr.Unit.t()} | {:error, {module(), binary()}}
@doc since: "3.10.0"
def parse(unit_string, options \\ []) do
options = Keyword.put(options, :backend, unquote(backend))
Cldr.Unit.parse(unit_string, options)
end
@doc since: "3.13.4"
@doc """
Parse a string to find a matching unit-atom.
This function attempts to parse a string and
extract the `unit type`.
The parsed `unit type` is aliased against all the
known unit names for a give locale (or the current
locale if no locale is specified). The known
aliases for unit types can be returned with
`MyApp.Cldr.Unit.unit_strings_for/1` where `MyApp.Cldr`
is the name of a backend module.
## Arguments
* `unit_name_string` is any string to be parsed and converted into a `unit type`
* `options` is a keyword list of options
## Options
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `t:Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
* `:backend` is any module that includes `use Cldr` and therefore
is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
* `:only` is a unit category or unit, or a list of unit categories and units.
The parsed unit must match one of the categories or units in order to
be valid. This is helpful when disambiguating parsed units. For example,
parsing "w" could be either `:watt` or `:weeks`. Specifying `only: :duration`
would return `:weeks`. Specifying `only: :power` would return `:watt`
* `:except` is the oppostte of `:only`. The parsed unit must *not*
match the specified unit or category, or unit categories and units.
## Returns
* `{:ok, unit_name}` or
* `{:error, {exception, reason}}`
## Notes
* When both `:only` and `:except` options are passed, both
conditions must be true in order to return a parsed result.
* Only units returned by `Cldr.Unit.known_units/0` can be
used in the `:only` and `:except` filters.
## Examples
iex> #{inspect(__MODULE__)}.parse_unit_name "kg"
{:ok, :kilogram}
iex> #{inspect(__MODULE__)}.parse_unit_name "w"
{:ok, :watt}
iex> #{inspect(__MODULE__)}.parse_unit_name "w", only: :duration
{:ok, :week}
iex> #{inspect(__MODULE__)}.parse_unit_name "m", only: [:year, :month, :day]
{:ok, :month}
iex> #{inspect(__MODULE__)}.parse_unit_name "tages", locale: "de"
{:ok, :day}
iex> #{inspect(__MODULE__)}.parse_unit_name "tag", locale: "de"
{:ok, :day}
iex> #{inspect(__MODULE__)}.parse_unit_name("millispangels")
{:error, {Cldr.UnknownUnitError, "Unknown unit was detected at \\"spangels\\""}}
"""
@spec parse_unit_name(binary, Keyword.t()) :: {:ok, atom} | {:error, {module(), binary()}}
def parse_unit_name(unit_name_string, options \\ []) do
options = Keyword.put(options, :backend, unquote(backend))
Cldr.Unit.parse_unit_name(unit_name_string, options)
end
@doc """
Parse a string to create a new unit or
raises an exception.
This function attempts to parse a string
into a `number` and `unit type`. If successful
it attempts to create a new unit using
`Cldr.Unit.new/3`.
The parsed `unit type` is un-aliased against all the
known unit names for a give locale (or the current
locale if no locale is specified). The known
aliases for unit types can be returned with
`MyApp.Cldr.Unit.unit_strings_for/1` where `MyApp.Cldr`
is the name of a backend module.
## Arguments
* `unit string` is any string to be parsed and if
possible used to create a new `t:Cldr.Unit`
* `options` is a keyword list of options
## Options
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `t:Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
## Returns
* `unit` or
* raises an exception
## Examples
iex> #{inspect(__MODULE__)}.parse! "1kg"
Cldr.Unit.new!(1, :kilogram)
iex> #{inspect(__MODULE__)}.parse! "1 tages", locale: "de"
Cldr.Unit.new!(1, :day)
iex> #{inspect(__MODULE__)}.parse!("42 candela per lux")
Cldr.Unit.new!(42, "candela per lux")
iex> #{inspect(__MODULE__)}.parse!("42 millispangels")
** (Cldr.UnknownUnitError) Unknown unit was detected at "spangels"
"""
@spec parse!(binary) :: Cldr.Unit.t() | no_return()
@doc since: "3.10.0"
def parse!(unit_string, options \\ []) do
options = Keyword.put(options, :backend, unquote(backend))
Cldr.Unit.parse!(unit_string, options)
end
@doc since: "3.13.4"
@doc """
Parse a string to find a matching unit-atom.
This function attempts to parse a string and
extract the `unit type`.
The parsed `unit type` is aliased against all the
known unit names for a give locale (or the current
locale if no locale is specified). The known
aliases for unit types can be returned with
`MyApp.Cldr.Unit.unit_strings_for/1` where `MyApp.Cldr`
is the name of a backend module.
## Arguments
* `unit_name_string` is any string to be parsed and converted into a `unit type`
* `options` is a keyword list of options
## Options
* `:locale` is any valid locale name returned by `Cldr.known_locale_names/0`
or a `t:Cldr.LanguageTag` struct. The default is `Cldr.get_locale/0`
* `:backend` is any module that includes `use Cldr` and therefore
is a `Cldr` backend module. The default is `Cldr.default_backend!/0`.
* `:only` is a unit category or unit, or a list of unit categories and units.
The parsed unit must match one of the categories or units in order to
be valid. This is helpful when disambiguating parsed units. For example,
parsing "w" could be either `watts` or `:week`. Specifying `only: :duration`
would return `:week`. Specifying `only: :power` would return `:watts`
* `:except` is the oppostte of `:only`. The parsed unit must *not*
match the specified unit or category, or unit categories and units.
## Returns
* `unit_name` or
* raises an exception
## Notes
* When both `:only` and `:except` options are passed, both
conditions must be true in order to return a parsed result.
* Only units returned by `Cldr.Unit.known_units/0` can be
used in the `:only` and `:except` filters.
## Examples
iex> #{inspect(__MODULE__)}.parse_unit_name! "kg"
:kilogram
iex> #{inspect(__MODULE__)}.parse_unit_name! "w"
:watt
iex> #{inspect(__MODULE__)}.parse_unit_name! "w", only: :duration
:week
iex> #{inspect(__MODULE__)}.parse_unit_name! "m", only: [:year, :month, :day]
:month
iex> #{inspect(__MODULE__)}.parse_unit_name! "tages", locale: "de"
:day
iex> #{inspect(__MODULE__)}.parse_unit_name! "tag", locale: "de"
:day
iex> #{inspect(__MODULE__)}.parse_unit_name!("millispangels")
** (Cldr.UnknownUnitError) Unknown unit was detected at "spangels"
"""
@spec parse_unit_name!(binary) :: atom() | no_return()
def parse_unit_name!(unit_name_string, options \\ []) do
options = Keyword.put(options, :backend, unquote(backend))
Cldr.Unit.parse_unit_name!(unit_name_string, options)
end
@doc """
Returns a list of the preferred units for a given
unit, locale, use case and scope.
The units used to represent length, volume and so on
depend on a given territory, measurement system and usage.
For example, in the US, people height is most commonly
referred to in `inches`, or informally as `feet and inches`.
In most of the rest of the world it is `centimeters`.
## Arguments
* `unit` is any unit returned by `Cldr.Unit.new/2`.
* `backend` is any Cldr backend module. That is, any module
that includes `use Cldr`. The default is `Cldr.default_backend/0`
* `options` is a keyword list of options or a
`Cldr.Unit.Conversion.Options` struct. The default
is `[]`.
## Options
* `:usage` is the unit usage. for example `;person` for a unit
type of length. The available usage for a given unit category can
be seen with `Cldr.Unit.unit_category_usage/0`. The default is `nil`
* `:scope` is either `:small` or `nil`. In some usage, the units
used are different when the unit size is small. It is up to the
developer to determine when `scope: :small` is appropriate.
* `:alt` is either `:informal` or `nil`. Like `:scope`, the units
in use depend on whether they are being used in a formal or informal
context.
* `:locale` is any locale returned by `Cldr.validate_locale/2`
## Returns
* `{:ok, unit_list, formatting_options}` or
* `{:error, {exception, reason}}`
## Notes
`formatting_options` is a keyword list of options
that can be passed to `Cldr.Unit.to_string/3`. Its
primary intended usage is for localizing a unit that
decomposes into more than one unit (for example when
2 meters might become 6 feet 6 inches.) In such
cases, the last unit in the list (in this case the
inches) is formatted with the `formatting_options`.
## Examples
iex> meter = Cldr.Unit.new!(:meter, 1)
iex> #{inspect(__MODULE__)}.preferred_units meter, locale: "en-US", usage: :person_height
{:ok, [:foot, :inch], []}
iex> #{inspect(__MODULE__)}.preferred_units meter, locale: "en-US", usage: :person
{:ok, [:inch], []}
iex> #{inspect(__MODULE__)}.preferred_units meter, locale: "en-AU", usage: :person
{:ok, [:centimeter], []}
iex> #{inspect(__MODULE__)}.preferred_units meter, locale: "en-US", usage: :road
{:ok, [:foot], [round_nearest: 1]}
iex> #{inspect(__MODULE__)}.preferred_units meter, locale: "en-AU", usage: :road
{:ok, [:meter], [round_nearest: 1]}
"""
@spec preferred_units(Cldr.Unit.t(), Keyword.t()) ::
{:ok, String.t()} | {:error, {module, binary}}
def preferred_units(unit, options \\ []) do
Cldr.Unit.Preference.preferred_units(unit, unquote(backend), options)
end
@doc """
Returns a list of the preferred units for a given
unit, locale, use case and scope.
The units used to represent length, volume and so on
depend on a given territory, measurement system and usage.
For example, in the US, people height is most commonly
referred to in `inches`, or informally as `feet and inches`.
In most of the rest of the world it is `centimeters`.
## Arguments
* `unit` is any unit returned by `Cldr.Unit.new/2`.
* `backend` is any Cldr backend module. That is, any module
that includes `use Cldr`. The default is `Cldr.default_backend/0`
* `options` is a keyword list of options or a
`Cldr.Unit.Conversion.Options` struct. The default
is `[]`.
## Options
* `:usage` is the unit usage. for example `;person` for a unit
type of length. The available usage for a given unit category can
be seen with `Cldr.Unit.unit_category_usage/0`. The default is `nil`
* `:scope` is either `:small` or `nil`. In some usage, the units
used are different when the unit size is small. It is up to the
developer to determine when `scope: :small` is appropriate.
* `:alt` is either `:informal` or `nil`. Like `:scope`, the units
in use depend on whether they are being used in a formal or informal
context.
* `:locale` is any locale returned by `Cldr.validate_locale/2`
## Returns
* `unit_list` or
* raises an exception
## Examples
iex> meter = Cldr.Unit.new!(:meter, 2)
iex> #{inspect(__MODULE__)}.preferred_units! meter, locale: "en-US", usage: :person_height
[:foot, :inch]
iex> #{inspect(__MODULE__)}.preferred_units! meter, locale: "en-AU", usage: :person
[:centimeter]
iex> #{inspect(__MODULE__)}.preferred_units! meter, locale: "en-US", usage: :road
[:foot]
iex> #{inspect(__MODULE__)}.preferred_units! meter, locale: "en-AU", usage: :road
[:meter]
"""
def preferred_units!(unit, options \\ []) do
Cldr.Unit.Preference.preferred_units!(unit, unquote(backend), options)
end
@grammatical_features Cldr.Config.grammatical_features()
@grammatical_gender Cldr.Config.grammatical_gender()
@default_gender :masculine
# Generate the functions that encapsulate the unit data from CDLR
@doc false
def units_for(locale \\ unquote(backend).get_locale(), style \\ Cldr.Unit.default_style())
for locale_name <- Cldr.Locale.Loader.known_locale_names(config) do
locale_data =
locale_name
|> Cldr.Locale.Loader.get_locale(config)
|> Map.get(:units)
units_for_style = fn additional_units, style ->
Map.get(locale_data, style)
|> Enum.map(&elem(&1, 1))
|> Cldr.Map.merge_map_list()
|> Map.merge(additional_units)
|> Map.new()
end
for style <- @styles do
additional_units = additional_units.units_for(locale_name, style)
units = units_for_style.(additional_units, style)
def units_for(unquote(locale_name), unquote(style)) do
unquote(Macro.escape(units))
end
end
language_tag = Cldr.Config.language_tag(locale_name)
language = Map.fetch!(language_tag, :language)
grammatical_features = Map.get(@grammatical_features, language) || %{}
grammatical_gender = Map.get(@grammatical_gender, language) || [@default_gender]
default_gender = Enum.find(grammatical_gender, &(&1 == :neuter)) || @default_gender
def grammatical_features(unquote(locale_name)) do
unquote(Macro.escape(grammatical_features))
end
def grammatical_gender(unquote(locale_name)) do
{:ok, unquote(Macro.escape(grammatical_gender))}
end
def default_gender(unquote(locale_name)) do
{:ok, unquote(default_gender)}
end
unit_strings =
for style <- @styles do
additional_units = additional_units.units_for(locale_name, style)
units =
units_for_style.(additional_units, style)
|> Cldr.Map.prune(fn
{k, _v} when k in [:per_unit_pattern, :per, :times, :unit] ->
true
{k, _v} ->
if String.starts_with?(Atom.to_string(k), "10"), do: true, else: false
_other ->
false
end)
|> Enum.map(fn {k, v} -> {k, Cldr.Map.extract_strings(v)} end)
|> Map.new()
end
|> Cldr.Map.merge_map_list(&Cldr.Map.combine_list_resolver/3)
|> Enum.map(fn {k, v} -> {k, Enum.map(v, &String.trim/1)} end)
|> Enum.map(fn {k, v} -> {k, Enum.map(v, &String.downcase/1)} end)
|> Enum.map(fn {k, v} -> {k, Enum.uniq(v)} end)
|> Map.new()
|> Cldr.Map.invert(duplicates: :keep)
def unit_strings_for(unquote(locale_name)) do
{:ok, unquote(Macro.escape(unit_strings))}
end
end
def unit_strings_for(%LanguageTag{cldr_locale_name: cldr_locale_name}) do
unit_strings_for(cldr_locale_name)
end
def unit_strings_for(locale) do
{:error, Cldr.Locale.locale_error(locale)}
end
def units_for(%LanguageTag{cldr_locale_name: cldr_locale_name}, style) do
units_for(cldr_locale_name, style)
end
def grammatical_features(%LanguageTag{cldr_locale_name: locale_name}) do
grammatical_features(locale_name)
end
def grammatical_features(locale_name) do
{:error, Cldr.Locale.locale_error(locale_name)}
end
def grammatical_gender(%LanguageTag{cldr_locale_name: locale_name}) do
grammatical_gender(locale_name)
end
def grammatical_gender(locale_name) do
{:error, Cldr.Locale.locale_error(locale_name)}
end
def default_gender(%LanguageTag{cldr_locale_name: locale_name}) do
default_gender(locale_name)
end
def default_gender(locale_name) do
{:error, Cldr.Locale.locale_error(locale_name)}
end
end
end
end
end