# `Localize.Ecto.Collation`
[🔗](https://github.com/elixir-localize/localize_sql/blob/v1.0.1/lib/localize/ecto/collation.ex#L1)

Resolves a locale to the name of a PostgreSQL ICU collation.

PostgreSQL's `initdb` imports the full set of ICU collations into
`pg_catalog`, naming each one after its BCP 47 locale identifier with
an `-x-icu` suffix — for example `de-DE-x-icu`, `zh-Hant-TW-x-icu`
and the root collation `und-x-icu`.

This module maps a `t:Localize.LanguageTag.t/0` (or any locale
identifier accepted by `Localize.validate_locale/1`) onto the best
matching collation using the [CLDR Language Matching](https://www.unicode.org/reports/tr35/tr35.html#LanguageMatching)
algorithm implemented by `Localize.LanguageTag.best_match/3`. The
requested locale is matched against the set of collation locales
PostgreSQL derives from ICU, bundled with this library, and the root
collation `und-x-icu` is the fallback of last resort.

Because CLDR collation tailorings are defined per language (and
script) rather than per territory, a match to a broader locale — for
example `de-DE` matching the `de` collation locale — selects an
identical collator.

The same names serve SQLite. `Localize.Ecto.SQLite3` resolves through
this module too, and the `localize_icu` extension registers exactly
these names, so a locale produces the same collation on either
database. The list matched against is PostgreSQL's because that is
what keeps the two in step — SQLite itself will build any collation
ICU can open.

The primary public API is `collation_for/2` and `collation_for!/2`.

# `collation_for`

```elixir
@spec collation_for(Localize.locale() | String.t(), Keyword.t()) ::
  {:ok, String.t()} | {:error, Exception.t()}
```

Returns the PostgreSQL ICU collation name for the given locale.

Resolutions against the default collation locales are cached, so
repeated calls for the same locale are inexpensive.

### Arguments

* `locale` is a `t:Localize.LanguageTag.t/0`, or any locale identifier
  accepted by `Localize.validate_locale/1`. The default is
  `Localize.get_locale/0`.

* `options` is a keyword list of options.

### Options

* `:available` is a list of BCP 47 locale strings (without the
  `-x-icu` suffix) to match against. The default is the list bundled
  with this library, generated from PostgreSQL's `pg_collation`
  catalog.

### Returns

* `{:ok, collation_name}` where `collation_name` is a string such as
  `"de-x-icu"`, or

* `{:error, exception}` if `locale` is not a valid locale.

### Examples

    iex> Localize.Ecto.Collation.collation_for("de-DE")
    {:ok, "de-x-icu"}

    iex> Localize.Ecto.Collation.collation_for("zh-TW")
    {:ok, "zh-Hant-x-icu"}

    iex> Localize.Ecto.Collation.collation_for("xx")
    {:error, %Localize.InvalidLocaleError{locale_id: "xx"}}

# `collation_for!`

```elixir
@spec collation_for!(Localize.locale() | String.t(), Keyword.t()) :: String.t()
```

Returns the PostgreSQL ICU collation name for the given locale or
raises.

### Arguments

* `locale` is a `t:Localize.LanguageTag.t/0`, or any locale identifier
  accepted by `Localize.validate_locale/1`. The default is
  `Localize.get_locale/0`.

* `options` is a keyword list of options. See `collation_for/2`.

### Returns

* A collation name string such as `"de-x-icu"`, or

* raises if `locale` is not a valid locale.

### Examples

    iex> Localize.Ecto.Collation.collation_for!("sv")
    "sv-x-icu"

    iex> Localize.Ecto.Collation.collation_for!(:"en-GB")
    "en-GB-x-icu"

# `known_collations`

```elixir
@spec known_collations() :: [String.t()]
```

Returns the list of locales for which a PostgreSQL ICU collation is
known to exist.

The list contains BCP 47 locale strings without the `-x-icu` suffix,
as recorded in the `colllocale` column of `pg_collation`.

### Returns

* A list of locale strings.

### Examples

    iex> "de-DE" in Localize.Ecto.Collation.known_collations()
    true

    iex> "und" in Localize.Ecto.Collation.known_collations()
    true

# `resolve!`

```elixir
@spec resolve!(Localize.locale() | String.t() | Keyword.t()) :: String.t()
```

Resolves the argument of `Localize.Ecto.collate/2` to a collation
name.

This is the runtime companion of the `Localize.Ecto.collate/1,2`
macros and is not usually called directly.

### Arguments

* `locale_or_options` is a locale accepted by `collation_for!/2`, or
  a keyword list.

### Options

* `:collation` is a collation name used verbatim, bypassing locale
  resolution — for example a collation created with
  `Localize.Ecto.Migration.create_collation/2` under a custom name.

* Any other options are passed to `collation_for!/2`.

### Returns

* A collation name string, or

* raises if the locale is not valid.

### Examples

    iex> Localize.Ecto.Collation.resolve!("sv")
    "sv-x-icu"

    iex> Localize.Ecto.Collation.resolve!(collation: "german_phonebook")
    "german_phonebook"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
