PhoenixKitAI.Components.AITranslate (PhoenixKitAI v0.17.0)

Copy Markdown View Source

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:

  • :missingphx-value-lang="*" (bulk, missing only)
  • :allphx-value-lang="**" (bulk, overwrite all non-primary)
  • :currentphx-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.

Summary

Functions

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.

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

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.

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

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

Functions

ai_multilang_tabs(assigns)

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 true.

  • show_info (:boolean) - Defaults to true.

  • 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(assigns)

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

Attributes

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

ai_translate_hint(assigns)

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(assigns)

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

Attributes

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

ai_translate_progress(assigns)

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".