# `Localize.Locale.Provider`
[🔗](https://github.com/elixir-localize/localize/blob/v0.6.0/lib/localize/locale/provider.ex#L1)

Defines the behaviour for locale data providers.

A locale data provider is responsible for loading, storing, and
retrieving CLDR locale data. Implementations may store data in
any backing store such as `:persistent_term`, ETS, or the
filesystem.

## Callbacks

Implementing modules must define four callbacks:

* `load/1` — finds and retrieves locale data for a given locale.

* `store/2` — persists locale data to the provider's backing store.

* `loaded?/1` — checks whether a locale's data has been loaded
  and is available for use.

* `get/3` — retrieves a specific value from locale data by
  following a list of access keys, with optional fallback to
  parent locales.

# `locale`

```elixir
@type locale() :: locale_id() | Localize.LanguageTag.t()
```

A locale reference: either a locale identifier atom or a language tag struct.

# `locale_id`

```elixir
@type locale_id() :: atom()
```

A locale identifier as an atom.

# `allow_download?`
*optional* 

```elixir
@callback allow_download?() :: boolean()
```

Returns whether this provider is permitted to download locale
data from a remote source at runtime.

Providers that never download (e.g. a database-backed provider)
should return `false`. Providers that always have data locally
available can simply not implement this callback — the default
implementation reads `Application.get_env(:localize,
:allow_runtime_locale_download, false)`.

# `get`

```elixir
@callback get(locale(), list(), Keyword.t()) :: {:ok, term()} | {:error, term()}
```

Retrieves a value from locale data by following a list of access keys.

Navigates the locale data map using the provided list of keys,
returning the value found at the end of the key path.

### Arguments

* `locale` is a locale identifier atom or a `t:Localize.LanguageTag.t/0`.

* `keys` is a list of keys to traverse in the locale data map.

* `options` is a keyword list of options. The default is `[]`.

### Options

* `:fallback` is a boolean. When `true`, if the requested key path
  is not found in the given locale, the provider will attempt to
  find it in parent locales according to the CLDR locale inheritance
  chain. The default is `false`.

### Returns

* `{:ok, value}` if the key path resolves to a value.

* `{:error, reason}` if the key path cannot be resolved.

# `load`

```elixir
@callback load(locale()) :: {:ok, map()} | {:error, Exception.t()}
```

Loads locale data for the given locale.

Finds the locale data for the given locale identifier or
language tag, retrieves it from the data source, and returns
the data as a map.

### Arguments

* `locale` is a locale identifier atom or a `t:Localize.LanguageTag.t/0`.

### Returns

* `{:ok, locale_data}` where `locale_data` is a map of the locale's
  CLDR data.

* `{:error, Localize.UnknownLocaleError.t()}` if the locale is not
  recognized.

# `loaded?`

```elixir
@callback loaded?(locale()) :: boolean()
```

Returns whether locale data has been loaded and is available.

### Arguments

* `locale` is a locale identifier atom or a `t:Localize.LanguageTag.t/0`.

### Returns

* `true` if the locale data has been loaded and stored.

* `false` otherwise.

# `store`

```elixir
@callback store(locale_id(), map()) :: :ok | {:error, term()}
```

Stores locale data in the provider's backing store.

### Arguments

* `locale` is a locale identifier atom.

* `locale_data` is a map of locale data to store.

### Returns

* `:ok` on success.

* `{:error, reason}` on failure.

# `allow_download?`

```elixir
@spec allow_download?(module()) :: boolean()
```

Returns whether runtime locale downloads are permitted for the
given provider module.

If the provider module implements the optional `allow_download?/0`
callback, that implementation is called. Otherwise falls back to
the `:allow_runtime_locale_download` application environment key
(default `false`).

### Arguments

* `provider_module` is a module that implements the
  `Localize.Locale.Provider` behaviour. The default is the
  currently configured provider.

### Returns

* `true` if runtime downloads are permitted.

* `false` otherwise.

# `base_url`

```elixir
@spec base_url() :: String.t()
```

Returns the base URL from which locale data files are downloaded.

### Returns

* A string URL.

### Examples

    iex> Localize.Locale.Provider.base_url()
    "https://elixir-localize.com/locales"

# `default_locale_cache_dir`

```elixir
@spec default_locale_cache_dir() :: String.t()
```

Returns the default directory in which downloaded locale data is cached.

The default directory is located under the `:localize` application's
`priv` directory at `localize/locales`.

### Returns

* A string path to the default locale cache directory.

### Examples

    iex> String.ends_with?(Localize.Locale.Provider.default_locale_cache_dir(), "localize/locales")
    true

# `download_locale`

```elixir
@spec download_locale(locale_id()) :: {:ok, binary()} | {:error, Exception.t()}
```

Downloads locale data for the given locale from `locale_url/1`.

Uses Erlang's built-in `:httpc` to fetch the file. The downloaded
content is returned as a binary and is not written to disk or
decoded by this function.

### Arguments

* `locale_id` is a locale identifier atom.

### Returns

* `{:ok, binary}` with the raw downloaded file contents on success.

* `{:error, exception}` if the locale could not be downloaded.

# `load_with_fallback`

```elixir
@spec load_with_fallback(module(), locale()) ::
  {:ok, map(), locale_id()} | {:error, Exception.t()}
```

Loads locale data with fallback through the CLDR parent chain.

Attempts to load the requested locale via `provider.load/1`. If the
load fails, walks up the CLDR locale inheritance chain (e.g.
`en-AU` → `en` → `und`) trying each parent in turn. If the entire
chain is exhausted without success, falls back to `:en` which is
guaranteed to be present.

Returns `{:ok, locale_data, resolved_locale_id}` so the caller
knows which locale was actually loaded.

### Arguments

* `provider` is the module implementing `Localize.Locale.Provider`.

* `locale` is a locale identifier atom or a `t:Localize.LanguageTag.t/0`.

### Returns

* `{:ok, locale_data, resolved_locale_id}` on success.

* `{:error, exception}` if even the `:en` fallback fails (should not
  happen in normal operation).

# `locale_cache_dir`

```elixir
@spec locale_cache_dir() :: String.t()
```

Returns the directory in which downloaded locale data is cached.

The directory is resolved from the `:locale_cache_dir` application
environment key for `:localize`, falling back to
`default_locale_cache_dir/0` when unset.

### Returns

* A string path to the locale cache directory.

### Examples

    iex> is_binary(Localize.Locale.Provider.locale_cache_dir())
    true

# `locale_file_name`

```elixir
@spec locale_file_name(locale_id()) :: String.t()
```

Returns the file name for a locale's cached data file.

### Arguments

* `locale_id` is a locale identifier atom.

### Returns

* A string file name of the form `"{locale_id}.etf"`.

### Examples

    iex> Localize.Locale.Provider.locale_file_name(:en)
    "en.etf"

# `locale_url`

```elixir
@spec locale_url(locale_id()) :: String.t()
```

Returns the download URL for a given locale.

The URL is versioned by the current `Localize.version/0` so
that each Localize release downloads from its own path.

### Arguments

* `locale_id` is a locale identifier atom.

### Returns

* A string URL from which the locale's data file can be downloaded.

### Examples

    iex> url = Localize.Locale.Provider.locale_url(:en)
    iex> String.starts_with?(url, "https://elixir-localize.com/locales/")
    true
    iex> String.ends_with?(url, "/en.etf")
    true

# `version_segment`

```elixir
@spec version_segment() :: String.t()
```

Returns the version segment used in cache paths and download URLs.

### Returns

* A string of the form `"v{major}.{minor}.{patch}"` matching
  `Localize.version/0` with a `v` prefix.

---

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