From 6428acc248204bf9ae67c80f7da9dfacfd8929c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?marcin=20miko=C5=82ajczak?= Date: Sat, 7 Oct 2023 00:49:57 +0200 Subject: [PATCH] Store translations in database MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- lib/pleroma/status_translation.ex | 65 +++++++++++++++++++ .../controllers/status_controller.ex | 10 +-- .../web/mastodon_api/views/status_view.ex | 23 +++++-- ...31005232600_create_status_translations.exs | 21 ++++++ 4 files changed, 108 insertions(+), 11 deletions(-) create mode 100644 lib/pleroma/status_translation.ex create mode 100644 priv/repo/migrations/20231005232600_create_status_translations.exs diff --git a/lib/pleroma/status_translation.ex b/lib/pleroma/status_translation.ex new file mode 100644 index 0000000000..646d23fcd7 --- /dev/null +++ b/lib/pleroma/status_translation.ex @@ -0,0 +1,65 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2022 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.StatusTranslation do + use Ecto.Schema + + import Ecto.Changeset + import Ecto.Query + + alias Pleroma.Language.Translation + alias Pleroma.Object + alias Pleroma.Repo + alias Pleroma.StatusTranslation + + schema "status_translations" do + field(:language, :string) + field(:provider, :string) + field(:detected_source_language, :string) + field(:content, {:map, :string}) + + belongs_to(:object, Object) + + timestamps() + end + + def changeset(%StatusTranslation{} = status_translation, params \\ %{}) do + status_translation + |> cast(params, [:object_id, :language, :provider, :detected_source_language, :content]) + |> validate_required([:object_id, :language, :content]) + |> unique_constraint([:object_id, :language]) + end + + def get(%Object{} = object, language, fetch_unavailable \\ true) do + translation = Repo.get_by(StatusTranslation, object_id: object.id, language: language) + + if translation or not fetch_unavailable do + translation + else + with {:ok, + %{ + content: content, + detected_source_language: detected_source_language, + provider: provider + }} <- + Translation.translate( + object.data["content"], + object.data["language"], + language + ) do + %StatusTranslation{} + |> changeset(%{ + object_id: object.id, + language: language, + provider: provider, + detected_source_language: detected_source_language, + content: %{ + "content" => content + } + }) + |> Repo.insert!() + end + end + end +end diff --git a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex index fc0d046b0f..6891e53b23 100644 --- a/lib/pleroma/web/mastodon_api/controllers/status_controller.ex +++ b/lib/pleroma/web/mastodon_api/controllers/status_controller.ex @@ -592,13 +592,9 @@ def translate( Pleroma.Config.get([Pleroma.Language.Translation, :allow_remote])}, {:language, language} when is_binary(language) <- {:language, Map.get(params, :target_language) || user.language}, - {:ok, result} <- - Translation.translate( - object.data["content"], - object.data["language"], - language - ) do - render(conn, "translation.json", result) + %Pleroma.StatusTranslation{} = result <- + Pleroma.StatusTranslation.get(object, language) do + render(conn, "translation.json", result: result) else {:authentication, false} -> render_error(conn, :unauthorized, "Authorization is required to translate statuses") diff --git a/lib/pleroma/web/mastodon_api/views/status_view.ex b/lib/pleroma/web/mastodon_api/views/status_view.ex index bf4d06a98f..d6dd5c68a8 100644 --- a/lib/pleroma/web/mastodon_api/views/status_view.ex +++ b/lib/pleroma/web/mastodon_api/views/status_view.ex @@ -471,7 +471,8 @@ def render("show.json", %{activity: %{data: %{"object" => _object}} = activity} content_type: opts[:with_source] && (object.data["content_type"] || "text/plain"), quotes_count: object.data["quotesCount"] || 0, event: build_event(object.data, opts[:for]), - bookmark_folder: bookmark_folder + bookmark_folder: bookmark_folder, + translation: get_translation(object, opts[:language]) } } end @@ -480,6 +481,18 @@ def render("show.json", _) do nil end + defp get_translation(object, language) when is_binary(language) do + translation = Pleroma.StatusTranslation.get(object, language) + + if translation do + render("translation.json", %{result: translation}) + else + nil + end + end + + defp get_translation(_, _), do: nil + def render("card.json", %{embed: %Embed{} = embed}) do with {:ok, %Card{} = card} <- Card.parse(embed) do Card.to_map(card) @@ -691,9 +704,11 @@ def render("context.json", %{activity: activity, activities: activities, user: u end def render("translation.json", %{ - content: content, - detected_source_language: detected_source_language, - provider: provider + result: %{ + content: %{"content" => content}, + detected_source_language: detected_source_language, + provider: provider + } }) do %{content: content, detected_source_language: detected_source_language, provider: provider} end diff --git a/priv/repo/migrations/20231005232600_create_status_translations.exs b/priv/repo/migrations/20231005232600_create_status_translations.exs new file mode 100644 index 0000000000..42f1f86854 --- /dev/null +++ b/priv/repo/migrations/20231005232600_create_status_translations.exs @@ -0,0 +1,21 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2023 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Repo.Migrations.CreateStatusTranslations do + use Ecto.Migration + + def change do + create_if_not_exists table(:status_translations) do + add(:object_id, references(:objects, on_delete: :delete_all), null: false) + add(:language, :text, null: false) + add(:provider, :text) + add(:detected_source_language, :text) + add(:content, {:map, :string}) + + timestamps() + end + + create_if_not_exists(unique_index(:status_translations, [:object_id, :language])) + end +end