diff --git a/lib/pleroma/akkoma/translators/deepl.ex b/lib/pleroma/akkoma/translators/deepl.ex index f93fb7e59..da6b8a582 100644 --- a/lib/pleroma/akkoma/translators/deepl.ex +++ b/lib/pleroma/akkoma/translators/deepl.ex @@ -23,12 +23,21 @@ defp tier do @impl Pleroma.Akkoma.Translator def languages do - with {:ok, %{status: 200} = response} <- do_languages(), - {:ok, body} <- Jason.decode(response.body) do - resp = - Enum.map(body, fn %{"language" => code, "name" => name} -> %{code: code, name: name} end) + with {:ok, %{status: 200} = source_response} <- do_languages("source"), + {:ok, %{status: 200} = dest_response} <- do_languages("target"), + {:ok, source_body} <- Jason.decode(source_response.body), + {:ok, dest_body} <- Jason.decode(dest_response.body) do + source_resp = + Enum.map(source_body, fn %{"language" => code, "name" => name} -> + %{code: code, name: name} + end) - {:ok, resp} + dest_resp = + Enum.map(dest_body, fn %{"language" => code, "name" => name} -> + %{code: code, name: name} + end) + + {:ok, source_resp, dest_resp} else {:ok, %{status: status} = response} -> Logger.warning("DeepL: Request rejected: #{inspect(response)}") @@ -80,9 +89,9 @@ defp do_request(api_key, tier, string, from_language, to_language) do defp maybe_add_source(opts, nil), do: opts defp maybe_add_source(opts, lang), do: Map.put(opts, :source_lang, lang) - defp do_languages() do + defp do_languages(type) do HTTP.get( - base_url(tier()) <> "languages?type=target", + base_url(tier()) <> "languages?type=#{type}", [ {"authorization", "DeepL-Auth-Key #{api_key()}"} ] diff --git a/lib/pleroma/akkoma/translators/libre_translate.ex b/lib/pleroma/akkoma/translators/libre_translate.ex index 319907c2f..3a8d9d827 100644 --- a/lib/pleroma/akkoma/translators/libre_translate.ex +++ b/lib/pleroma/akkoma/translators/libre_translate.ex @@ -18,7 +18,8 @@ def languages do with {:ok, %{status: 200} = response} <- do_languages(), {:ok, body} <- Jason.decode(response.body) do resp = Enum.map(body, fn %{"code" => code, "name" => name} -> %{code: code, name: name} end) - {:ok, resp} + # No separate source/dest + {:ok, resp, resp} else {:ok, %{status: status} = response} -> Logger.warning("LibreTranslate: Request rejected: #{inspect(response)}") diff --git a/lib/pleroma/akkoma/translators/translator.ex b/lib/pleroma/akkoma/translators/translator.ex index aa49b0655..93fbeb3b9 100644 --- a/lib/pleroma/akkoma/translators/translator.ex +++ b/lib/pleroma/akkoma/translators/translator.ex @@ -1,5 +1,8 @@ defmodule Pleroma.Akkoma.Translator do @callback translate(String.t(), String.t() | nil, String.t()) :: {:ok, String.t(), String.t()} | {:error, any()} - @callback languages() :: {:ok, [%{name: String.t(), code: String.t()}]} | {:error, any()} + @callback languages() :: + {:ok, [%{name: String.t(), code: String.t()}], + [%{name: String.t(), code: String.t()}]} + | {:error, any()} end diff --git a/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex b/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex index 49ef89a50..9983a7e39 100644 --- a/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex +++ b/lib/pleroma/web/akkoma_api/controllers/translation_controller.ex @@ -21,9 +21,9 @@ defmodule Pleroma.Web.AkkomaAPI.TranslationController do @doc "GET /api/v1/akkoma/translation/languages" def languages(conn, _params) do - with {:ok, languages} <- get_languages() do + with {:ok, source_languages, dest_languages} <- get_languages() do conn - |> json(languages) + |> json(%{source: source_languages, target: dest_languages}) else e -> IO.inspect(e) end @@ -33,8 +33,8 @@ defp get_languages do module = Pleroma.Config.get([:translator, :module]) @cachex.fetch!(:translations_cache, "languages:#{module}}", fn _ -> - with {:ok, languages} <- module.languages() do - {:ok, languages} + with {:ok, source_languages, dest_languages} <- module.languages() do + {:ok, source_languages, dest_languages} else {:error, err} -> {:ignore, {:error, err}} end diff --git a/lib/pleroma/web/api_spec/operations/translate_operation.ex b/lib/pleroma/web/api_spec/operations/translate_operation.ex index aa3b69a18..bf0280319 100644 --- a/lib/pleroma/web/api_spec/operations/translate_operation.ex +++ b/lib/pleroma/web/api_spec/operations/translate_operation.ex @@ -17,22 +17,34 @@ def languages_operation() do operationId: "AkkomaAPI.TranslationController.languages", security: [%{"oAuth" => ["read:statuses"]}], responses: %{ - 200 => Operation.response("Translation", "application/json", languages_schema()) + 200 => + Operation.response("Translation", "application/json", source_dest_languages_schema()) + } + } + end + + defp source_dest_languages_schema do + %Schema{ + type: :object, + required: [:source, :target], + properties: %{ + source: languages_schema(), + target: languages_schema() } } end defp languages_schema do %Schema{ - type: "array", + type: :array, items: %Schema{ - type: "object", + type: :object, properties: %{ code: %Schema{ - type: "string" + type: :string }, name: %Schema{ - type: "string" + type: :string } } } diff --git a/test/pleroma/translators/deepl_test.exs b/test/pleroma/translators/deepl_test.exs index 58f23fe26..d85bef982 100644 --- a/test/pleroma/translators/deepl_test.exs +++ b/test/pleroma/translators/deepl_test.exs @@ -32,9 +32,23 @@ test "should list supported languages" do } ]) } + + %{method: :get, url: "https://api-free.deepl.com/v2/languages?type=source"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!([ + %{ + "language" => "JA", + "name" => "Japanese", + "supports_formality" => false + } + ]) + } end) - assert {:ok, [%{code: "BG", name: "Bulgarian"}, %{code: "CS", name: "Czech"}]} = + assert {:ok, [%{code: "JA", name: "Japanese"}], + [%{code: "BG", name: "Bulgarian"}, %{code: "CS", name: "Czech"}]} = DeepL.languages() end diff --git a/test/pleroma/translators/libre_translate_test.exs b/test/pleroma/translators/libre_translate_test.exs index d28d9278a..3c81c3d76 100644 --- a/test/pleroma/translators/libre_translate_test.exs +++ b/test/pleroma/translators/libre_translate_test.exs @@ -29,7 +29,8 @@ test "should list supported languages" do } end) - assert {:ok, [%{code: "en", name: "English"}, %{code: "ar", name: "Arabic"}]} = + assert {:ok, [%{code: "en", name: "English"}, %{code: "ar", name: "Arabic"}], + [%{code: "en", name: "English"}, %{code: "ar", name: "Arabic"}]} = LibreTranslate.languages() end diff --git a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs index e38f5fe58..f76ab3d0d 100644 --- a/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs +++ b/test/pleroma/web/mastodon_api/controllers/status_controller_test.exs @@ -2080,6 +2080,40 @@ test "posting a quote of a status that doesn't exist", %{conn: conn} do oauth_access(["read:statuses"]) end + test "listing languages", %{conn: conn} do + Tesla.Mock.mock_global(fn + %{method: :get, url: "https://api-free.deepl.com/v2/languages?type=source"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!([ + %{language: "en", name: "English"} + ]) + } + + %{method: :get, url: "https://api-free.deepl.com/v2/languages?type=target"} -> + %Tesla.Env{ + status: 200, + body: + Jason.encode!([ + %{language: "ja", name: "Japanese"} + ]) + } + end) + + conn = + conn + |> put_req_header("content-type", "application/json") + |> get("/api/v1/akkoma/translation/languages") + + response = json_response_and_validate_schema(conn, 200) + + assert %{ + "source" => [%{"code" => "en", "name" => "English"}], + "target" => [%{"code" => "ja", "name" => "Japanese"}] + } = response + end + test "should return text and detected language", %{conn: conn} do clear_config([:deepl, :tier], :free)