kip

kip

ex_cldr Core Team

ex_money is a package to manage a money data type and provide localised formatting, arithmetic, exchange rates, basic financial calculations and serialization with a special attention on preserving precision.

CLDR data drives the localisation capabilities. As a result ex_money knows about each currencies precision, separators, grouping and symbols in any of about 500 locales.

Version 3.2.4 is out this week with a new ability to parse money strings. Some examples follow:

  # These are the strings available for a given currency
  # and locale that are recognised during parsing
  iex> Cldr.Currency.strings_for_currency :AUD, "de"
  ["aud", "au$", "australischer dollar", "australische dollar"]

  # Parsing can be localised
  iex> Money.parse "12 346 dollar australien", locale: "fr"
  #Money<:AUD, 12346>

  iex> Money.parse "A$ 12346", locale: "en"
  #Money<:AUD, 12346>

  # Note that the decimal separator in the "de" locale
  # is a `.`
  iex> Money.parse "AU$ 12346,45", locale: "de"
  #Money<:AUD, 12346.45>

  # Round trip formatting is supported
  iex> {:ok, string} = Cldr.Number.to_string 1234, Money.Cldr, currency: :AUD
  {:ok, "A$1,234.00"}
  iex> Money.parse string
  #Money<:AUD, 1234.00>

  # Fuzzy matching is possible
  iex> Money.parse("100 eurosports", fuzzy: 0.8)
  #Money<:EUR, 100>

  iex> Money.parse("100 eurosports", fuzzy: 0.9)
  {:error,
   {Money.Invalid, "Unable to create money from \"eurosports\" and \"100\""}}

  # Eligible currencies can be filtered by type
  iex> Money.parse("100 eurosports", fuzzy: 0.8, currency_filter: [:current, :tender])
  #Money<:EUR, 100>

Showing Posts 15 to 6

kip

kip OP

ex_cldr Core Team

I’ve just published the first in a new series of libraries focused on input. First up is ex_money_input. Soon to come is one for plain numbers (which will be part of a new library, localize_inputs).

It’s the form-input layer for the elixir-money family. It rounds out the trio: ex_money for the data type, ex_money_sql for Ecto persistence, and now ex_money_input for users actually typing a value into a form.

Example component usage

<.money_input
  form={@form}
  field={:price}
  default_currency={:USD}
  currency_picker={true}
  preferred_currencies={[:USD, :EUR, :GBP, :JPY]}
/>

Features

  • A <.money_input> HEEx component with a paired <.currency_picker>. Locale determines the separators, symbol position, fractional digits (USD 2, JPY 0, BHD 3), and even the digit system (Arabic, Persian).
  • A small JS hook wrapping AutoNumeric (MIT, Alexandre Bonneau) for live formatting and cursor preservation. Optional — without it the input still works server-side. But AutoNumeric does a great job on the UX side, respecting and understanding different locale grouping and fraction separators.
  • An Ecto changeset bridge (cast_money/3, validate_money/3) with currency-aware precision and bounds.
  • A headless cast/validate/currency layer that’s usable without Phoenix.

Money Input Playground

There’s a Plug-based visualizer that demos every component across CLDR locales and currencies.

It’s deployed at https://elixir-money-input.fly.dev so you can explore its potential use for your projects.

Links

Docs: https://hexdocs.pm/ex_money_input
Source: https://github.com/ex-money/money_input
Integration guide: https://hexdocs.pm/ex_money_input/integration.html

Feedback welcome — particularly on the locales you actually ship to. The CLDR coverage is wide but there’s always a corner case.

webuhu

webuhu

We shipped new version of ex_money to production last week - without any issues.
Thanks again for your great work.

kip

kip OP

ex_cldr Core Team

Thanks for the feedback - and I’m glad it’s positive! I’m hoping others have a similar experience so I can confidently publish the format 6.0.0 version soon.

jswanner

jswanner

Hey @kip,

After upgrading to ex_money 6.0.0-rc.0 I was able to drop all the ex_cldr* libraries, and everything is working great!

kip

kip OP

ex_cldr Core Team

Finally. finally. ex_money is updated to be based upon localize, not ex_cldr.

Updated libraries

I’m definitely looking for any feedback on ex_money before I publish the final 6.0 release.

Changes

Overall there are no functional changes, only platform changes:

  • add localize
  • remove ex_cldr
  • move all custom and private currency registry functions to Money.Currency. They were removed from Localize.Currency. This is a much cleaner responsibility model.
  • remove gringotts optional dependency
  • remove :json_library configuration (standardise on :json)
  • requires at least Elixir 1.17
kip

kip OP

ex_cldr Core Team

ex_money just hit a million downloads on hex.pm. Small beer in comparison to its older sibling money but still - thank you to everyone who has found value in it and given it your support.

First commit was June 19, 2016 so it’s been seven years in the making :slight_smile: The last release was 3 weeks ago and there have been no issues raised since March. So its in good shape, still under active support and feature requests are always welcome.

kip

kip OP

ex_cldr Core Team

