# `PhoenixKitEcommerce.Translations`
[🔗](https://github.com/BeamLabEU/phoenix_kit_ecommerce/blob/v0.1.8/lib/phoenix_kit_ecommerce/translations.ex#L1)

Localized fields helper for Shop module.

All translatable fields are stored as JSONB maps directly in the field:

    %Product{
      title: %{"en" => "Planter", "ru" => "Кашпо"},
      slug: %{"en" => "planter", "ru" => "kashpo"},
      description: %{"en" => "Modern pot", "ru" => "Современное кашпо"}
    }

## Fallback Chain

When retrieving a translated field, the fallback chain is:
1. Exact language match (e.g., "ru")
2. Default language from Languages module
3. First available value in the map

## Usage Examples

    # Get translated field with automatic fallback
    Translations.get(product, :title, "ru")
    #=> "Кашпо"

    Translations.get(product, :title, "fr")
    #=> "Planter" (fallback to default or first available)

    # Set a single translated field
    product = Translations.put(product, :title, "es", "Maceta")

    # Build changeset attrs for localized field update
    attrs = Translations.changeset_attrs(product, :title, "ru", "Новое кашпо")
    #=> %{title: %{"en" => "Planter", "ru" => "Новое кашпо"}}

# `available_languages`

```elixir
@spec available_languages(
  struct(),
  atom()
) :: [String.t()]
```

Gets all languages that have a value for a field.

## Examples

    iex> Translations.available_languages(product, :title)
    ["en", "ru"]

# `category_fields`

```elixir
@spec category_fields() :: [atom()]
```

Returns the list of translatable fields for categories.

# `changeset_attrs`

```elixir
@spec changeset_attrs(struct(), atom(), String.t(), any()) :: map()
```

Builds changeset attrs for localized field update.

Merges the new value into the existing field map for the given language.

## Examples

    iex> Translations.changeset_attrs(product, :title, "ru", "Новое кашпо")
    %{title: %{"en" => "Planter", "ru" => "Новое кашпо"}}

# `changeset_attrs_multi`

```elixir
@spec changeset_attrs_multi(struct(), String.t(), map()) :: map()
```

Builds changeset attrs for multiple localized fields at once.

## Examples

    iex> Translations.changeset_attrs_multi(product, "ru", %{title: "Кашпо", slug: "kashpo"})
    %{title: %{"en" => "Planter", "ru" => "Кашпо"}, slug: %{"en" => "planter", "ru" => "kashpo"}}

# `default_language`

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

Returns the default/master language code.

Checks Languages module first, falls back to Settings content language,
then defaults to "en".

## Examples

    iex> Translations.default_language()
    "en"

# `enabled_languages`

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

Returns list of enabled language codes.

When Languages module is enabled, returns all enabled language codes.
Otherwise returns only the default language.

## Examples

    iex> Translations.enabled_languages()
    ["en", "es", "ru"]

    # When Languages module disabled:
    iex> Translations.enabled_languages()
    ["en"]

# `get`

```elixir
@spec get(struct(), atom(), String.t()) :: any()
```

Gets a localized value with automatic fallback chain.

Fallback order:
1. Exact language match
2. Default language
3. First available value

## Parameters

  - `entity` - Product or Category struct
  - `field` - Field atom (e.g., :title, :name, :slug)
  - `language` - Language code (e.g., "ru", "en")

## Examples

    iex> product = %Product{title: %{"en" => "Planter", "ru" => "Кашпо"}}
    iex> Translations.get(product, :title, "ru")
    "Кашпо"

    iex> Translations.get(product, :title, "fr")
    "Planter"  # Falls back to default or first available

# `get_all_for_language`

```elixir
@spec get_all_for_language(struct(), String.t(), [atom()]) :: map()
```

Gets all values for a specific language from the entity's localized fields.

Returns a map of field => value for the given language.

## Examples

    iex> Translations.get_all_for_language(product, "ru", [:title, :slug, :description])
    %{title: "Кашпо", slug: "kashpo", description: "Описание"}

# `get_field`

```elixir
@spec get_field(struct(), atom(), String.t()) :: any()
```

DEPRECATED: Use `get/3` instead.

This function exists for backward compatibility during migration.

# `get_slug`

```elixir
@spec get_slug(
  struct(),
  String.t()
) :: String.t() | nil
```

Gets the localized slug with fallback.

Convenience function for URL slug retrieval.

## Examples

    iex> Translations.get_slug(product, "es")
    "maceta-geometrica"

# `has_translation?`

```elixir
@spec has_translation?(struct(), atom(), String.t()) :: boolean()
```

Checks if translation exists for language in a specific field.

## Examples

    iex> Translations.has_translation?(product, :title, "ru")
    true

    iex> Translations.has_translation?(product, :title, "zh")
    false

# `languages_enabled?`

```elixir
@spec languages_enabled?() :: boolean()
```

Checks if Languages module is enabled.

# `product_fields`

```elixir
@spec product_fields() :: [atom()]
```

Returns the list of translatable fields for products.

# `put`

```elixir
@spec put(struct(), atom(), String.t(), any()) :: struct()
```

Sets a localized value for a language.

Returns the updated entity struct (not persisted to database).

## Examples

    iex> product = Translations.put(product, :title, "ru", "Новое кашпо")
    %Product{title: %{"en" => "Planter", "ru" => "Новое кашпо"}}

# `put_all`

```elixir
@spec put_all(struct(), String.t(), map()) :: struct()
```

Sets multiple translated fields for a language.

Returns the updated entity struct (not persisted to database).

## Examples

    iex> product = Translations.put_all(product, "es", %{title: "Maceta", slug: "maceta"})
    %Product{title: %{"en" => "Planter", "es" => "Maceta"}, ...}

# `put_field`

```elixir
@spec put_field(struct(), atom(), String.t(), any()) :: struct()
```

DEPRECATED: Use `put/4` instead.

This function exists for backward compatibility during migration.

# `translatable_fields`

```elixir
@spec translatable_fields(struct()) :: [atom()]
```

Returns translatable fields based on entity type.

# `translation_changeset_attrs`

```elixir
@spec translation_changeset_attrs(map() | nil, String.t(), map()) :: map()
```

DEPRECATED: Use `changeset_attrs_multi/3` instead.

Builds changeset attrs for updating translations.
This function adapts the old API to the new localized fields approach.

# `translation_status`

```elixir
@spec translation_status(struct(), String.t(), [atom()] | nil) :: map()
```

Gets translation completeness for a language across all translatable fields.

## Examples

    iex> Translations.translation_status(product, "ru")
    %{complete: 4, total: 6, percentage: 67, missing: [:body_html, :seo_description]}

---

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