Translate Ecto validation messages

Hello I have the following schema in my Phoenix App :

defmodule TattooBackend.Accounts.Account do
  @moduledoc """
  Contains schema and changesets for Account resource.
  """

  use Ecto.Schema

  import Ecto.Changeset

  alias TattooBackend.Accounts.Account

  schema "accounts" do
    field :email, :string
    field :crypted_password, :string
    field :password, :string, virtual: true
    timestamps()
  end

  def changeset(%Account{} = user, attributes \\ %{}) do
    user
    |> cast(attributes, [:email, :password])
    |> validate_required([:email, :password])
    |> validate_length(:password, min: 6)
    |> validate_format(:email, ~r/([\w-\.]+)@((?:[\w]+\.)+)([a-zA-Z]{2,4})/)
    |> unique_constraint(:email, name: "accounts_lower_email_index")
    |> put_password_hash
  end

  defp put_password_hash(changeset) do
    case changeset do
      %Ecto.Changeset{valid?: true, changes: %{password: pass}} ->
        put_change(changeset, :crypted_password, Comeonin.Bcrypt.hashpwsalt(pass))
      _ ->
        changeset
    end
  end
end

And I wrote simple test:

defmodule TattooBackend.Accounts.AccountTest do
  use TattooBackend.DataCase, async: true

  alias TattooBackend.Repo
  alias TattooBackend.Accounts.Account

  describe "with invalid attributes" do
    setup do
      changeset = Account.changeset(%Account{})

      {:ok, %{changeset: changeset}}
    end

    test "changeset is inalid", %{changeset: changeset} do
      refute changeset.valid?
    end

    test "changeset have errors", %{changeset: changeset} do
      assert changeset.errors == [
        email:      {"can't be blank", [validation: :required]},
        password:   {"can't be blank", [validation: :required]},
      ]
    end
  end
end

Now my question is how can I translate these Ecto validation messages?

If you used mix phoenix.new generator, it already created the required functions and infrastructure for you. If you open your generated error_helpers.ex you will find translate_error/1 function there that does what you want. You can use it directly in your views/templates (or import it in other places if you need to move to different layer). It takes the tuple with string and options, which is exactly what Ecto validations return.

Here is the template for reference:

Please note that if you do use the error_tag/2 function from the same module, it already translates the errors for you.

You should already have the translations template file in priv/gettext/errors.pot, and you can put in the translations you want to say priv/gettext/fr/LC_MESSAGES/errors.po

2 Likes

Expanding on @hubertlepicki’s answer, you’ll need to provide translations string for Ecto errors inside errors.pot

In this case, add the following lines into errors.pot

msgid "can't be blank"
msgstr "" 

It’ll work after performing normal translation process