From 495b15cee7b10586f594b3c5ff7478981eeb64a7 Mon Sep 17 00:00:00 2001 From: Kip Cole Date: Sat, 8 Oct 2022 08:30:37 +0800 Subject: [PATCH] Add unambiguous narrow symbols to currency strings --- CHANGELOG.md | 8 ++++ lib/cldr/backend.ex | 6 ++- lib/cldr/currency.ex | 74 +++++++++++++++++++++-------------- mix.exs | 2 +- mix.lock | 12 +++--- test/cldr_currencies_test.exs | 8 ++++ 6 files changed, 72 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd1791b..6e23546 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Cldr_Currencies v2.14.2 + +This is the changelog for Cldr_Currencies v2.14.2 released on October 8th, 2022. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_currencies/tags) + +### Bug Fixes + +* Fix `Cldr.Currency.currency_strings/2` to include narrow symbols. Note that where duplicate symbols exist (same symbol for more than one currency) they are are omitted from the list of strings since they are ambiguous (unless one of them is a historic currency in which case the current currency is kept and the historic removed). + ## Cldr_Currencies v2.14.1 This is the changelog for Cldr_Currencies v2.14.1 released on June 8th, 2022. For older changelogs please consult the release tag on [GitHub](https://github.com/elixir-cldr/cldr_currencies/tags) diff --git a/lib/cldr/backend.ex b/lib/cldr/backend.ex index 707dda1..97a38f6 100644 --- a/lib/cldr/backend.ex +++ b/lib/cldr/backend.ex @@ -515,9 +515,10 @@ defmodule Cldr.Currency.Backend do |> Map.new() currency_strings = - for {currency_code, currency} <- Cldr.Config.currencies_for!(locale_name, config) do + for {currency_code, currency} <- currencies do strings = - ([currency.name, currency.symbol, currency.code] ++ Map.values(currency.count)) + [currency.name, currency.symbol, currency.code] + |> Kernel.++(Map.values(currency.count)) |> Enum.reject(&is_nil/1) |> Enum.map(&String.downcase/1) |> Enum.map(&String.trim_trailing(&1, ".")) @@ -530,6 +531,7 @@ defmodule Cldr.Currency.Backend do Cldr.Currency.invert_currency_strings(currency_strings) |> Cldr.Currency.remove_duplicate_strings(currencies) |> Map.new() + |> Cldr.Currency.add_unique_narrow_symbols(currencies) def currencies_for_locale( %LanguageTag{cldr_locale_name: unquote(locale_name)}, diff --git a/lib/cldr/currency.ex b/lib/cldr/currency.ex index 4d0fa55..bdb3d12 100644 --- a/lib/cldr/currency.ex +++ b/lib/cldr/currency.ex @@ -1248,7 +1248,7 @@ defmodule Cldr.Currency do * `{:ok, currency_string_map}` or - * raises an exception + * raises an exception. ## Example @@ -1549,31 +1549,9 @@ defmodule Cldr.Currency do !annotated?(currency) end - # Sort the list by string. If the string is the same - # then sort historic currencies after the current one - - @doc false - def string_comparator({k, v1}, {k, v2}, currencies) do - cond do - historic?(currencies[v1]) -> - false - - historic?(currencies[v2]) -> - true - - true -> - raise "String #{inspect(k)} has two current currencies of #{inspect(v1)} and " <> - "#{inspect(v2)}." - end - end - - def string_comparator({k1, _v1}, {k2, _v2}, _currencies) do - k1 < k2 - end - # Its possible that more than one currency will have a string # in common with another currency. One example is `:AFA` and - # `:AFN`. As in this csae, its most common when a country + # `:AFN`. As in this case, its most common when a country # changes to a new currency with the same name. # The strategy is to remove the duplicate string from the @@ -1582,18 +1560,37 @@ defmodule Cldr.Currency do @doc false def remove_duplicate_strings(strings, currencies) do strings - |> Enum.sort(fn a, b -> string_comparator(a, b, currencies) end) + |> Enum.sort(fn a, b -> string_comparator(a, b) end) |> remove_duplicates(currencies) end + def string_comparator({k1, _v1}, {k2, _v2}) do + k1 < k2 + end + + # If the same code and one is historic and the other is current then + # keep the current one. If they are both current, then omit the string + # because it is ambiguous. + + defp remove_duplicates([], _currencies) do + [] + end + defp remove_duplicates([{_, _}] = currency, _currencies) do currency end - # Same string, different code -> omit the 2nd one since - # we sort historic currencies after the current ones - defp remove_duplicates([{c1, code1} | [{c1, _code2} | rest]], currencies) do - remove_duplicates([{c1, code1} | rest], currencies) + defp remove_duplicates([{c1, code1} | [{c1, code2} | rest]], currencies) do + cond do + historic?(currencies[code1]) && current?(currencies[code2]) -> + remove_duplicates([{c1, code2} | rest], currencies) + + current?(currencies[code1]) && historic?(currencies[code2]) -> + remove_duplicates([{c1, code1} | rest], currencies) + + true -> + remove_duplicates(rest, currencies) + end end # Not a duplicate, process the rest of the list @@ -1609,6 +1606,25 @@ defmodule Cldr.Currency do |> List.flatten() end + # Add the narrow currency symbols iff they don't duplicate an + # existing string + + @doc false + def add_unique_narrow_symbols(currency_strings, currencies) do + Enum.reduce(currencies, currency_strings, fn {currency_code, currency}, strings -> + cond do + is_nil(currency.narrow_symbol) -> + strings + + Map.has_key?(strings, currency.narrow_symbol) -> + strings + + true -> + Map.put(strings, String.downcase(currency.narrow_symbol), currency_code) + end + end) + end + defp currency_already_defined_error(code) do "Currency #{inspect(code)} is already defined." end diff --git a/mix.exs b/mix.exs index d9bfe82..9dd70d6 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule Cldr.Currencies.MixProject do use Mix.Project - @version "2.14.1" + @version "2.14.2" def project do [ diff --git a/mix.lock b/mix.lock index e7f5b38..c03a4fc 100644 --- a/mix.lock +++ b/mix.lock @@ -1,16 +1,16 @@ %{ "benchee": {:hex, :benchee, "1.1.0", "f3a43817209a92a1fade36ef36b86e1052627fd8934a8b937ac9ab3a76c43062", [:mix], [{:deep_merge, "~> 1.0", [hex: :deep_merge, repo: "hexpm", optional: false]}, {:statistex, "~> 1.0", [hex: :statistex, repo: "hexpm", optional: false]}], "hexpm", "7da57d545003165a012b587077f6ba90b89210fd88074ce3c60ce239eb5e6d93"}, - "cldr_utils": {:hex, :cldr_utils, "2.17.1", "d5532ccfbe4b39cb652ba4566571324278344a6a2fb4500dac213ce8e123732f", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "052e0c2cf5ee801018580d69939b25528730d73ea05a05cb2c0e0a8204856d76"}, + "cldr_utils": {:hex, :cldr_utils, "2.19.1", "5a7bcd2f2fd432c548e494e850bba8a9e838f1b10202f682ea1d9809d74eff31", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:decimal, "~> 1.9 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}], "hexpm", "fbd10f79363e70f3d893ab21e195f444ca87c2c80120b5911761491da4489620"}, "decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"}, "deep_merge": {:hex, :deep_merge, "1.0.0", "b4aa1a0d1acac393bdf38b2291af38cb1d4a52806cf7a4906f718e1feb5ee961", [:mix], [], "hexpm", "ce708e5f094b9cd4e8f2be4f00d2f4250c4095be93f8cd6d018c753894885430"}, - "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"}, + "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, "earmark": {:hex, :earmark, "1.4.14", "d04572cef64dd92726a97d92d714e38d6e130b024ea1b3f8a56e7de66ec04e50", [:mix], [{:earmark_parser, ">= 1.4.12", [hex: :earmark_parser, repo: "hexpm", optional: false]}], "hexpm", "df338b8b1852ee425180b276c56c6941cb12220e04fe8718fe4acbdd35fd699f"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.21", "7299db854f6d63730c15c8a781862889bb0fbf4432d7c306b3e63ce825d64baa", [:mix], [], "hexpm", "60664e1bdf7a02d8cbec2ac1d5b6fe0a68cf1d749ba955990d647346fac421e4"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.28", "0bf6546eb7cd6185ae086cbc5d20cd6dbb4b428aad14c02c49f7b554484b4586", [:mix], [], "hexpm", "501cef12286a3231dc80c81352a9453decf9586977f917a96e619293132743fb"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, "eternal": {:hex, :eternal, "1.2.1", "d5b6b2499ba876c57be2581b5b999ee9bdf861c647401066d3eeed111d096bc4", [:mix], [], "hexpm", "b14f1dc204321429479c569cfbe8fb287541184ed040956c8862cb7a677b8406"}, - "ex_cldr": {:hex, :ex_cldr, "2.28.0", "8f7a8c70a49dc31f656eb02d4c6280550ab52abd340406e8341dd4ba2390798d", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.17", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "564608c4a344c9cca54874e95fb77cd7149f593ccf522db5cbe8943c0b183630"}, - "ex_doc": {:hex, :ex_doc, "0.28.2", "e031c7d1a9fc40959da7bf89e2dc269ddc5de631f9bd0e326cbddf7d8085a9da", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "51ee866993ffbd0e41c084a7677c570d0fc50cb85c6b5e76f8d936d9587fa719"}, - "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"}, + "ex_cldr": {:hex, :ex_cldr, "2.33.2", "8adc4df3985e7f5d1d55cbbf72f993569de20eff5012ff3ea9412753961d4c00", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}, {:certifi, "~> 2.5", [hex: :certifi, repo: "hexpm", optional: true]}, {:cldr_utils, "~> 2.18", [hex: :cldr_utils, repo: "hexpm", optional: false]}, {:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.19", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: true]}], "hexpm", "fd81a7147b4ed86c0c44c0251444cb8d1defccc7b33b89067ca1635f23e9fbf8"}, + "ex_doc": {:hex, :ex_doc, "0.28.5", "3e52a6d2130ce74d096859e477b97080c156d0926701c13870a4e1f752363279", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "d2c4b07133113e9aa3e9ba27efb9088ba900e9e51caa383919676afdf09ab181"}, + "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, "makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"}, "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, diff --git a/test/cldr_currencies_test.exs b/test/cldr_currencies_test.exs index 5fe56c5..b148bdf 100644 --- a/test/cldr_currencies_test.exs +++ b/test/cldr_currencies_test.exs @@ -75,4 +75,12 @@ defmodule Cldr.Currency.Test do test "Currency from binary locale" do assert _currency = Cldr.Currency.currency_from_locale("fr") end + + test "Narrow symbols are included in currency strings if they are not ambiguous" do + assert Cldr.Currency.currency_strings!("en", MyApp.Cldr) + |> Enum.filter(fn {_k, v} -> v == :ZAR end) == + [{"south african rand", :ZAR}, {"r", :ZAR}, {"zar", :ZAR}] + + assert Cldr.Currency.currency_strings!("en", MyApp.Cldr) |> Map.get("$") == :USD + end end