ICU MessageFormat 1 for Localize: arguments, formatted arguments and the plural, select and selectordinal selectors, formatted with Localize's locales, plural rules and formatters. It is a port of the MessageFormat 1 support in ex_cldr_messages, so an application that moves from ex_cldr to Localize keeps its MessageFormat 1 translations and msgids unchanged. Localize itself formats MessageFormat 2.
Features
MessageFormat 1 syntax — arguments, formatted arguments, the
plural,selectandselectordinalselectors withoffset:and explicit=nclauses,#, and ICU apostrophe quoting.Localize formatting — numbers, currencies, spelled-out numbers, ordinals, dates, times, units, lists and plural categories from Localize's CLDR data, and money through
ex_money6 when it is a dependency.Compatible with
ex_cldr_messages— the same API, options and output, so messages and canonical msgids carry over. The migration guide lists every difference.Gettext interpolation —
Localize.Message.MF1.Gettext.Interpolationformats a Gettext backend's messages as MessageFormat 1.Canonical messages —
canonical_message/2and the~Msigil give a message a canonical form for use as a msgid, andjaro_distance/3compares two messages.No backend module — the locale is Localize's, and formatting options are arguments.
Never raises on invalid input — every function except the
!functions returns{:ok, result}or{:error, exception}.
Supported Elixir and OTP versions
Localize MF1 requires Elixir 1.17+ and Erlang/OTP 26+.
On OTP 26, also add {:json_polyfill, "~> 0.2 or ~> 1.0"} to your dependencies. It provides the OTP 27+ :json module that Localize uses. OTP 27 and later need no extra dependency.
Installation
Add localize_mf1 to your dependencies in mix.exs, and ex_money if your messages format money arguments:
def deps do
[
{:localize_mf1, "~> 0.1"},
{:ex_money, "~> 6.0"}
]
endLocalize ships with the en locale. Download the data for any other locale your application uses at build time with mix localize.download_locales, for example mix localize.download_locales fr de. See mix localize.download_locales.
Quick start
Arguments are bound by name, from a keyword list or a map, or by position:
iex> Localize.Message.MF1.format("Hello {name}!", name: "World")
{:ok, "Hello World!"}
iex> Localize.Message.MF1.format("{0} and {1}", ["this", "that"])
{:ok, "this and that"}Formatted arguments use Localize's formatters in the current locale, or the :locale option:
iex> Localize.Message.MF1.format("{count, number} jelly beans", [count: 1234], locale: :de)
{:ok, "1.234 jelly beans"}
iex> Localize.Message.MF1.format("Due {due, date, long}", due: ~D[2026-10-27])
{:ok, "Due October 27, 2026"}plural and selectordinal choose a clause by the locale's plural rules, and select by a value:
iex> Localize.Message.MF1.format("{count, plural, =0 {no items} one {# item} other {# items}}", count: 3)
{:ok, "3 items"}
iex> Localize.Message.MF1.format("{place, selectordinal, one {#st} two {#nd} few {#rd} other {#th}}", place: 22)
{:ok, "22nd"}
iex> Localize.Message.MF1.format("{gender, select, female {She} male {He} other {They}} replied", gender: "female")
{:ok, "She replied"}A canonical form ignores layout white space, for use as a msgid:
iex> Localize.Message.MF1.canonical_message("{count, plural,\n other {# items}\n one {# item}}")
{:ok, "{count, plural, one {# item} other {# items}}"}Gettext
Name the interpolation module in a Gettext backend, and its messages are formatted as MessageFormat 1:
defmodule MyApp.Gettext do
use Gettext.Backend,
otp_app: :my_app,
interpolation: Localize.Message.MF1.Gettext.Interpolation
endThe ~M sigil of Localize.Message.MF1.Sigils canonicalizes a message at compile time, so a change of layout does not make a new msgid.
Documentation
Migrating from ex_cldr_messages — the API mapping and every difference in behaviour.
Localize.Message.MF1 — formatting, the argument types and styles, named formats and canonical messages.
Localize.Message.MF1.Gettext.Interpolation — Gettext interpolation.
The full documentation is published on HexDocs.
License
Localize MF1 is released under the Apache License 2.0.