add seperate source and dest entries in language listing (#193)
[akkoma] / lib / pleroma / akkoma / translators / deepl.ex
1 defmodule Pleroma.Akkoma.Translators.DeepL do
2 @behaviour Pleroma.Akkoma.Translator
3
4 alias Pleroma.HTTP
5 alias Pleroma.Config
6 require Logger
7
8 defp base_url(:free) do
9 "https://api-free.deepl.com/v2/"
10 end
11
12 defp base_url(:pro) do
13 "https://api.deepl.com/v2/"
14 end
15
16 defp api_key do
17 Config.get([:deepl, :api_key])
18 end
19
20 defp tier do
21 Config.get([:deepl, :tier])
22 end
23
24 @impl Pleroma.Akkoma.Translator
25 def languages do
26 with {:ok, %{status: 200} = source_response} <- do_languages("source"),
27 {:ok, %{status: 200} = dest_response} <- do_languages("target"),
28 {:ok, source_body} <- Jason.decode(source_response.body),
29 {:ok, dest_body} <- Jason.decode(dest_response.body) do
30 source_resp =
31 Enum.map(source_body, fn %{"language" => code, "name" => name} ->
32 %{code: code, name: name}
33 end)
34
35 dest_resp =
36 Enum.map(dest_body, fn %{"language" => code, "name" => name} ->
37 %{code: code, name: name}
38 end)
39
40 {:ok, source_resp, dest_resp}
41 else
42 {:ok, %{status: status} = response} ->
43 Logger.warning("DeepL: Request rejected: #{inspect(response)}")
44 {:error, "DeepL request failed (code #{status})"}
45
46 {:error, reason} ->
47 {:error, reason}
48 end
49 end
50
51 @impl Pleroma.Akkoma.Translator
52 def translate(string, from_language, to_language) do
53 with {:ok, %{status: 200} = response} <-
54 do_request(api_key(), tier(), string, from_language, to_language),
55 {:ok, body} <- Jason.decode(response.body) do
56 %{"translations" => [%{"text" => translated, "detected_source_language" => detected}]} =
57 body
58
59 {:ok, detected, translated}
60 else
61 {:ok, %{status: status} = response} ->
62 Logger.warning("DeepL: Request rejected: #{inspect(response)}")
63 {:error, "DeepL request failed (code #{status})"}
64
65 {:error, reason} ->
66 {:error, reason}
67 end
68 end
69
70 defp do_request(api_key, tier, string, from_language, to_language) do
71 HTTP.post(
72 base_url(tier) <> "translate",
73 URI.encode_query(
74 %{
75 text: string,
76 target_lang: to_language,
77 tag_handling: "html"
78 }
79 |> maybe_add_source(from_language),
80 :rfc3986
81 ),
82 [
83 {"authorization", "DeepL-Auth-Key #{api_key}"},
84 {"content-type", "application/x-www-form-urlencoded"}
85 ]
86 )
87 end
88
89 defp maybe_add_source(opts, nil), do: opts
90 defp maybe_add_source(opts, lang), do: Map.put(opts, :source_lang, lang)
91
92 defp do_languages(type) do
93 HTTP.get(
94 base_url(tier()) <> "languages?type=#{type}",
95 [
96 {"authorization", "DeepL-Auth-Key #{api_key()}"}
97 ]
98 )
99 end
100 end