Search documentation of Localize

# Localize.Chars protocol (Localize v0.39.0)

Copy Markdown View Source

Protocol for locale-aware string formatting.

`Localize.Chars` provides a single dispatch point for formatting any supported value as a localized string. It mirrors the `String.Chars` protocol from Elixir core, but every implementation is locale-aware and returns the standard Localize result tuple `{:ok, formatted}` / `{:error, exception}`.

## Examples

    iex> Localize.Chars.to_string(1234.5, locale: :de)
    {:ok, "1.234,5"}

    iex> Localize.Chars.to_string(1234.5, locale: :en)
    {:ok, "1,234.5"}

    iex> Localize.Chars.to_string(~D[2025-07-10], locale: :en)
    {:ok, "Jul 10, 2025"}

    iex> {:ok, unit} = Localize.Unit.new(42, "kilometer")
    iex> Localize.Chars.to_string(unit, format: :short, locale: :en)
    {:ok, "42 km"}

## Built-in implementations

Type | Delegates to
--- | ---
`Integer` | `Localize.Number.to_string/2`
`Float` | `Localize.Number.to_string/2`
`Decimal` | `Localize.Number.to_string/2`
`Date` | `Localize.Date.to_string/2`
`Time` | `Localize.Time.to_string/2`
`DateTime` | `Localize.DateTime.to_string/2`
`NaiveDateTime` | `Localize.DateTime.to_string/2`
`Range` | `Localize.Number.to_range_string/2`
`BitString` | identity (returns the string unchanged)
`List` | `Localize.List.to_string/2`
`Localize.Unit` | `Localize.Unit.to_string/2`
`Localize.Duration` | `Localize.Duration.to_string/2`
`Localize.LanguageTag` | `Localize.Locale.LocaleDisplay.display_name/2`
`Localize.Currency` | `Localize.Currency.display_name/2`

Types without a Localize-specific implementation fall through to `Kernel.to_string/1`, which dispatches via `String.Chars`. This mirrors the relationship between `Localize.Chars` and `String.Chars`: where Localize knows how to format the type in a locale-aware way it does so; otherwise it returns `{:ok, Kernel.to_string(value)}`. Types with no `String.Chars` implementation either (tuples, maps without an explicit impl, PIDs, references, anonymous functions) raise the same `Protocol.UndefinedError` they would from `Kernel.to_string/1` — `Localize.Chars` does not invent a representation for them.

## Caveats

- The `List` implementation formats the list as a locale-aware conjunction (`"a, b, and c"`) by delegating to `Localize.List.to_string/2`, which itself recursively formats each element via `Localize.to_string/2` so dates, numbers, units, etc. inside a list pick up the outer locale and other options (e.g. `currency: :USD`). Charlists are special-cased: a printable list of integer codepoints (`~c"hello"`) is converted via `Kernel.to_string/1` rather than being joined digit-by-digit, mirroring how `String.Chars`'s `List` impl handles them.

- The `Localize.LanguageTag` implementation produces the localized display name ("English (United States)"), not the canonical BCP-47 string. The canonical form is still available via `Kernel.to_string/1`, which uses the internal `String.Chars` protocol.

## Adding implementations for your own types

Implement the protocol for any struct you want to support through `Localize.to_string/1` and `Localize.to_string/2`:

    defimpl Localize.Chars, for: MyApp.Money do
      def to_string(money), do: Localize.Chars.to_string(money, [])

      def to_string(%MyApp.Money{amount: amount, currency: currency}, options) do
        options = Keyword.put_new(options, :currency, currency)
        Localize.Number.to_string(amount, options)
      end
    end

After this, `Localize.to_string(%MyApp.Money{...}, locale: :de)` works exactly like the built-in implementations.

## Summary

### Types

t()

All the types that implement this protocol.

### Functions

to_string(value)

Formats `value` as a localized string with default options.

to_string(value, options)

Formats `value` as a localized string with the given options.

## Types

# t()

    @type t() :: term()

All the types that implement this protocol.

## Functions

# to_string(value)

    @spec to_string(t()) :: {:ok, String.t()} | {:error, Exception.t()}

Formats `value` as a localized string with default options.

Equivalent to `to_string(value, [])`.

### Returns

- `{:ok, formatted_string}` on success.

- `{:error, exception}` if formatting fails. The exception is a struct (e.g. `%Localize.UnknownLocaleError{}`).

# to_string(value, options)

    @spec to_string(t(), Keyword.t()) :: {:ok, String.t()} | {:error, Exception.t()}

Formats `value` as a localized string with the given options.

Each implementation accepts the option set of its underlying formatter. Every implementation accepts at least `:locale`.

### Arguments

- `value` is any term that has a `Localize.Chars` implementation.

- `options` is a keyword list of options forwarded to the underlying formatter.

### Returns

- `{:ok, formatted_string}` on success.

- `{:error, exception}` if formatting fails.