logo

pleroma

My custom branche(s) on git.pleroma.social/pleroma/pleroma git clone https://anongit.hacktivis.me/git/pleroma.git/
commit: 0dfcc24d30b3b33980ae7780b5c08bd28317399c
parent ba8b5682ccd77a819f644e714deab217195b4879
Author: nicole mikołajczyk <me@mkljczk.pl>
Date:   Sat, 29 Nov 2025 16:50:42 +0100

Merge branch 'translation-provider-translatelocally' into 'develop'

Support translateLocally translation provider

See merge request pleroma/pleroma!4377

Diffstat:

Achangelog.d/translation-provider-translatelocally.add1+
Mconfig/description.exs11++++++++++-
Alib/pleroma/language/translation/translate_locally.ex129+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atest/pleroma/language/translation/translate_locally_test.exs59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 199 insertions(+), 1 deletion(-)

diff --git a/changelog.d/translation-provider-translatelocally.add b/changelog.d/translation-provider-translatelocally.add @@ -0,0 +1 @@ +Support translateLocally translation provider diff --git a/config/description.exs b/config/description.exs @@ -3559,7 +3559,8 @@ config :pleroma, :config_description, [ suggestions: [ Pleroma.Language.Translation.Deepl, Pleroma.Language.Translation.Libretranslate, - Pleroma.Language.Translation.Mozhi + Pleroma.Language.Translation.Mozhi, + Pleroma.Language.Translation.TranslateLocally ] }, %{ @@ -3591,6 +3592,14 @@ config :pleroma, :config_description, [ suggestions: ["YOUR_API_KEY"] }, %{ + group: {:subgroup, Pleroma.Language.Translation.TranslateLocally}, + key: :intermediary_language, + label: + "translateLocally intermediary language (used when direct source->target model is not available)", + type: :string, + suggestions: ["en"] + }, + %{ group: {:subgroup, Pleroma.Language.Translation.Mozhi}, key: :base_url, label: "Mozhi instance URL", diff --git a/lib/pleroma/language/translation/translate_locally.ex b/lib/pleroma/language/translation/translate_locally.ex @@ -0,0 +1,129 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Language.Translation.TranslateLocally do + alias Pleroma.Language.Translation.Provider + + use Provider + + @behaviour Provider + + @name "translateLocally" + + @impl Provider + def missing_dependencies do + if Pleroma.Utils.command_available?("translateLocally") do + [] + else + ["translateLocally"] + end + end + + @impl Provider + def configured?, do: is_map(models()) + + @impl Provider + def translate(content, source_language, target_language) do + model = + models() + |> Map.get(source_language, %{}) + |> Map.get(target_language) + + models = + if model do + [model] + else + [ + models() + |> Map.get(source_language, %{}) + |> Map.get(intermediary_language()), + models() + |> Map.get(intermediary_language(), %{}) + |> Map.get(target_language) + ] + end + + translated_content = + Enum.reduce(models, content, fn model, content -> + text_path = Path.join(System.tmp_dir!(), "translateLocally-#{Ecto.UUID.generate()}") + + File.write(text_path, content) + + translated_content = + case System.cmd("translateLocally", ["-m", model, "-i", text_path, "--html"]) do + {content, _} -> content + _ -> nil + end + + File.rm(text_path) + + translated_content + end) + + {:ok, + %{ + content: translated_content, + detected_source_language: source_language, + provider: @name + }} + end + + @impl Provider + def supported_languages(:source) do + languages = + languages_matrix() + |> elem(1) + |> Map.keys() + + {:ok, languages} + end + + @impl Provider + def supported_languages(:target) do + languages = + languages_matrix() + |> elem(1) + |> Map.values() + |> List.flatten() + |> Enum.uniq() + + {:ok, languages} + end + + @impl Provider + def languages_matrix do + languages = + models() + |> Map.to_list() + |> Enum.map(fn {key, value} -> {key, Map.keys(value)} end) + |> Enum.into(%{}) + + matrix = + if intermediary_language() do + languages + |> Map.to_list() + |> Enum.map(fn {key, value} -> + with_intermediary = + (((value ++ languages[intermediary_language()]) + |> Enum.uniq()) -- + [key]) + |> Enum.sort() + + {key, with_intermediary} + end) + |> Enum.into(%{}) + else + languages + end + + {:ok, matrix} + end + + @impl Provider + def name, do: @name + + defp models, do: Pleroma.Config.get([__MODULE__, :models]) + + defp intermediary_language, do: Pleroma.Config.get([__MODULE__, :intermediary_language]) +end diff --git a/test/pleroma/language/translation/translate_locally_test.exs b/test/pleroma/language/translation/translate_locally_test.exs @@ -0,0 +1,59 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2024 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.Language.Translation.TranslateLocallyTest do + use Pleroma.DataCase + + alias Pleroma.Language.Translation.TranslateLocally + + @example_models %{ + "de" => %{ + "en" => "de-en-base" + }, + "en" => %{ + "de" => "en-de-base", + "pl" => "en-pl-tiny" + }, + "cs" => %{ + "en" => "cs-en-base" + }, + "pl" => %{ + "en" => "pl-en-tiny" + } + } + + test "it returns languages list" do + clear_config([Pleroma.Language.Translation.TranslateLocally, :models], @example_models) + + assert {:ok, languages} = TranslateLocally.supported_languages(:source) + assert ["cs", "de", "en", "pl"] = languages |> Enum.sort() + end + + describe "it returns languages matrix" do + test "without intermediary language" do + clear_config([Pleroma.Language.Translation.TranslateLocally, :models], @example_models) + + assert {:ok, + %{ + "cs" => ["en"], + "de" => ["en"], + "en" => ["de", "pl"], + "pl" => ["en"] + }} = TranslateLocally.languages_matrix() + end + + test "with intermediary language" do + clear_config([Pleroma.Language.Translation.TranslateLocally, :models], @example_models) + clear_config([Pleroma.Language.Translation.TranslateLocally, :intermediary_language], "en") + + assert {:ok, + %{ + "cs" => ["de", "en", "pl"], + "de" => ["en", "pl"], + "en" => ["de", "pl"], + "pl" => ["de", "en"] + }} = TranslateLocally.languages_matrix() + end + end +end