# `Calendrical.Preference`

Resolves the preferred Calendrical calendar module for a CLDR locale or an
ISO 3166 territory.

CLDR ships preference rankings that say, for any given territory, which
calendar systems are most appropriate to use. This module turns those
rankings into actual Elixir module names by walking the preference list and
returning the first calendar whose Calendrical implementation is loaded in
the current build.

The two main entry points are:

* `calendar_from_territory/1` — given an ISO 3166 territory code, return the
  preferred calendar module.

* `calendar_from_locale/1` — given a CLDR locale, return the preferred
  calendar module. Honours the `-u-ca-` BCP 47 calendar extension and the
  `-u-fw-` first-day-of-week extension when present.

## The calendar a `-u-ca-` extension names

A language tag's `-u-ca-<name>` names a CLDR calendar, and the module it
means is `Calendrical.calendar_from_cldr_calendar_type/1`'s for that
name, refined by the locale in the two cases where its territory says
more than the name does:

* **`gregory`** — the territory's Gregorian calendar, with its first day
  of the week and the days its first week must hold, so `en-GB` and
  `en-GB-u-ca-gregory` name one calendar, `Calendrical.GB`.

* **`chinese` in Vietnam** — `Calendrical.Vietnamese`, the same lunisolar
  calendar reckoned at Hanoi's meridian.

A name alone has no territory, so `calendar_from_cldr_calendar_type/1`
answers `Calendrical.Gregorian` and `Calendrical.Chinese` for those. A
language tag carries only CLDR's calendar names: the identifiers of
`Calendrical.additional_calendars/0`, such as `julian`, are not valid in
one, and are named to `calendar_from_cldr_calendar_type/1` or in an IXDTF
suffix.

In every case, if no calendar in the preference list is available, the
module falls back to `Calendrical.Gregorian` (the default calendar), which
is always present.

## Optional calendar packages

Some calendar implementations only ship if their dependencies are loaded —
for example, the lunisolar calendars require `Astro`. The runtime
`Code.ensure_loaded?/1` checks in this module exist precisely so that the
preference resolver gracefully degrades when an optional calendar is not
available in the current build.

# `calendar_from_locale`

Returns the Calendrical calendar module preferred for the given locale.

Honours the BCP 47 `-u-ca-` calendar extension and the `-u-fw-` first-day-
of-week extension when present in the locale identifier. If no calendar
extension is supplied, falls back to the territory preference list (see
`calendar_from_territory/1`).

### Arguments

* `locale` is a locale identifier atom, string, or a
  `t:Localize.LanguageTag.t/0`. The default is `Localize.get_locale/0`.

### Returns

* `{:ok, calendar_module}` on success.

* `{:error, exception}` if the locale is invalid.

### Examples

    iex> Calendrical.Preference.calendar_from_locale(:"en-GB")
    {:ok, Calendrical.GB}

    iex> Calendrical.Preference.calendar_from_locale("en-GB-u-ca-gregory")
    {:ok, Calendrical.GB}

    iex> Calendrical.Preference.calendar_from_locale(:en)
    {:ok, Calendrical.US}

    iex> Calendrical.Preference.calendar_from_locale("en-u-ca-iso8601")
    {:ok, Calendrical.ISO}

    iex> Calendrical.Preference.calendar_from_locale("en-u-fw-mon")
    {:ok, Calendrical.Gregorian}

    iex> Calendrical.Preference.calendar_from_locale(:"fa-IR")
    {:ok, Calendrical.Persian}

    iex> Calendrical.Preference.calendar_from_locale("fa-IR-u-ca-gregory")
    {:ok, Calendrical.IR}

# `calendar_from_territory`

Returns the Calendrical calendar module preferred for the given territory.

Walks the CLDR territory preference list and returns the first calendar
whose Calendrical implementation is loaded in the current build. If no
preferred calendar is loaded, falls back to `Calendrical.Gregorian`.

### Arguments

* `territory` is any valid ISO 3166 alpha-2 code as a `t:String.t/0` or an
  upcased `t:atom/0` (e.g. `:US`, `:IR`, `:JP`).

### Returns

* `{:ok, calendar_module}` on success.

* `{:error, exception}` if the territory is unknown.

### Examples

    iex> Calendrical.Preference.calendar_from_territory(:US)
    {:ok, Calendrical.US}

    iex> {:error, %Localize.UnknownTerritoryError{}} =
    ...>   Calendrical.Preference.calendar_from_territory(:YY)

### Notes

The overwhelming majority of territories have `:gregorian` as their first
preferred calendar, so `Calendrical.Gregorian` is returned for most
territories.

Returning any other calendar module requires both that another calendar is
preferred over `:gregorian` for the territory, and that the corresponding
Calendrical implementation is loaded. For example, Iran (`:IR`) prefers the
`:persian` calendar, so `Calendrical.Persian` is returned (the Persian
calendar is built into Calendrical and always available).

# `calendar_from_territory`

Returns the Calendrical calendar module for a territory and a
preferred calendar type.

The calendar type is chosen when the territory lists it among its
preferences, or the territory has its own variant of it. Otherwise
the territory's first loaded preference is returned, as
`calendar_from_territory/1` does.

### Arguments

* `territory` is any valid ISO 3166 alpha-2 code as an upcased
  `t:atom/0` (e.g. `:US`, `:IR`, `:JP`).

* `calendar` is a CLDR calendar type such as `:persian` or
  `:buddhist`.

### Returns

* `{:ok, calendar_module}` on success.

* `{:error, exception}` if the territory is unknown.

### Examples

    iex> Calendrical.Preference.calendar_from_territory(:IR, :persian)
    {:ok, Calendrical.Persian}

    iex> Calendrical.Preference.calendar_from_territory(:US, :persian)
    {:ok, Calendrical.US}

---

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