Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send context when translating #7

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 37 additions & 15 deletions lib/adapter.ex
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
defmodule Kanta.DeepL.Adapter do
@moduledoc """
DeepL API adapter

We use XML tag handling to avoid translating the content of curly brackets.
These curly brackets are used by gettext for variable substitution.
They look like this:

```
price = Money.new(1000, "EUR")
gettext("Price: %{price}", price: price)
```
"""

use Tesla
Expand All @@ -13,29 +22,34 @@ defmodule Kanta.DeepL.Adapter do

plug(Tesla.Middleware.JSON)

def request_translation(source_lang, target_lang, text) do
post("/v2/translate", %{
source_lang: source_lang,
target_lang: target_lang,
text: [text]
})
|> case do
{:ok, %Tesla.Env{body: %{"translations" => translations}}} -> {:ok, translations}
{_, %Tesla.Env{body: body, status: status}} -> {:error, status, body}
error -> {:error, error}
end
def request_translation(source_lang, target_lang, text, context_name) do
request_translations(source_lang, target_lang, [text], context_name)
end

def request_translations(source_lang, target_lang, texts) do
def request_translations(source_lang, target_lang, texts, context_name) do
texts = Enum.map(texts, &replace_curly_brackets_with_xml_tags/1)

post("/v2/translate", %{
source_lang: source_lang,
target_lang: target_lang,
context: context_name,
tag_handling: "xml",
ignore_tags: ["gettext_variable"],
text: texts
})
|> case do
{:ok, %Tesla.Env{body: %{"translations" => translations}}} -> {:ok, translations}
{_, %Tesla.Env{body: body, status: status}} -> {:error, status, body}
error -> {:error, error}
{:ok, %Tesla.Env{body: %{"translations" => translations}}} ->
translations
|> Enum.map(fn translation ->
Map.update!(translation, "text", &replace_xml_tags_with_curly_brackets/1)
end)
|> then(&{:ok, &1})

{_, %Tesla.Env{body: body, status: status}} ->
{:error, status, body}

error ->
{:error, error}
end
end

Expand All @@ -54,4 +68,12 @@ defmodule Kanta.DeepL.Adapter do
{_, config} -> Keyword.get(config, :api_key)
end
end

defp replace_curly_brackets_with_xml_tags(text) do
Regex.replace(~r/%{(.*)}/, text, fn _, x -> "<gettext_variable>#{x}</gettext_variable>" end)
end

defp replace_xml_tags_with_curly_brackets(text) do
Regex.replace(~r/<gettext_variable>(.*)<\/gettext_variable>/, text, fn _, x -> "%{#{x}}" end)
end
end
9 changes: 2 additions & 7 deletions lib/form_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,8 @@ defmodule Kanta.DeepL.Plugin.FormComponent do
%{"translated_text" => translated},
%{assigns: %{message: %Message{message_type: :singular}}} = socket
) do
locale = socket.assigns.locale
translation = socket.assigns.translation

Translations.update_singular_translation(translation, %{"translated_text" => translated})

{:noreply, socket}
end

Expand All @@ -121,11 +118,8 @@ defmodule Kanta.DeepL.Plugin.FormComponent do
%{"translated_text" => translated},
%{assigns: %{message: %Message{message_type: :plural}}} = socket
) do
locale = socket.assigns.locale
translation = socket.assigns.translation

Translations.update_plural_translation(translation, %{"translated_text" => translated})

{:noreply, socket}
end

Expand All @@ -140,7 +134,8 @@ defmodule Kanta.DeepL.Plugin.FormComponent do
case Adapter.request_translation(
source_locale,
String.upcase(translate_locale.iso639_code),
source_text
source_text,
if(message.context, do: message.context.name)
) do
{:ok, translations} ->
%{"text" => translated_text} = List.first(translations)
Expand Down
21 changes: 13 additions & 8 deletions lib/translate_all_component.ex
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ defmodule Kanta.DeepL.Plugin.TranslateAllComponent do
singular_messages =
Translations.list_singular_translations(
filter: %{locale_id: socket.assigns.locale_id, translated_text: :is_null},
preloads: [:message],
preloads: [message: :context],
skip_pagination: true
)

plural_messages =
Translations.list_plural_translations(
filter: %{locale_id: socket.assigns.locale_id, translated_text: :is_null},
preloads: [:message],
preloads: [message: :context],
skip_pagination: true
)

Expand All @@ -50,18 +50,23 @@ defmodule Kanta.DeepL.Plugin.TranslateAllComponent do
{:noreply, socket}
end

defp translate_all(messages, locale_code, update_fn) do
messages
|> Enum.chunk_every(@deepl_limit)
|> Enum.map(&translate_batch(&1, locale_code, update_fn))
defp translate_all(translations, locale_code, update_fn) do
translations
|> Enum.group_by(&if &1.message.context, do: &1.message.context.name)
|> Enum.reduce([], fn {context_name, same_context_translations}, acc ->
same_context_translations
|> Enum.chunk_every(@deepl_limit)
|> Enum.map(&translate_batch(&1, locale_code, update_fn, context_name))
|> then(&Kernel.++(acc, &1))
end)
end

defp translate_batch(batch, locale_code, update_fn) do
defp translate_batch(batch, locale_code, update_fn, context_name) do
source_lang = nil
target_lang = String.upcase(locale_code)
texts = Enum.map(batch, & &1.message.msgid)

case Adapter.request_translations(source_lang, target_lang, texts) do
case Adapter.request_translations(source_lang, target_lang, texts, context_name) do
{:ok, translations} ->
batch
|> Enum.zip(translations)
Expand Down