defmodule EctoGettext do @moduledoc """ EctoGettext - library for localization Ecto validation errors with using Gettext ### Example: import EctoGettext localize_validations(MyApp.Gettext, errors) """ @doc """ Get a list of errors and return a new list with translated errors """ @spec localize_validations(module, list) :: list def localize_validations(module, errors) do errors |> Enum.map(fn elem -> localize(module, elem) end) end @spec localize(module, tuple) :: {String.t, String.t} defp localize(module, error) do {attr, message} = error {set_attr(module, attr), set_message(module, message)} end @spec numbers() :: list defp numbers, do: ~w(0 1 2 3 4 5 6 7 8 9) @spec set_attr(module, atom) :: String.t defp set_attr(module, attr) do attr = attr |> Atom.to_string |> String.replace("_", " ") Gettext.dgettext(module, "attributes", attr) end @spec set_message(module, String.t) :: String.t defp set_message(module, message) do message = String.downcase(message) cond do String.starts_with?(message, "should be") && parse_number(message) -> Gettext.dgettext(module, "errors", format_message(message), count: parse_number(message)) true -> Gettext.dgettext(module, "errors", message) end end @spec format_message(String.t) :: String.t defp format_message(message) do message |> String.graphemes |> Enum.filter(fn elem -> !Enum.member?(numbers, elem) end) |> Enum.join |> String.split(" ", trim: true) |> List.insert_at(4, "%{count}") |> Enum.join(" ") end @spec parse_number(String.t) :: integer | nil defp parse_number(message) do message = message |> String.graphemes |> Enum.filter(fn elem -> Enum.member?(numbers, elem) end) |> Enum.join case message do "" -> nil _ -> String.to_integer(message) end end end