# `PhoenixKitAI.Components.AITranslate`
[🔗](https://github.com/BeamLabEU/phoenix_kit_ai/blob/0.19.3/lib/phoenix_kit_ai/components/ai_translate.ex#L1)

Shared AI-translation UI for multilang form LiveViews — the
publishing/projects-style trigger button + modal, on top of core's
`PhoenixKitAI.Translations` pipeline.

Render-only function components driven by a single `ai_translate` config
map the host LV builds each render; the host owns the state + event
handlers (see `PhoenixKitAI.Translations` for the backend and
any consumer's form LV for the wiring shape). Five surfaces:

  * `<.ai_multilang_tabs>` — core's multilang tabs with the
    button/progress/hint row bundled underneath in the canonical
    placement; the preferred entry point for new consumers (the modal
    still renders separately — see its doc).
  * `<.ai_translate_button>` — compact "AI Translate" trigger; toggles
    the modal. Spinner while a job is in flight.
  * `<.ai_translate_modal>` — daisyUI dialog: endpoint + prompt
    selectors, a "Generate Default Prompt" button when none exists, a
    scope picker (missing-only / all-overwrite / current tab), in-flight
    status, and one scope-driven "Translate" action.
  * `<.ai_translate_progress>` — slim inline progress bar for the session.
  * `<.ai_translate_hint>` — the "taking a while…" stall reassurance.

## Host contract

Pass `ai_translate: %{...}` (string OR atom keys accepted):

    %{
      enabled: true,                  # gates render
      event: "translate_lang",        # dispatch (phx-value-lang)
      toggle_event: "toggle_ai",      # open/close modal
      select_endpoint_event: "...",   # endpoint dropdown change
      select_prompt_event: "...",     # prompt dropdown change
      select_scope_event: "...",      # scope radio change
      generate_prompt_event: "...",   # generate-default-prompt
      missing: ["es", "de"],          # langs lacking a translation
      all_langs: ["es", "de", "fr"],  # every non-primary enabled lang
      in_flight: ["es"],              # jobs running now
      modal_open: false,
      endpoints: [{uuid, name}, ...],
      prompts: [{uuid, name}, ...],
      selected_endpoint_uuid: "...",
      selected_prompt_uuid: "...",
      scope: :missing,                # :missing | :all | :current
      default_prompt_exists: true,
      current_lang: "es",
      primary_lang: "en",
      primary_lang_name: "English",
      # progress bar (optional):
      translation_status: :in_progress, # nil | :in_progress | :completed
      translation_progress: 1,
      translation_total: 3
    }

## Action contract

The modal's single "Translate" button sends `event` with a `lang` value
driven by `scope`:

  - `:missing` → `phx-value-lang="*"` (bulk, missing only)
  - `:all`     → `phx-value-lang="**"` (bulk, overwrite all non-primary)
  - `:current` → `phx-value-lang=<current_lang>` (single)

Host's `handle_event(event, %{"lang" => lang}, socket)` branches on `"*"`,
`"**"`, or a concrete code.

## Placement

The modal contains its own `<form phx-change>` selectors — HTML forbids
nested forms, so render `<.ai_translate_modal>` **outside** (after) the
host's outer `</.form>`. The button can live inside the form. Both take
the same config map; build it once and pass to both.

# `ai_multilang_tabs`

Core's `<.multilang_tabs>` with the AI-translate row bundled underneath —
the "just enable it" wrapper for the canonical placement every consumer
was hand-building (a compact button/progress/hint row tucked under the
tabs). Attrs mirror `PhoenixKitWeb.Components.MultilangForm.multilang_tabs/1`
plus the `ai_translate` config map from `FormGlue.ai_translate_config/1`;
when that is nil or disabled, the tabs render exactly as core's component
alone would, so the attr is safe to pass unconditionally.

    <.ai_multilang_tabs
      multilang_enabled={@multilang_enabled}
      language_tabs={@language_tabs}
      current_lang={@current_lang}
      ai_translate={FormGlue.ai_translate_config(assigns)}
    />

The modal is NOT bundled — it carries its own selector `<form>`s and HTML
forbids nesting, so keep `<.ai_translate_modal>` outside (after) the host's
outer `</.form>` as before.

Rendering alone is not enough: the config comes from the LV wiring —
`use PhoenixKitAI.Components.AITranslate.Embed` (event/PubSub hooks) plus a
`FormGlue.assign_ai_translation/4` call in mount with the consumer's
`FormBinding`. Without it the config is nil and this renders tabs-only.

`class` and `ai_row_class` defaults are tuned as a pair (the row is a
sibling of the tabs div and pads itself to match `card-body`); override
both together when embedding in a container that owns the padding.

## Attributes

* `multilang_enabled` (`:boolean`) (required)
* `language_tabs` (`:list`) (required)
* `current_lang` (`:string`) (required)
* `compact` (`:boolean`) - Defaults to `nil`.
* `show_header` (`:boolean`) - Defaults to `false`.
* `show_info` (`:boolean`) - Defaults to `false`.
* `class` (`:string`) - Defaults to `"card-body pb-0"`.
* `ai_translate` (`:map`) - FormGlue config map; nil or disabled renders the tabs alone. Defaults to `nil`.
* `ai_row_class` (`:any`) - Class of the button/progress/hint row under the tabs. Tuned as a PAIR
  with `class`: replace `class` (e.g. with "" inside an already-padded
  container) and adjust this to match — typically dropping the px-6.

  Defaults to `"flex items-center gap-3 -mt-3 px-6"`.

# `ai_translate_button`

Compact trigger button. Hidden when disabled / no toggle event.
## Attributes

* `ai_translate` (`:map`) - Config map — see moduledoc. Defaults to `nil`.

# `ai_translate_hint`

Reassurance line shown when a translation is taking a while (`slow: true`
in the config while jobs are still in flight). A leading attention icon
flags the line, then the visible message, then a trailing info icon whose
tooltip carries the fuller "you can leave, nothing is lost" detail.
Renders nothing otherwise.

## Attributes

* `ai_translate` (`:map`) - Same config map; reads `:slow` + `:in_flight`. Defaults to `nil`.

# `ai_translate_modal`

Modal dialog: endpoint/prompt selectors + scope picker + action.
## Attributes

* `ai_translate` (`:map`) - Config map — see moduledoc. Defaults to `nil`.

# `ai_translate_progress`

Slim inline session progress bar. Renders once a dispatch has started.
## Attributes

* `ai_translate` (`:map`) (required) - Same config map; reads translation_status/progress/total.
* `wrapper_class` (`:string`) - Defaults to `"flex-1 min-w-0"`.
* `class` (`:string`) - Defaults to `"progress h-2 w-full block"`.

---

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