defmodule Localizator.Translator do alias Localizator.Commons alias Localizator.Direction @typedoc """ Locale """ @type locale :: String.t() @type from :: locale @type from_may_be_nil :: from | nil @type to :: locale @type direction :: {from, to} | to | %{from: from, to: to} | %{to: to} @type direction_map :: %{to: to, from: from_may_be_nil} @typedoc """ Translation service """ @type translator :: Atom.t() @typedoc """ Translation services list """ @type translators :: [translator] @typedoc """ Translation resource """ @type resource :: String.t() | Map.t() | List.t() @type source :: resource @type result :: resource @typedoc """ Error Message """ @type message :: String.t() @spec list() :: translators def list(), do: Application.get_env(:localizator, :translators) @spec default() :: translator def default(), do: list() |> List.first() @spec translate(source, direction, translator) :: result def translate(source, direction, translator \\ default()) do map = Direction.get(direction) translate(source, map.to, map.from, translator) end @spec translate(String.t(), to, from_may_be_nil, translator) :: result def translate(string, to, from, translator) when is_binary(string) do case Commons.is_html?(string) do true -> translate_html(string, to, from, translator) false -> translate_plain(string, to, from, translator) end end @spec translate(Map.t(), to, from_may_be_nil, translator) :: result def translate(map, to, from, translator) when is_map(map) do Enum.map(map, fn {key, value} -> {key, translate(value, to, from, translator)} end) |> Map.new() end @spec translate(List.t(), to, from_may_be_nil, translator) :: result def translate(list, to, from, translator) when is_list(list) do Enum.map(list, fn element -> translate(element, to, from, translator) end) end defp translate_plain(string, to, from, translator) do translator.translate!(string, to, from) end defp translate_html(string, to, from, translator) do string |> Meeseeks.parse() |> Meeseeks.tree() |> translate_html_element(to, from, translator) |> Meeseeks.parse(:tuple_tree) |> Meeseeks.html() |> String.trim_leading("") |> String.trim_trailing("") end # Plain Text Content defp translate_html_element([element], to, from, translator) when is_binary(element) do [translator.translate!(element, to, from)] end # Part of the Plain Text Content defp translate_html_element(element, to, from, translator) when is_binary(element) do translator.translate!(element, to, from) end # List of html elements defp translate_html_element(elements, to, from, translator) when is_list(elements) do Enum.map(elements, &translate_html_element(&1, to, from, translator)) end # Html element defp translate_html_element({tag, attributes, content}, to, from, translator) do {tag, attributes, translate_html_element(content, to, from, translator)} end end