Ex_cldr - Common Locale Data Repository (CLDR) functions for Elixir

CLDR 48 was released last week which has triggered new versions of several of the core ex_cldr libraries. Here’s a summary of newsworthy changes:

Ex_cldr

Bug Fixes

  • Parsing language tags with the und (unknown) language now correctly substituted for a known language name if one can be found in Cldr.Locale.likely_subtags/0. For example:
iex> Cldr.validate_locale("und-TW")
{:ok, TestBackend.Cldr.Locale.new!("zh-Hant-TW")}
  • The :gettext_locale_name field of a t:Cldr.LanguageTag.t/0 is now set exactly as returned from Gettext.known_locale_names/1. Previously it was being tranformed to a BCP 47 format locale (replacing “_” with “-”). That is no longer the case.

  • Territory containment was previously not considering nested containers and is now doing so. For example, territory “019” (Americas) includes “419” (Latin America and the Carribbean) but “419” was not appearing in the list for “019” since CLDR categorises “grouping” territories separately. This should not affect any consumers, only library writers.

Enhancements

  • Update to CLDR 48 data.

  • Add Cldr.Locale.Match.best_match/2 and Cldr.Locale.Match.match_distance/3 to implement the CLDR Language Matching algorithm. This is a more formal and testable approach that the previous mechanism. This new function will be use to implement better matching between a known CLDR locale name and supported Gettext locale names. Therefore it is possible that the gettext_locale_name field of a t:Cldr.LanguageTag.t/0 may change with this release.

Cldr Numbers

  • Adds Cldr.Number.to_ratio_string/3 to format numbers as a rational string. Numbers can also be formatted as an integer and a ratio. Since different rendering systems (browsers, terminals etc) reproduce ratios with differing fidelity, there are options to format the ratio as a precomposed fraction, super- and subscript numerals separated by a fraction slash or normal numerals separated by a fraction slash.

  • For number systems other than Latn, the :prefer: :precomposed and prefer: :super_sub options have no effect.

Examples

Function call Result
Cldr.Number.to_ratio_string(0.75) {:ok, "3⁄4"}
Cldr.Number.to_ratio_string(0.75, prefer: :super_sub) {:ok, "¹⁄₂"}
Cldr.Number.to_ratio_string(0.75, prefer: :precomposed). {:ok, "½"}
Cldr.Number.to_ratio_string(0.875, prefer: [:precomposed, :super_sub]) {:ok, "⅞"}
Cldr.Number.to_ratio_string(3.875, prefer: [:precomposed, :super_sub]) {:ok, "3\u2060⅞"}
Cldr.Number.to_ratio_string(0.923, prefer: [:precomposed, :super_sub]) {:ok, "⁹⁄₁₀"}

Cldr Dates Times

Breaking Changes

  • Changes in the implemementation of time zone formatting may result in different (but semantically the same) strings for formats that include time zone information. See Bug Fixes below.

Bug Fixes

  • Fixes the generation of time zone formats to be in accordance with CLDR Time Zone Names. This is particularly true of the following time zone formats:

    • Generic non-location format (eg “Pacific Time”, “PT”)
    • Generic partial location format (eg “Pacific Time (Canada)”)
    • Generic location format (eg “France Time”, “Adelaide Time”)
    • Specific non-location format (eg “Pacific Standard Time”, “PST”)
    • Localized GMT format (eg “GMT+03:30”, “Гринуич+03:30”, “GMT+?”)
  • Fixes Cldr.DateTime.Relative.to_string/3 when the relative value is an integer of 2 or -2 and the locale provides a specific word for that value. For example, in English there are words for 1 day in advance or behind (“today” and “yesterday”). When specifing 2 days ago, English has no specific word so the result is “2 days ago”. In German the result is “vorgestern”. Similary for the English “in 2 days”, the German result will be “übermorgen”.

Enhancements

  • Updates to CLDR 48 data.

  • Adds Cldr.DateTime.Format.gmt_unknown_format/1 to return a string representing an unknown GMT offset.

  • Adds style: :at to Cldr.DateTime.Relative.to_string/2. This allows formatting of string like “tomorrow at 3:30 PM”. The default is style: :standard.

  • Significant improvement in support of date time skeletons. Skeletons are a flexible way to express desired formatting in a locale-indepdendent way.

  • Support is added for the “j”, “J” and “C” input skeleton symbols which will be substituted with the locales preferred hour formats. These changes also improve implicit format generation derived from whatever date and time data is passed to the Cldr.Date.to_string/3, Cldr.Time.to_string/3, Cldr.DateTime.to_string/3 functions.

Cldr Calendars

Primarily bug fixes to the Julian calendar and enhancements to make the Julian calendar configurable (in history, the Julian calendar new year has celebrated at different times of year).

Bug Fixes

  • Fix year/1, month/2 and days_in_month/2 for Julian calendars.

  • CLDR 48 fixes the dates for some Japanese eras.

Enhancements

  • Use CLDR 48 calendar data. The primary change for calendars is to the era dates for the Japanese calendar.

  • Adds use Cldr.Calendar.Julian, new_year_starting_month_and_day: {month_of_year, day_of_month} to allow modelling Julian calendars that don’t start on January 1st.

  • Adds Cldr.Calendar.convert/2 which converts either a date or a date range to another calendar.

Cldr Calendars Japanese

Bug Fixes

  • Several era dates were fixed in CLDR 48.

  • The calendar_year/3 callback was fixed to return the regnal year (year of the reign of the then-current emperor) as expected by date time formatting.

Other library updates

These are updates primarily to be compatible with CLDR 48

Evolution of ex_cldr

Work continues on localize as the “version 3” of ex_cldr. The objective is to get the initial release covering the core, numbers, calendars and date/times released in the first quarter of 2026.

It’s my intention to continue to maintain ex_cldr and friends for as long as there is usage and bug reports. However I hope this will be the last update for ex_cldr to use a new version of CLDR data so that I can focus more time on localize. That scenario can be revised if required around March 2026 with CLDR 49.

16 Likes