Add supported languages list to /api/v2/instance

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
marcin mikołajczak 2022-11-08 23:09:42 +01:00
parent f0eb8e0b0c
commit 28f8bb00d8
9 changed files with 155 additions and 25 deletions

View file

@ -6,9 +6,9 @@ defmodule Pleroma.Language.Translation do
@cachex Pleroma.Config.get([:cachex, :provider], Cachex)
def configured? do
service = get_service()
provider = get_provider()
!!service and service.configured?
!!provider and provider.configured?
end
def translate(text, source_language, target_language) do
@ -16,13 +16,13 @@ defmodule Pleroma.Language.Translation do
case @cachex.get(:translations_cache, cache_key) do
{:ok, nil} ->
service = get_service()
provider = get_provider()
result =
if !service or !service.configured? do
if !configured?() do
{:error, :not_found}
else
service.translate(text, source_language, target_language)
provider.translate(text, source_language, target_language)
end
store_result(result, cache_key)
@ -37,7 +37,33 @@ defmodule Pleroma.Language.Translation do
end
end
defp get_service, do: Pleroma.Config.get([__MODULE__, :provider])
def supported_languages(type) when type in [:source, :target] do
provider = get_provider()
cache_key = "#{type}_languages/#{provider.name()}"
case @cachex.get(:translations_cache, cache_key) do
{:ok, nil} ->
result =
if !configured?() do
{:error, :not_found}
else
provider.supported_languages(type)
end
store_result(result, cache_key)
result
{:ok, result} ->
{:ok, result}
{:error, error} ->
{:error, error}
end
end
defp get_provider, do: Pleroma.Config.get([__MODULE__, :provider])
defp get_cache_key(text, source_language, target_language) do
"#{source_language}/#{target_language}/#{content_hash(text)}"

View file

@ -9,14 +9,17 @@ defmodule Pleroma.Language.Translation.Deepl do
@behaviour Provider
@name "DeepL"
@impl Provider
def configured? do
is_atom(get_base_url()) and not_empty_string(get_api_key())
end
def configured?, do: not_empty_string(base_url()) and not_empty_string(api_key())
@impl Provider
def translate(content, source_language, target_language) do
endpoint = get_base_url()
endpoint =
base_url()
|> URI.merge("/v2/translate")
|> URI.to_string()
case Pleroma.HTTP.post(
endpoint <>
@ -30,7 +33,7 @@ defmodule Pleroma.Language.Translation.Deepl do
"",
[
{"Content-Type", "application/x-www-form-urlencoded"},
{"Authorization", "DeepL-Auth-Key #{get_api_key()}"}
{"Authorization", "DeepL-Auth-Key #{api_key()}"}
]
) do
{:ok, %{status: 429}} ->
@ -50,7 +53,7 @@ defmodule Pleroma.Language.Translation.Deepl do
%{
content: content,
detected_source_language: detected_source_language,
provider: "DeepL"
provider: @name
}}
_ ->
@ -58,11 +61,41 @@ defmodule Pleroma.Language.Translation.Deepl do
end
end
defp get_base_url do
@impl Provider
def supported_languages(type) when type in [:source, :target] do
endpoint =
base_url()
|> URI.merge("/v2/languages")
|> URI.to_string()
case Pleroma.HTTP.post(
endpoint <> "?" <> URI.encode_query(%{type: type}),
"",
[
{"Content-Type", "application/x-www-form-urlencoded"},
{"Authorization", "DeepL-Auth-Key #{api_key()}"}
]
) do
{:ok, %{status: 200} = res} ->
languages =
Jason.decode!(res.body)
|> Enum.map(fn %{"language" => language} -> language |> String.downcase() end)
{:ok, languages}
_ ->
{:error, :internal_server_error}
end
end
@impl Provider
def name, do: @name
defp base_url do
Pleroma.Config.get([__MODULE__, :base_url])
end
defp get_api_key do
defp api_key do
Pleroma.Config.get([__MODULE__, :api_key])
end
end

View file

@ -9,21 +9,21 @@ defmodule Pleroma.Language.Translation.Libretranslate do
@behaviour Provider
@name "LibreTranslate"
@impl Provider
def configured?, do: not_empty_string(get_base_url())
def configured?, do: not_empty_string(base_url()) and not_empty_string(api_key())
@impl Provider
def translate(content, source_language, target_language) do
endpoint = endpoint_url()
case Pleroma.HTTP.post(
endpoint,
base_url() <> "/translate",
Jason.encode!(%{
q: content,
source: source_language |> String.upcase(),
target: target_language,
format: "html",
api_key: get_api_key()
api_key: api_key()
}),
[
{"Content-Type", "application/json"}
@ -52,15 +52,29 @@ defmodule Pleroma.Language.Translation.Libretranslate do
end
end
defp endpoint_url do
get_base_url() <> "/translate"
@impl Provider
def supported_languages(_) do
case Pleroma.HTTP.get(base_url() <> "/languages") do
{:ok, %{status: 200} = res} ->
languages =
Jason.decode!(res.body)
|> Enum.map(fn %{"code" => code} -> code end)
{:ok, languages}
_ ->
{:error, :internal_server_error}
end
end
defp get_base_url do
@impl Provider
def name, do: @name
defp base_url do
Pleroma.Config.get([__MODULE__, :base_url])
end
defp get_api_key do
defp api_key do
Pleroma.Config.get([__MODULE__, :api_key], "")
end
end

View file

@ -17,4 +17,9 @@ defmodule Pleroma.Language.Translation.Provider do
provider: String.t()
}}
| {:error, atom()}
@callback supported_languages(type :: :string | :target) ::
{:ok, [String.t()]} | {:error, atom()}
@callback name() :: String.t()
end

