PhoenixKitEcommerce.AITranslatable (PhoenixKitEcommerce v0.2.0)

Copy Markdown View Source

PhoenixKitAI.Translatable adapter for shop products.

Resource identity

resource_type is "shop_product"; resource_uuid is the product uuid.

Fields

%{"title", "description", "body", "seo_title", "seo_description"} from the source language (Translations.get/3), non-empty only. "body" maps to the schema's body_html (the shared prompt vocabulary uses body). The slug is NEVER sourced from or trusted to the AI — it is regenerated locally from the translated title, and only when the target language has no slug yet, so re-translations can't change published URLs (which is why no slug-history/redirect machinery is needed).

Concurrency

All languages share ONE product row's JSONB maps, so put_translation/4 re-reads the row under FOR UPDATE and merges against the latest committed state (the publishing group-adapter pattern) — concurrent per-language jobs serialize on the row lock and never drop a sibling language. update_product/2 / update_product_translation/3 are deliberately NOT used here: they write a stale in-memory struct without a lock — the exact lost-update race this adapter must prevent.

Slug uniqueness within the language is checked app-side (suffix on collision); there is no DB unique constraint on the JSONB slug map (core migration v47 dropped it), so the check is best-effort across rows.

Prompt

The seo fields are not in the shared translation prompt's vocabulary, so this adapter ships its own prompt (ensure_prompt/0, slug phoenixkit-shop-product-translation). Host forms must pass its uuid per job — the global ai_translation_prompt_uuid setting stays untouched.

Requires the optional phoenix_kit_ai plugin: ensure_prompt/0 returns {:error, :ai_not_installed} when it is absent, and the whole adapter is only reached through duck-typed discovery, which never runs without it.

Summary

Functions

Idempotently creates this adapter's translation prompt and returns its uuid — host forms pass it per job instead of the shared default prompt.

The resource-type key this adapter registers under.

Functions

ensure_prompt()

@spec ensure_prompt() :: {:ok, String.t()} | {:error, term()}

Idempotently creates this adapter's translation prompt and returns its uuid — host forms pass it per job instead of the shared default prompt.

fetch(arg1, product_uuid)

put_translation(product, target_lang, fields, opts)

resource_type()

The resource-type key this adapter registers under.

source_fields(product, source_lang)