Intl

An Elixir interface to internationalization functions modelled on the JavaScript Intl API.

If you are familiar with the JS Intl API, you already know how to use this library. The module names, function purposes, and option names mirror their JS counterparts — adapted to idiomatic Elixir conventions (snake_case, keyword options, {:ok, result} / {:error, reason} tuples).

Relationship to Localize

Intl is a thin shim over the Localize library which provides the full CLDR-based locale data and formatting engine. Each Intl module translates JS Intl option names and conventions into the corresponding Localize calls:

If you need lower-level control or access to features beyond the Intl API surface (such as unit conversion, message formatting, or calendar metadata), use Localize directly.

Compatibility and Differences

The full compatibility matrix is in the Compatibility guide. Key points:

Examples

Number Formatting

iex> Intl.NumberFormat.format(1_234_567.89, locale: :en)
{:ok, "1,234,567.89"}

iex> Intl.NumberFormat.format(1_234_567.89, locale: :de)
{:ok, "1.234.567,89"}

iex> Intl.NumberFormat.format(0.56, locale: :en, style: :percent)
{:ok, "56%"}

iex> Intl.NumberFormat.format(1234.5, locale: :en, style: :currency, currency: :USD)
{:ok, "$1,234.50"}

Date and Time Formatting

iex> Intl.DateTimeFormat.format(~D[2025-03-15], locale: :en, date_style: :full)
{:ok, "Saturday, March 15, 2025"}

iex> Intl.DateTimeFormat.format(~D[2025-03-15], locale: :en, date_style: :short)
{:ok, "3/15/25"}

List Formatting

iex> Intl.ListFormat.format(["Monday", "Tuesday", "Wednesday"], locale: :en)
{:ok, "Monday, Tuesday, and Wednesday"}

iex> Intl.ListFormat.format(["tea", "coffee", "juice"], locale: :en, type: :disjunction)
{:ok, "tea, coffee, or juice"}

iex> Intl.ListFormat.format(["lundi", "mardi", "mercredi"], locale: :fr)
{:ok, "lundi, mardi et mercredi"}

Display Names

iex> Intl.DisplayNames.of("US", type: :region, locale: :en)
{:ok, "United States"}

iex> Intl.DisplayNames.of("DE", type: :region, locale: :fr)
{:ok, "Allemagne"}

iex> Intl.DisplayNames.of("fr", type: :language, locale: :en)
{:ok, "French"}

iex> Intl.DisplayNames.of(:Latn, type: :script, locale: :en)
{:ok, "Latin"}

iex> Intl.DisplayNames.of("JPY", type: :currency, locale: :en)
{:ok, "Japanese Yen"}

iex> Intl.DisplayNames.of(:gregorian, type: :calendar, locale: :en)
{:ok, "Gregorian Calendar"}

Relative Time

iex> Intl.RelativeTimeFormat.format(-1, :day, locale: :en)
{:ok, "yesterday"}

iex> Intl.RelativeTimeFormat.format(3, :hour, locale: :en)
{:ok, "in 3 hours"}

iex> Intl.RelativeTimeFormat.format(-3, :day, locale: :fr)
{:ok, "il y a 3 jours"}

Plural Rules

iex> Intl.PluralRules.select(1, locale: "en")
{:ok, :one}

iex> Intl.PluralRules.select(5, locale: "en")
{:ok, :other}

iex> Intl.PluralRules.select(2, locale: "ar")
{:ok, :two}

Collation

iex> Intl.Collator.compare("ä", "z", locale: :de, sensitivity: :base)
:lt

iex> Intl.Collator.sort(["banana", "apple", "cherry"], locale: :en)
["apple", "banana", "cherry"]

Duration Formatting

iex> Intl.DurationFormat.format(%{hours: 2, minutes: 30}, locale: :en)
{:ok, "2 hours and 30 minutes"}

Text Segmentation

iex> Intl.Segmenter.segment("héllo", granularity: :grapheme)
{:ok, ["h", "é", "l", "l", "o"]}

iex> Intl.Segmenter.segment("Hello world", granularity: :word, trim: true)
{:ok, ["Hello", "world"]}

iex> Intl.Segmenter.segment("Hello. How are you?", granularity: :sentence)
{:ok, ["Hello. ", "How are you?"]}

Locale Utilities

iex> Intl.get_canonical_locales(["en-us", "fr-fr"])
{:ok, ["en-US", "fr-FR"]}

iex> {:ok, calendars} = Intl.supported_values_of(:calendar)
iex> :gregorian in calendars
true

Installation

Add intl to your list of dependencies in mix.exs:

def deps do
  [
    {:intl, "~> 0.1.0"}
  ]
end

Word and sentence segmentation require the optional unicode_string dependency:

{:unicode_string, "~> 1.8"}

Locale Data

Intl delegates to Localize for locale data. The :en locale is always available. To use other locales, either pre-download their data at build time:

mix localize.download_locales de fr ja

Or enable runtime downloading in config/runtime.exs:

config :localize, :allow_runtime_locale_download, true

Locale data is loaded lazily into :persistent_term on first access. See the Localize documentation for full configuration details.