View file

@ -206,10 +206,32 @@ defmodule Pleroma.Web.MastodonAPI.InstanceView do
vapid: %{
public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key)
},
translation: %{enabled: Pleroma.Language.Translation.configured?()}
translation: translation_config()
})
end
defp translation_config do
enabled = Pleroma.Language.Translation.configured?()
source_languages =
case Pleroma.Language.Translation.supported_languages(:source) do
{:ok, languages} -> languages
_ -> nil
end
target_languages =
case Pleroma.Language.Translation.supported_languages(:target) do
{:ok, languages} -> languages
_ -> nil
end
%{
enabled: enabled,
source_languages: source_languages,
target_languages: target_languages
}
end
defp pleroma_configuration(instance) do
%{
metadata: %{

View file

@ -0,0 +1 @@
[{"language":"BG","name":"Bulgarian","supports_formality":false},{"language":"CS","name":"Czech","supports_formality":false},{"language":"DA","name":"Danish","supports_formality":false},{"language":"DE","name":"German","supports_formality":true},{"language":"EL","name":"Greek","supports_formality":false},{"language":"EN-GB","name":"English (British)","supports_formality":false},{"language":"EN-US","name":"English (American)","supports_formality":false},{"language":"ES","name":"Spanish","supports_formality":true},{"language":"ET","name":"Estonian","supports_formality":false},{"language":"FI","name":"Finnish","supports_formality":false},{"language":"FR","name":"French","supports_formality":true},{"language":"HU","name":"Hungarian","supports_formality":false},{"language":"ID","name":"Indonesian","supports_formality":false},{"language":"IT","name":"Italian","supports_formality":true},{"language":"JA","name":"Japanese","supports_formality":false},{"language":"LT","name":"Lithuanian","supports_formality":false},{"language":"LV","name":"Latvian","supports_formality":false},{"language":"NL","name":"Dutch","supports_formality":true},{"language":"PL","name":"Polish","supports_formality":true},{"language":"PT-BR","name":"Portuguese (Brazilian)","supports_formality":true},{"language":"PT-PT","name":"Portuguese (European)","supports_formality":true},{"language":"RO","name":"Romanian","supports_formality":false},{"language":"RU","name":"Russian","supports_formality":true},{"language":"SK","name":"Slovak","supports_formality":false},{"language":"SL","name":"Slovenian","supports_formality":false},{"language":"SV","name":"Swedish","supports_formality":false},{"language":"TR","name":"Turkish","supports_formality":false},{"language":"UK","name":"Ukrainian","supports_formality":false},{"language":"ZH","name":"Chinese (simplified)","supports_formality":false}]

View file

@ -24,4 +24,14 @@ defmodule Pleroma.Language.Translation.DeeplTest do
provider: "DeepL"
} = res
end
test "it returns languages list" do
Tesla.Mock.mock_global(fn env -> apply(HttpRequestMock, :request, [env]) end)
clear_config([Pleroma.Language.Translation.Deepl, :base_url], "https://api-free.deepl.com")
clear_config([Pleroma.Language.Translation.Deepl, :api_key], "API_KEY")
assert {:ok, [language | _languages]} = Deepl.supported_languages(:target)
assert is_binary(language)
end
end

View file

@ -1578,6 +1578,15 @@ defmodule HttpRequestMock do
}}
end
def post("https://api-free.deepl.com/v2/languages" <> _, _, _, _) do
{:ok,
%Tesla.Env{
status: 200,
body: File.read!("test/fixtures/tesla_mock/deepl-languages-list.json"),
headers: [{"content-type", "application/json"}]
}}
end
def post(url, query, body, headers) do
{:error,
"Mock response not implemented for POST #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}

View file

@ -7,6 +7,8 @@ defmodule TranslationMock do
@behaviour Provider
@name "TranslationMock"
@impl Provider
def configured?, do: true
@ -16,7 +18,15 @@ defmodule TranslationMock do
%{
content: content |> String.reverse(),
detected_source_language: source_language,
provider: "TranslationMock"
provider: @name
}}
end
@impl Provider
def supported_languages(_) do
["en", "pl"]
end
@impl Provider
def name, do: @name
end