add seperate source and dest entries in language listing (#193)
authorfloatingghost <hannah@coffee-and-dreams.uk>
Tue, 30 Aug 2022 16:59:33 +0000 (16:59 +0000)
committerfloatingghost <hannah@coffee-and-dreams.uk>
Tue, 30 Aug 2022 16:59:33 +0000 (16:59 +0000)
Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/193

lib/pleroma/akkoma/translators/deepl.ex
lib/pleroma/akkoma/translators/libre_translate.ex
lib/pleroma/akkoma/translators/translator.ex
lib/pleroma/web/akkoma_api/controllers/translation_controller.ex
lib/pleroma/web/api_spec/operations/translate_operation.ex
test/pleroma/translators/deepl_test.exs
test/pleroma/translators/libre_translate_test.exs
test/pleroma/web/mastodon_api/controllers/status_controller_test.exs

index f93fb7e59faa4a3d7c4e438067a866b63fe2e2dd..da6b8a5822de93cfbf043add1100ed36879fe020 100644 (file)
@@ -23,12 +23,21 @@ defmodule Pleroma.Akkoma.Translators.DeepL 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)
+
+      dest_resp =
+        Enum.map(dest_body, fn %{"language" => code, "name" => name} ->
+          %{code: code, name: name}
+        end)
 
-      {:ok, resp}
+      {:ok, source_resp, dest_resp}
     else
       {:ok, %{status: status} = response} ->
         Logger.warning("DeepL: Request rejected: #{inspect(response)}")
@@ -80,9 +89,9 @@ defmodule Pleroma.Akkoma.Translators.DeepL 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()}"}
       ]
index 319907c2ffeb1f68b3d718883767eb25d2a3f8ca..3a8d9d827481d2314e5add4bb43f9b8acdcef151 100644 (file)
@@ -18,7 +18,8 @@ defmodule Pleroma.Akkoma.Translators.LibreTranslate 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)}")
index aa49b065583630d0935c9cf882c5bb8b6e3cd398..93fbeb3b973106a6dd9c3a913b6cfa72d4d21600 100644 (file)
@@ -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
index 49ef89a508774c8a8d48f34e86f1e7070d61ca41..9983a7e3926e83ca45bb6542d72d9ff0fb71396f 100644 (file)
@@ -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 @@ defmodule Pleroma.Web.AkkomaAPI.TranslationController 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
index aa3b69a1867c1cb877538c860609b3068d18eeb6..bf0280319379141c4b6fb8f63476c9cc78ffa4b3 100644 (file)
@@ -17,22 +17,34 @@ defmodule Pleroma.Web.ApiSpec.TranslationOperation 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
           }
         }
       }
index 58f23fe2616a7eb0b171578b8390ec2eecd3ffde..d85bef982ebea3387ddcc2e06b5d8fb1d8498f0b 100644 (file)
@@ -32,9 +32,23 @@ defmodule Pleroma.Akkoma.Translators.DeepLTest 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
 
index d28d9278a9aa2672bd9783f66776c2d18b25da1b..3c81c3d76063941648474e9b8cf133af632126aa 100644 (file)
@@ -29,7 +29,8 @@ defmodule Pleroma.Akkoma.Translators.LibreTranslateTest 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
 
index e38f5fe58d4e5ba6a9fd99cab27cf3f1008ee357..f76ab3d0d91e9cdb5570f815325e344e8a689699 100644 (file)
@@ -2080,6 +2080,40 @@ defmodule Pleroma.Web.MastodonAPI.StatusControllerTest 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)