ex_money version 5.11.0 has been published. This release adds support for ISO 24165 digital tokens (crypto currencies. The changelog entry is:

Money Enhancements

  • Adds support for ISO 24165 Digital Tokens (crypto currency). Digital Token-based money behaves the same as currency-based money with the following exceptions due to limited data availability:

    • Digital token names are not localized (there is no localised data available in CLDR)
    • Digital token names are not pluralized (also because there is no localised data available)
    • Digital token amounts are never rounded (there is no data available to standardise on rounding rules or the number of fractional digits to round to)

ex_money version 2.11.0 depends on ex_cldr_numbers 2.27.0 that provides the support for formatting numbers and currencies. The changelog entry is:

Cldr Numbers Enhancements

  • Add support for formatting numbers representing ISO 24165 Digital Tokens (aka crypto currencies). The behaviour follows that for currency formatting. Given that the digital token registry does not contain fraction precision data or pluralised or localised token names, the formatting of digital tokens amounts is not localized beyond formatting the number itself.
kip

kip OP

ex_cldr Core Team

Thanks to some prompting from @ayrat555, I did some further research into supporting crypto currencies in ex_money.

In September, ISO 24165 was introduced to standardise the registration and unique identification of digital tokens (aka “crypto currencies”). This significantly increases the ability to integrate crypto into ex_money as a first-class citizen along side ISO 4217 currencies.

The first step is to make the DTIF registry data available in Elixir. This is now done with the initial release of the library digital_token. The repo is at GitHub - ex-money/digital_token: Elixir integration for ISO 24165 Digital Tokens through the DTIF registry data · GitHub.

Next step is to integrate digital_token into ex_money without compromising any of the guiding principles. Digital tokens don’t have standard definitions of digits of precision or rounding rules for example. And there is no CLDR translation data available for them either.

As always, comments, suggestions, bug reports and PRs are most welcome.

kip

kip OP

ex_cldr Core Team

ex_money version 5.1.0 is out today with a primary focus on parsing strings that have a money amount and a currency. In addition, exchange rate HTTPS requests now properly verify the certificate.

In prior versions, parsing a string that had no currency detected would error:

iex> Money.parse("100")
{:error, {Money.Invalid,
  "A currency code, symbol or description must be specified but was not found in \"100\""}}

In this version, the locale of the current process or the provided locale will be used to derive the currency in use for that locale if no currency is detected in the string. For example:

# Specifying a locale will derive the
# currency if none if detected in the
# string
iex> Money.parse("100", locale: "en")
#Money<:USD, 100>

# If no `:locale` is specified the locale of the current
# process is used which should simplify a lot
# of workflows
iex> Money.parse("100")
#Money<:USD, 100>

iex> Money.parse("100", locale: "en-AU")
#Money<:AUD, 100>

iex> assert Money.parse("100", locale: "de")
#Money<:EUR, 100>

# Traditional Chinese in HK implies HK dollars
hex> Money.parse("100", locale: "zh-Hant-hk")                                                                  
#Money<:HKD, 100>

# Traditional Chinese implies New Taiwan dollars
iex> Money.parse("100", locale: "zh-Hant")   
#Money<:TWD, 100>

# Simplified Chinese implies Chinese RMB
iex> Money.parse("100", locale: "zh-Hans")
#Money<:CNH, 100>

# of course detecting the currency in the
# string still applies
iex> Money.parse("12346.45 Australian dollars")
#Money<:AUD, 12346.45>

# Using the locale to derive the currency can be
# disabled by setting `default_currency: false`
# ie the actual `false`, not `nil`
iex> Money.parse("100", default_currency: false) ==
{:error, {Money.Invalid,
  "A currency code, symbol or description must be specified but was not found in \"100\""}}

Bonus content

If you got this far, then thanks! Here’s how the regional override and currency in a more complex language tag interacts with currency parsing:

# A locale that has a regional override. The regional override
# takes precedence and hence the currency is USD
iex> Money.parse("100", locale: "zh-Hans-u-rg-uszzzz")    
#Money<:USD, 100>

# A locale that has a regional override and a currency
# override uses the currency override as precedent over
# the regional override. In this case, EUR
iex> Money.parse("100", locale: "zh-Hans-u-rg-uszzzz-cu-eur") 
#Money<:EUR, 100>
chouzar

chouzar

I tried both almost a year ago and ex_money resulted to be way more precise for my needs (thanks to decimal). Not sure how they compare today but my suggestion is that you try some arithmetic operations on both.

Update: If I remember correctly, it had to do with the precision I think money had fixed decimals per currency while ex_money didn’t had those limitations. I could be very wrong though.

Where Next? Top

Trending in Announcing Top

type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
woylie
I released Doggo, a collection of unstyled Phoenix components. https://github.com/woylie/doggo Features Unstyled Phoenix components....
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
ahamez
Hi everyone, I’ve been working on this protobuf library for 3 years. We use it in the company I work for, EasyMile, to communicate with ...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
kip
I’ll shortly be launching Text, a nascent text analysis library. Current functionality In this early version (not ready for prime time) ...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews