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

On-disk cache for downloaded locale data files.

This module is responsible for reading and writing locale ETF
files under the directory returned by
`Localize.Locale.Provider.locale_cache_dir/0`, and for detecting
when a cached file is stale: of another version than
`Localize.version/0`, or not the bytes the release's hash manifest
records for it.

## Primary API

* `get/1` — returns cached locale data, or an error tuple if the
  file is missing or stale.

* `store/2` — writes locale data to the cache directory.

* `stale?/1` — checks whether a cached locale file is stale.

* `path/1` — returns the absolute path for a locale's cache file.

# `locale_id`

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

A locale identifier as an atom.

# `get`

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

Retrieves locale data from the cache directory.

Reads the locale's cache file, decodes it, and validates that
its `:version` field matches `Localize.version/0` and that its bytes
match the SHA-256 hash the release's manifest records for it.

### Arguments

* `locale_id` is a locale identifier atom.

### Returns

* `{:ok, locale_data}` if the cache file is present, its version
  matches the current version and its bytes match the manifest.

* `{:error, Localize.LocaleIsStaleError.t()}` if the cache file
  is present but its version or its bytes do not match.

* `{:error, Localize.LocaleNotFoundInCacheError.t()}` if the
  cache file is not present.

* `{:error, exception}` if `locale_id` is not an atom.

### Examples

    iex> {:error, error} = Localize.Locale.Provider.Cache.get(:"zz-ZZ")
    iex> error.__struct__
    Localize.LocaleNotFoundInCacheError

# `path`

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

Returns the absolute cache file path for the given locale.

### Arguments

* `locale_id` is a locale identifier atom.

### Returns

* A string path to the locale's cache file.

### Examples

    iex> path = Localize.Locale.Provider.Cache.path(:en)
    iex> String.ends_with?(path, "en.etf")
    true

# `stale?`

```elixir
@spec stale?(locale_id()) :: boolean()
```

Returns whether a cached locale file is stale.

A cache file is considered stale if its `:version` field does
not equal `Localize.version/0`, or if its bytes do not match the
SHA-256 hash the release's manifest records for the locale. A file
that is missing, unreadable, or undecodable (corrupt) is also
considered stale.

### Arguments

* `locale_id` is a locale identifier atom.

### Returns

* `true` if the cache file is missing, unreadable, or its
  version or bytes do not match.

* `false` if the cache file is present, its version matches and
  its bytes match the manifest.

### Examples

    iex> Localize.Locale.Provider.Cache.stale?(:"xx-NOPE")
    true

# `store`

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

Stores locale content in the cache directory.

Creates the cache directory if it does not already exist and
writes `content` to the locale's cache file. `content` should
be the raw binary form of the locale ETF file.

### Arguments

* `locale_id` is a locale identifier atom.

* `content` is a binary containing the encoded locale data.

### Returns

* `{:ok, path}` where `path` is the absolute path the content
  was written to.

* `{:error, Localize.LocaleCacheWriteError.t()}` on failure.

* `{:error, exception}` if `locale_id` is not an atom or `content`
  is not a binary.

### Examples

A store writes the cache file, so the example shows the answer that
writes nothing, for content that is not a binary:

    iex> Localize.Locale.Provider.Cache.store(:en, :not_a_binary) |> elem(0)
    :error

---

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