Merge branch 'post-languages' into 'develop'
Add supported languages list to /api/v2/instance See merge request soapbox-pub/rebased!209
This commit is contained in:
commit
4c0b30e327
9 changed files with 151 additions and 23 deletions
|
@ -37,6 +37,32 @@ def translate(text, source_language, target_language) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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_provider, do: Pleroma.Config.get([__MODULE__, :provider])
|
||||||
|
|
||||||
defp get_cache_key(text, source_language, target_language) do
|
defp get_cache_key(text, source_language, target_language) do
|
||||||
|
|
|
@ -9,14 +9,17 @@ defmodule Pleroma.Language.Translation.Deepl do
|
||||||
|
|
||||||
@behaviour Provider
|
@behaviour Provider
|
||||||
|
|
||||||
|
@name "DeepL"
|
||||||
|
|
||||||
@impl Provider
|
@impl Provider
|
||||||
def configured? do
|
def configured?, do: not_empty_string(base_url()) and not_empty_string(api_key())
|
||||||
not_empty_string(get_base_url()) and not_empty_string(get_api_key())
|
|
||||||
end
|
|
||||||
|
|
||||||
@impl Provider
|
@impl Provider
|
||||||
def translate(content, source_language, target_language) do
|
def translate(content, source_language, target_language) do
|
||||||
endpoint = get_endpoint()
|
endpoint =
|
||||||
|
base_url()
|
||||||
|
|> URI.merge("/v2/translate")
|
||||||
|
|> URI.to_string()
|
||||||
|
|
||||||
case Pleroma.HTTP.post(
|
case Pleroma.HTTP.post(
|
||||||
endpoint <>
|
endpoint <>
|
||||||
|
@ -30,7 +33,7 @@ def translate(content, source_language, target_language) do
|
||||||
"",
|
"",
|
||||||
[
|
[
|
||||||
{"Content-Type", "application/x-www-form-urlencoded"},
|
{"Content-Type", "application/x-www-form-urlencoded"},
|
||||||
{"Authorization", "DeepL-Auth-Key #{get_api_key()}"}
|
{"Authorization", "DeepL-Auth-Key #{api_key()}"}
|
||||||
]
|
]
|
||||||
) do
|
) do
|
||||||
{:ok, %{status: 429}} ->
|
{:ok, %{status: 429}} ->
|
||||||
|
@ -50,7 +53,7 @@ def translate(content, source_language, target_language) do
|
||||||
%{
|
%{
|
||||||
content: content,
|
content: content,
|
||||||
detected_source_language: detected_source_language,
|
detected_source_language: detected_source_language,
|
||||||
provider: "DeepL"
|
provider: @name
|
||||||
}}
|
}}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -58,17 +61,41 @@ def translate(content, source_language, target_language) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_endpoint do
|
@impl Provider
|
||||||
get_base_url()
|
def supported_languages(type) when type in [:source, :target] do
|
||||||
|> URI.merge("/v2/translate")
|
endpoint =
|
||||||
|> URI.to_string()
|
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
|
end
|
||||||
|
|
||||||
defp get_base_url do
|
@impl Provider
|
||||||
|
def name, do: @name
|
||||||
|
|
||||||
|
defp base_url do
|
||||||
Pleroma.Config.get([__MODULE__, :base_url])
|
Pleroma.Config.get([__MODULE__, :base_url])
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_api_key do
|
defp api_key do
|
||||||
Pleroma.Config.get([__MODULE__, :api_key])
|
Pleroma.Config.get([__MODULE__, :api_key])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,21 +9,21 @@ defmodule Pleroma.Language.Translation.Libretranslate do
|
||||||
|
|
||||||
@behaviour Provider
|
@behaviour Provider
|
||||||
|
|
||||||
|
@name "LibreTranslate"
|
||||||
|
|
||||||
@impl Provider
|
@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
|
@impl Provider
|
||||||
def translate(content, source_language, target_language) do
|
def translate(content, source_language, target_language) do
|
||||||
endpoint = endpoint_url()
|
|
||||||
|
|
||||||
case Pleroma.HTTP.post(
|
case Pleroma.HTTP.post(
|
||||||
endpoint,
|
base_url() <> "/translate",
|
||||||
Jason.encode!(%{
|
Jason.encode!(%{
|
||||||
q: content,
|
q: content,
|
||||||
source: source_language |> String.upcase(),
|
source: source_language |> String.upcase(),
|
||||||
target: target_language,
|
target: target_language,
|
||||||
format: "html",
|
format: "html",
|
||||||
api_key: get_api_key()
|
api_key: api_key()
|
||||||
}),
|
}),
|
||||||
[
|
[
|
||||||
{"Content-Type", "application/json"}
|
{"Content-Type", "application/json"}
|
||||||
|
@ -52,15 +52,29 @@ def translate(content, source_language, target_language) do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
defp endpoint_url do
|
@impl Provider
|
||||||
get_base_url() <> "/translate"
|
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
|
end
|
||||||
|
|
||||||
defp get_base_url do
|
@impl Provider
|
||||||
|
def name, do: @name
|
||||||
|
|
||||||
|
defp base_url do
|
||||||
Pleroma.Config.get([__MODULE__, :base_url])
|
Pleroma.Config.get([__MODULE__, :base_url])
|
||||||
end
|
end
|
||||||
|
|
||||||
defp get_api_key do
|
defp api_key do
|
||||||
Pleroma.Config.get([__MODULE__, :api_key], "")
|
Pleroma.Config.get([__MODULE__, :api_key], "")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,4 +17,9 @@ defmodule Pleroma.Language.Translation.Provider do
|
||||||
provider: String.t()
|
provider: String.t()
|
||||||
}}
|
}}
|
||||||
| {:error, atom()}
|
| {:error, atom()}
|
||||||
|
|
||||||
|
@callback supported_languages(type :: :string | :target) ::
|
||||||
|
{:ok, [String.t()]} | {:error, atom()}
|
||||||
|
|
||||||
|
@callback name() :: String.t()
|
||||||
end
|
end
|
||||||
|
|
|
@ -253,7 +253,8 @@ defp pleroma_configuration(instance) do
|
||||||
privileged_staff: Config.get([:instance, :privileged_staff]),
|
privileged_staff: Config.get([:instance, :privileged_staff]),
|
||||||
birthday_required: Config.get([:instance, :birthday_required]),
|
birthday_required: Config.get([:instance, :birthday_required]),
|
||||||
birthday_min_age: Config.get([:instance, :birthday_min_age]),
|
birthday_min_age: Config.get([:instance, :birthday_min_age]),
|
||||||
migration_cooldown_period: Config.get([:instance, :migration_cooldown_period])
|
migration_cooldown_period: Config.get([:instance, :migration_cooldown_period]),
|
||||||
|
translation: supported_languages()
|
||||||
},
|
},
|
||||||
stats: %{mau: Pleroma.User.active_user_count()},
|
stats: %{mau: Pleroma.User.active_user_count()},
|
||||||
vapid_public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key),
|
vapid_public_key: Keyword.get(Pleroma.Web.Push.vapid_config(), :public_key),
|
||||||
|
@ -282,6 +283,31 @@ defp pleroma_configuration2(instance) do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
defp supported_languages do
|
||||||
|
enabled = Pleroma.Language.Translation.configured?()
|
||||||
|
|
||||||
|
source_languages =
|
||||||
|
with true <- enabled,
|
||||||
|
{:ok, languages} <- Pleroma.Language.Translation.supported_languages(:source) do
|
||||||
|
languages
|
||||||
|
else
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
|
||||||
|
target_languages =
|
||||||
|
with true <- enabled,
|
||||||
|
{:ok, languages} <- Pleroma.Language.Translation.supported_languages(:target) do
|
||||||
|
languages
|
||||||
|
else
|
||||||
|
_ -> nil
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
source_languages: source_languages,
|
||||||
|
target_languages: target_languages
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
defp contact_account(nil), do: nil
|
defp contact_account(nil), do: nil
|
||||||
|
|
||||||
defp contact_account("@" <> username) do
|
defp contact_account("@" <> username) do
|
||||||
|
|
1
test/fixtures/tesla_mock/deepl-languages-list.json
vendored
Normal file
1
test/fixtures/tesla_mock/deepl-languages-list.json
vendored
Normal 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}]
|
|
@ -24,4 +24,14 @@ test "it translates text" do
|
||||||
provider: "DeepL"
|
provider: "DeepL"
|
||||||
} = res
|
} = res
|
||||||
end
|
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
|
end
|
||||||
|
|
|
@ -1597,6 +1597,15 @@ def post("https://api-free.deepl.com/v2/translate" <> _, _, _, _) do
|
||||||
}}
|
}}
|
||||||
end
|
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
|
def post(url, query, body, headers) do
|
||||||
{:error,
|
{:error,
|
||||||
"Mock response not implemented for POST #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
|
"Mock response not implemented for POST #{inspect(url)}, #{query}, #{inspect(body)}, #{inspect(headers)}"}
|
||||||
|
|
|
@ -7,6 +7,8 @@ defmodule TranslationMock do
|
||||||
|
|
||||||
@behaviour Provider
|
@behaviour Provider
|
||||||
|
|
||||||
|
@name "TranslationMock"
|
||||||
|
|
||||||
@impl Provider
|
@impl Provider
|
||||||
def configured?, do: true
|
def configured?, do: true
|
||||||
|
|
||||||
|
@ -16,7 +18,15 @@ def translate(content, source_language, _target_language) do
|
||||||
%{
|
%{
|
||||||
content: content |> String.reverse(),
|
content: content |> String.reverse(),
|
||||||
detected_source_language: source_language,
|
detected_source_language: source_language,
|
||||||
provider: "TranslationMock"
|
provider: @name
|
||||||
}}
|
}}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@impl Provider
|
||||||
|
def supported_languages(_) do
|
||||||
|
["en", "pl"]
|
||||||
|
end
|
||||||
|
|
||||||
|
@impl Provider
|
||||||
|
def name, do: @name
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue