Packages
ex_cldr
0.4.0
2.47.5
2.47.4
2.47.3
2.47.2
2.47.1
2.47.0
2.46.0
2.45.2
2.45.1
2.45.0
2.44.1
2.44.0
2.43.2
2.43.1
2.43.0
2.42.0
2.41.1
2.41.0
2.40.4
2.40.3
2.40.2
2.40.1
2.40.0
2.39.2
2.39.1
2.39.0
2.38.1
2.38.0
2.37.5
2.37.4
2.37.3
retired
2.37.2
2.37.1
2.37.0
2.36.0
2.35.1
2.35.0
retired
2.34.2
2.34.1
2.34.0
2.33.2
2.33.1
2.33.1-rc.0
2.33.0
2.32.1
2.32.0
2.31.0
2.30.0
2.29.0
2.28.0
2.27.1
2.27.0
retired
2.26.3
2.26.2
2.26.1
2.26.0
2.25.0
2.24.2
2.24.1
2.24.0
2.24.0-rc.6
2.24.0-rc.5
2.24.0-rc.4
2.24.0-rc.3
2.24.0-rc.2
2.24.0-rc.1
2.24.0-rc.0
2.23.2
2.23.1
2.23.0
2.22.1
2.22.0
2.21.0
2.20.0
2.20.0-rc.3
2.20.0-rc.2
2.20.0-rc.1
2.20.0-rc.0
2.19.1
2.19.0
2.18.2
2.18.1
2.18.0
2.18.0-rc.0
2.17.2
2.17.1
2.17.0
2.16.2
2.16.1
2.16.1-rc.0
2.16.0
2.15.0
2.14.1
2.14.0
2.14.0-rc.0
2.13.0
2.12.1
2.12.0
2.11.1
2.11.0
2.10.2
2.10.1
2.10.0
retired
2.9.0
2.8.1
2.8.0
2.7.2
2.7.1
2.7.0
2.6.2
2.6.1
2.6.0
2.5.0
2.4.3
2.4.2
2.4.1
2.4.0
2.3.2
2.3.1
2.3.0
2.2.7
2.2.6
2.2.5
2.2.4
2.2.3
2.2.2
2.2.1
2.2.0
2.1.0
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
2.0.0-rc.3
retired
2.0.0-rc.2
retired
2.0.0-rc.1
retired
2.0.0-rc.0
retired
1.8.2
1.8.1
1.8.0
1.7.1
1.7.0
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.2
1.5.1
1.5.0
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
retired
1.4.0-rc.3
retired
1.4.0-rc.2
retired
1.4.0-rc.1
retired
1.4.0-rc.0
retired
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.0
1.0.0-rc.3
retired
1.0.0-rc.2
retired
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.13.1
0.13.0
0.12.2
retired
0.12.1
retired
0.12.0
retired
0.11.0
retired
0.10.0
retired
0.9.0
retired
0.8.3
retired
0.8.2
retired
0.8.1
retired
0.8.0
retired
0.7.0
retired
0.6.2
retired
0.6.1
retired
0.6.0
retired
0.5.2
retired
0.5.1
retired
0.5.0
retired
0.4.2
retired
0.4.1
retired
0.4.0
retired
0.3.0
retired
0.2.1
retired
0.2.0
retired
0.1.3
retired
0.1.2
retired
0.1.1
retired
0.1.0
retired
0.0.20
retired
0.0.19
retired
0.0.18
retired
0.0.17
retired
0.0.16
retired
0.0.15
retired
0.0.14
retired
0.0.13
retired
0.0.12
retired
0.0.11
retired
0.0.10
retired
0.0.8
retired
0.0.7
retired
0.0.6
retired
0.0.5
retired
0.0.4
retired
0.0.3
retired
Common Locale Data Repository (CLDR) functions for Elixir to localize and format numbers, dates, lists, messages, languages, territories and units with support for over 700 locales for internationalized (i18n) and localized (L10N) applications.
Retired package: Deprecated
Current section
Files
Jump to
Current section
Files
lib/cldr/number/rbnf/config.ex
defmodule Cldr.Rbnf.Config do
@moduledoc """
Rules Base Number Formatting Configuration management.
During the process of consolidating the various CLDR files into
a standard format that is easily digestible for Cldr, these functions
are used to do the parsing and normalising of RBNF data.
"""
alias Cldr.Rbnf.Rule
@default_radix 10
@data_dir Path.join(Cldr.Config.cldr_home, "data") <> "/cldr-rbnf"
@rbnf_dir Path.join(@data_dir, "rbnf")
@doc """
Returns the directory where the RBNF data is stored
## Example
iex> Cldr.Rbnf.Config.rbnf_dir =~ "/cldr-rbnf/rbnf"
true
"""
@spec rbnf_dir :: String.t
def rbnf_dir do
@rbnf_dir
end
if File.exists?(@rbnf_dir) do
@rbnf_locales Enum.map(File.ls!(@rbnf_dir), &Path.basename(&1, ".json"))
else
@rbnf_locales []
end
@doc """
Returns a list of the locales for which there is an rbnf rule set
Relies on the presence of downloaded CLDR data. This function is
usefully primarily to a Cldr library developer.
## Example
iex> Cldr.Rbnf.Config.rbnf_locales
["af", "am", "ar", "az", "be", "bg", "bs", "ca", "cs", "cy", "da", "de-CH",
"de", "ee", "el", "en", "eo", "es-419", "es", "et", "fa-AF", "fa", "fi", "fil",
"fo", "fr-BE", "fr-CH", "fr", "ga", "he", "hi", "hr", "hu", "hy", "id", "is",
"it", "ja", "ka", "kl", "km", "ko", "ky", "lo", "lt", "lv", "mk", "ms", "mt",
"my", "nb", "nl", "nn", "pl", "pt-PT", "pt", "ro", "root", "ru", "se", "sk",
"sl", "sq", "sr-Latn", "sr", "sv", "ta", "th", "tr", "uk", "vi", "yue",
"zh-Hant", "zh"]
"""
@spec rbnf_locales :: [String.t] | []
def rbnf_locales do
@rbnf_locales
end
@doc """
Returns the list of locales that is the intersection of
`Cldr.known_locales/0` and `Cldr.Rbnf.rbnf_locales/0`
This list is therefore the set of known locales for which
there are rbnf rules defined.
## Example
iex> Cldr.Rbnf.Config.known_locales
["lo", "eo", "ja", "el", "fo", "hu", "yue", "fil", "sq", "cy", "da", "sv", "ee",
"et", "ta", "nl", "vi", "nb", "lv", "id", "pt-PT", "fa-AF", "lt", "my",
"sr-Latn", "cs", "ms", "fa", "bg", "es", "en", "af", "mt", "am", "ca", "mk",
"ro", "de-CH", "ka", "root", "hr", "nn", "hy", "pt", "se", "he", "ga", "sr",
"hi", "ky", "ko", "zh-Hant", "kl", "km", "sk", "ru", "zh", "de", "fi", "it",
"be", "pl", "az", "tr", "is", "fr-CH", "es-419", "th", "fr-BE", "fr", "sl",
"bs", "uk", "ar"]
"""
def known_locales do
MapSet.intersection(MapSet.new(Cldr.known_locales), MapSet.new(rbnf_locales()))
|> MapSet.to_list
end
@doc """
Returns the rbnf rules for a `locale` or `{:error, :rbnf_file_not_found}`
* `locale` is any locale returned by `Rbnf.known_locales/0`.
Note that `for_locale/1` does not raise if the locale does not exist
like the majority of `Cldr`. This is by design since the set of locales
that have rbnf rules is substantially less than the set of locales
supported by `Cldr`.
## Example
iex> Cldr.Rbnf.Config.for_locale("en") |> Map.keys
[:OrdinalRules, :SpelloutRules]
"""
@spec for_locale(Locale.t) :: %{} | {:error, :rbnf_file_not_found}
def for_locale(locale) do
if File.exists?(locale_path(locale)) do
locale
|> locale_path
|> File.read!
|> Poison.decode!
|> Map.get("rbnf")
|> Map.get("rbnf")
|> rules_from_rule_sets
else
{:error, :rbnf_file_not_found}
end
end
defp rules_from_rule_sets(json) do
Enum.map(json, fn {group, sets} ->
{String.to_atom(group), rules_from_one_group(sets)}
end)
|> Enum.into(%{})
end
defp rules_from_one_group(sets) do
Enum.map(sets, fn {set, rules} ->
access = access_from_set(set)
{function_name_from(set), %{access: access, rules: rules_from(rules)}}
end)
|> Enum.into(%{})
end
defp access_from_set(<<"%%", _rest::binary>>), do: :private
defp access_from_set(_), do: :public
defp rules_from(rules) do
Enum.map(rules, fn {name, rule} ->
{base_value, radix} = radix_from_name(name)
%Rule{base_value: base_value, radix: radix, definition: remove_trailing_semicolon(rule)}
end)
|> sort_rules
|> set_range
|> set_divisor
end
defp sort_rules(rules) do
Enum.sort(rules, fn (a, b) ->
cond do
is_binary(a.base_value) -> true
is_binary(b.base_value) -> false
a.base_value < b.base_value -> true
true -> false
end
end)
end
defp radix_from_name(name) do
case String.split(name, "/") do
[base_value, radix] ->
{to_integer(base_value), to_integer(radix)}
[base_value] ->
{to_integer(base_value), @default_radix}
end
end
@spec locale_path(binary) :: String.t
defp locale_path(locale) when is_binary(locale) do
Path.join(rbnf_dir(), "/#{locale}.json")
end
defp to_integer(nil) do
nil
end
defp to_integer(value) do
with {int, ""} <- Integer.parse(value) do
int
else
_ -> value
end
end
defp remove_trailing_semicolon(text) do
String.replace_suffix(text, ";", "")
end
# If the current rule is numeric and the next rule is numeric then
# the next rules value determines the upper bound of the validity
# of the current rule.
#
# ie. "0": "one;"
# "10": "ten;"
#
# Means that rule "0" is applied for values up to but not including "10"
defp set_range([rule | [next_rule | rest]]) do
[%Rule{rule | range: range_from_next_rule(rule.base_value, next_rule.base_value)}] ++ set_range([next_rule] ++ rest)
end
defp set_range([rule | []]) do
[%Rule{rule | :range => :undefined}]
end
defp range_from_next_rule(rule, next_rule) when is_number(rule) and is_number(next_rule) do
next_rule
end
defp range_from_next_rule(_rule, _next_rule) do
:undefined
end
defp set_divisor([rule]) do
[%Rule{rule | divisor: divisor(rule.base_value, rule.radix)}]
end
defp set_divisor([rule | rest]) do
[%Rule{rule | divisor: divisor(rule.base_value, rule.radix)} | set_divisor(rest)]
end
# Thanks to twitter-cldr:
# https://github.com/twitter/twitter-cldr-rb/blob/master/lib/twitter_cldr/formatters/numbers/rbnf/rule.rb
defp divisor(base_value, radix) when is_integer(base_value) and is_integer(radix) do
exponent = if base_value > 0 do
Float.ceil(:math.log(base_value) / :math.log(radix)) |> trunc
else
1
end
divisor = if exponent > 0 do
:math.pow(radix, exponent) |> trunc
else
1
end
if divisor > base_value do
:math.pow(radix, exponent - 1) |> trunc
else
divisor
end
end
defp divisor(_base_value, _radix) do
nil
end
defp function_name_from(set) do
set
|> String.trim_leading("%")
|> String.replace("-","_")
|> String.to_atom
end
end