add seperate source and dest entries in language listing (#193)

Co-authored-by: FloatingGhost <hannah@coffee-and-dreams.uk>
Reviewed-on: https://akkoma.dev/AkkomaGang/akkoma/pulls/193
This commit is contained in:
floatingghost 2022-08-30 16:59:33 +00:00
parent c3fde9577d
commit decbca0c91
8 changed files with 94 additions and 20 deletions

View file

@ -23,12 +23,21 @@ defp tier do
@impl Pleroma.Akkoma.Translator @impl Pleroma.Akkoma.Translator
def languages do def languages do
with {:ok, %{status: 200} = response} <- do_languages(), with {:ok, %{status: 200} = source_response} <- do_languages("source"),
{:ok, body} <- Jason.decode(response.body) do {:ok, %{status: 200} = dest_response} <- do_languages("target"),
resp = {:ok, source_body} <- Jason.decode(source_response.body),
Enum.map(body, fn %{"language" => code, "name" => name} -> %{code: code, name: name} end) {: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 else
{:ok, %{status: status} = response} -> {:ok, %{status: status} = response} ->
Logger.warning("DeepL: Request rejected: #{inspect(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, nil), do: opts
defp maybe_add_source(opts, lang), do: Map.put(opts, :source_lang, lang) defp maybe_add_source(opts, lang), do: Map.put(opts, :source_lang, lang)
defp do_languages() do defp do_languages(type) do
HTTP.get( HTTP.get(
base_url(tier()) <> "languages?type=target", base_url(tier()) <> "languages?type=#{type}",
[ [
{"authorization", "DeepL-Auth-Key #{api_key()}"} {"authorization", "DeepL-Auth-Key #{api_key()}"}
] ]

View file

@ -18,7 +18,8 @@ def languages do
with {:ok, %{status: 200} = response} <- do_languages(), with {:ok, %{status: 200} = response} <- do_languages(),
{:ok, body} <- Jason.decode(response.body) do {:ok, body} <- Jason.decode(response.body) do
resp = Enum.map(body, fn %{"code" => code, "name" => name} -> %{code: code, name: name} end) resp = Enum.map(body, fn %{"code" => code, "name" => name} -> %{code: code, name: name} end)
{:ok, resp} # No separate source/dest
{:ok, resp, resp}
else else
{:ok, %{status: status} = response} -> {:ok, %{status: status} = response} ->
Logger.warning("LibreTranslate: Request rejected: #{inspect(response)}") Logger.warning("LibreTranslate: Request rejected: #{inspect(response)}")

View file

@ -1,5 +1,8 @@
defmodule Pleroma.Akkoma.Translator do defmodule Pleroma.Akkoma.Translator do
@callback translate(String.t(), String.t() | nil, String.t()) :: @callback translate(String.t(), String.t() | nil, String.t()) ::
{:ok, String.t(), String.t()} | {:error, any()} {: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 end

View file

@ -21,9 +21,9 @@ defmodule Pleroma.Web.AkkomaAPI.TranslationController do
@doc "GET /api/v1/akkoma/translation/languages" @doc "GET /api/v1/akkoma/translation/languages"
def languages(conn, _params) do def languages(conn, _params) do
with {:ok, languages} <- get_languages() do with {:ok, source_languages, dest_languages} <- get_languages() do
conn conn
|> json(languages) |> json(%{source: source_languages, target: dest_languages})
else else
e -> IO.inspect(e) e -> IO.inspect(e)
end end
@ -33,8 +33,8 @@ defp get_languages do
module = Pleroma.Config.get([:translator, :module]) module = Pleroma.Config.get([:translator, :module])
@cachex.fetch!(:translations_cache, "languages:#{module}}", fn _ -> @cachex.fetch!(:translations_cache, "languages:#{module}}", fn _ ->
with {:ok, languages} <- module.languages() do with {:ok, source_languages, dest_languages} <- module.languages() do
{:ok, languages} {:ok, source_languages, dest_languages}
else else
{:error, err} -> {:ignore, {:error, err}} {:error, err} -> {:ignore, {:error, err}}
end end

View file

@ -17,22 +17,34 @@ def languages_operation() do
operationId: "AkkomaAPI.TranslationController.languages", operationId: "AkkomaAPI.TranslationController.languages",
security: [%{"oAuth" => ["read:statuses"]}], security: [%{"oAuth" => ["read:statuses"]}],
responses: %{ 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 end
defp languages_schema do defp languages_schema do
%Schema{ %Schema{
type: "array", type: :array,
items: %Schema{ items: %Schema{
type: "object", type: :object,
properties: %{ properties: %{
code: %Schema{ code: %Schema{
type: "string" type: :string
}, },
name: %Schema{ name: %Schema{
type: "string" type: :string
} }
} }
} }

View file

@ -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) 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() DeepL.languages()
end end

View file

@ -29,7 +29,8 @@ test "should list supported languages" do
} }
end) 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() LibreTranslate.languages()
end end

View file

@ -2080,6 +2080,40 @@ test "posting a quote of a status that doesn't exist", %{conn: conn} do
oauth_access(["read:statuses"]) oauth_access(["read:statuses"])
end 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 test "should return text and detected language", %{conn: conn} do
clear_config([:deepl, :tier], :free) clear_config([:deepl, :tier], :free)