Reloading is necessary to detect changes in the changeset. Otherwise simple changes like changing the value of translation.public wouldn't get noticed and not being saved to db.
213 lines
8.0 KiB
Elixir
213 lines
8.0 KiB
Elixir
defmodule OutlookWeb.TranslationLive.FormComponent do
|
|
use OutlookWeb, :live_component
|
|
|
|
alias Outlook.{Translations,InternalTree}
|
|
alias Outlook.InternalTree.{TranslationUnit,Html}
|
|
|
|
@impl true
|
|
def render(assigns) do
|
|
~H"""
|
|
<div class="flex gap-8 max-h-fit">
|
|
<div class="basis-1/2 overflow-auto">
|
|
<.header>
|
|
<%= @title %>
|
|
<:subtitle>Use this form to manage translation records in your database.</:subtitle>
|
|
</.header>
|
|
|
|
<.simple_form
|
|
:let={f}
|
|
for={@changeset}
|
|
id="translation-form"
|
|
phx-target={@myself}
|
|
phx-change="validate"
|
|
phx-submit="save"
|
|
>
|
|
<.input field={{f, :article_id}} type="hidden" />
|
|
<.input field={{f, :language}} type="select" label="language"
|
|
options={Application.get_env(:outlook,:deepl)[:target_langs]} />
|
|
<.input field={{f, :title}} type="text" label="title" />
|
|
<.input field={{f, :teaser}} type="textarea" label="teaser" class="h-28" />
|
|
<.input field={{f, :date}} type="datetime-local" label="date" />
|
|
<div class="flex items-center justify-between">
|
|
<.input field={{f, :public}} type="checkbox" label="public" />
|
|
<.input field={{f, :unauthorized}} type="checkbox" label="unauthorized" />
|
|
</div>
|
|
<input type="hidden" id="continue_edit" name="continue_edit" value="false" />
|
|
<input type="hidden" id="publish" name="publish" value="false" />
|
|
<:actions>
|
|
<.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")}
|
|
phx-disable-with="Saving...">Save Translation</.button>
|
|
<.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "true"}, to: "#publish")}
|
|
phx-disable-with="Saving...">Save and Publish</.button>
|
|
<.button phx-click={JS.set_attribute({"value", "true"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")}
|
|
phx-disable-with="Saving...">Save and Edit</.button>
|
|
</:actions>
|
|
</.simple_form>
|
|
<.tunit_editor current_tunit={@current_tunit} target={@myself} />
|
|
</div>
|
|
<div class="article basis-1/2 max-h-screen overflow-auto">
|
|
<.button phx-disable-with="Translating..." phx-click="translate-deepl" phx-target={@myself}
|
|
data-confirm-not="Are you sure? All previously translated text will be lost.">Translate with Deepl</.button>
|
|
<progress :if={@deepl_progress} max="100" value={@deepl_progress} />
|
|
<.render_doc tree={@article_tree} />
|
|
</div>
|
|
</div>
|
|
"""
|
|
end
|
|
|
|
@impl true
|
|
def update(%{translation: translation} = assigns, socket) do
|
|
changeset = Translations.change_translation(translation)
|
|
|
|
{:ok,
|
|
socket
|
|
|> assign(assigns)
|
|
|> assign(:current_tunit, %TranslationUnit{status: nil})
|
|
|> assign(:changeset, changeset)
|
|
|> assign_article_tree(translation)
|
|
|> assign(:deepl_progress, nil)}
|
|
end
|
|
|
|
def update(%{progress: progress}, socket) do
|
|
{:ok, socket |> assign(deepl_progress: progress)}
|
|
end
|
|
|
|
def update(%{deepl_translation: translation}, socket) do
|
|
tunit_keys = Map.keys(socket.assigns.translation_content)
|
|
case Outlook.Translators.process_translation_result(translation, tunit_keys, socket.assigns.current_user) do
|
|
{:ok, new_translation_content} ->
|
|
{:ok, socket
|
|
|> assign(translation_content: new_translation_content)
|
|
|> update_current_tunit(socket.assigns.current_tunit.status)}
|
|
{:error, message} ->
|
|
{:ok, socket |> put_flash(:error, message)}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_event("translate-deepl", _, socket) do
|
|
Outlook.Translators.translate(socket.assigns.translation, socket.assigns.current_user)
|
|
{:noreply, socket}
|
|
end
|
|
|
|
def handle_event("validate", %{"translation" => translation_params}, socket) do
|
|
changeset =
|
|
socket.assigns.translation
|
|
|> Translations.change_translation(translation_params)
|
|
|> Map.put(:action, :validate)
|
|
|
|
{:noreply, assign(socket, :changeset, changeset)}
|
|
end
|
|
|
|
def handle_event("save", %{"translation" => translation_params} = params, socket) do
|
|
socket = socket
|
|
|> update_translation_with_current_tunit(socket.assigns.current_tunit.status)
|
|
params = %{params |
|
|
"translation" => Map.put(
|
|
translation_params,
|
|
"content",
|
|
socket.assigns.translation_content
|
|
)
|
|
|> publish(params, socket)
|
|
}
|
|
save_translation(socket, socket.assigns.action, params)
|
|
end
|
|
|
|
def handle_event("tunit_status", %{"status" => status}, socket) do
|
|
tunit = %TranslationUnit{socket.assigns.current_tunit | status: String.to_atom(status)}
|
|
{:noreply, socket |> assign(:current_tunit, tunit)}
|
|
end
|
|
|
|
def handle_event("select_current_tunit", %{"nid" => nid}, socket) do
|
|
{:noreply,
|
|
socket
|
|
|> update_translation_with_current_tunit(socket.assigns.current_tunit.status)
|
|
|> assign(:current_tunit, socket.assigns.translation_content[nid])}
|
|
end
|
|
|
|
@doc "updating on browser events"
|
|
def handle_event("update_current_tunit", %{"content" => content}, socket) do
|
|
tunit = %TranslationUnit{socket.assigns.current_tunit | content: content}
|
|
{:noreply, socket |> assign(:current_tunit, tunit)}
|
|
end
|
|
|
|
|
|
# updating after Deepl translation
|
|
defp update_current_tunit(socket, nil), do: socket
|
|
defp update_current_tunit(socket, _) do
|
|
assign(socket,
|
|
:current_tunit,
|
|
socket.assigns.translation_content[socket.assigns.current_tunit.nid])
|
|
end
|
|
|
|
defp assign_article_tree(socket, translation) do
|
|
socket
|
|
|> assign(
|
|
:article_tree,
|
|
InternalTree.add_phx_click_event(translation.article.content,
|
|
nodes: :tunits,
|
|
click: "select_current_tunit",
|
|
target: socket.assigns.myself)
|
|
|> InternalTree.garnish(%{tunits: %{class: "tunit"}}))
|
|
end
|
|
|
|
defp update_translation_with_current_tunit(socket, nil), do: socket
|
|
defp update_translation_with_current_tunit(socket, _) do
|
|
socket
|
|
|> assign(:translation_content,
|
|
socket.assigns.translation_content
|
|
|> Map.put(socket.assigns.current_tunit.nid, socket.assigns.current_tunit))
|
|
end
|
|
|
|
defp save_translation(socket, :edit, %{"translation" => translation_params} = params) do
|
|
case Translations.update_translation(socket.assigns.translation, translation_params) do
|
|
{:ok, _translation} ->
|
|
{:noreply,
|
|
socket
|
|
|> put_flash(:info, "Translation updated successfully")
|
|
|> continue_edit(:edit, params)}
|
|
|
|
{:error, %Ecto.Changeset{} = changeset} ->
|
|
{:noreply, assign(socket, :changeset, changeset)}
|
|
end
|
|
end
|
|
|
|
defp save_translation(socket, :new, %{"translation" => translation_params} = params) do
|
|
case Translations.create_translation(translation_params) do
|
|
{:ok, translation} ->
|
|
{:noreply,
|
|
socket
|
|
|> put_flash(:info, "Translation created successfully")
|
|
|> continue_edit(:new, Map.put(params,"id", translation.id))}
|
|
|
|
{:error, %Ecto.Changeset{} = changeset} ->
|
|
{:noreply, assign(socket, changeset: changeset)}
|
|
end
|
|
end
|
|
|
|
defp continue_edit(socket, :edit, %{"continue_edit" => "true"}) do
|
|
socket
|
|
|> assign(:translation, Translations.get_translation!(socket.assigns.translation.id))
|
|
end
|
|
defp continue_edit(socket, :new, %{"continue_edit" => "true"} = params) do
|
|
socket |> push_patch(to: ~p(/translations/#{params["id"]}/edit))
|
|
end
|
|
defp continue_edit(socket, _, %{"continue_edit" => "false"}) do
|
|
socket |> push_navigate(to: socket.assigns.navigate)
|
|
end
|
|
|
|
defp publish(translation_params, %{"publish" => "true"}, socket) do
|
|
translation_params
|
|
|> Map.put("public_content",
|
|
InternalTree.render_public_content(
|
|
socket.assigns.translation.article.content,
|
|
socket.assigns.translation_content,
|
|
socket.assigns.translation.language
|
|
)
|
|
)
|
|
end
|
|
defp publish(translation_params, %{"publish" => "false"}, _) do
|
|
translation_params
|
|
end
|
|
end
|