You can create .pot files manually. E.g. all the ecto errors are available for translation because phoenix generates a .pot file for it. Nothing in ecto itself knows about gettext.
In addition to @LostKobrakai’s insight, the messages from ex_money are most likely not directly translatable since the test message already embeds the invalid content. This was a poor design choice by me for error handling (true across all the ex_cldr-related libs) based upon my misunderstanding of exception handling back many years when I started all this.
I think you may need to pattern match on the exception module in the {:error, {module, message}} tuple and provide your own translatable messages using @LostKobrakai’s suggestion.
I will work out a way to make this more straight forward for the next release of ex_money but I’ve not thought of a good non-breaking strategy yet. Suggestions welcome.
@LostKobrakai That’s what I did: Created a .pot file.
But then I was running into the problem @kip was mentioning (regarding the message embedding the invalid content)
My solution for now is extending the translate_error message (provided by core_components.ex) and extracting the given reason with a regex:
def translate_error({msg, opts}) do
if Keyword.has_key?(opts, :exception) do
case opts[:exception] do
Money.UnknownCurrencyError ->
%{"currency" => currency} = Regex.named_captures(~r/.*(?<currency>\".*\").*/, msg)
Gettext.dgettext(
BackendWeb.Gettext,
"errors",
"The currency %{currency} is unknown or not supported",
currency: currency
)
Money.ParseError ->
%{"parsed" => parsed} = Regex.named_captures(~r/.*(?<parsed>\".*\").*/, msg)
Gettext.dgettext(
BackendWeb.Gettext,
"errors",
"Could not parse %{parsed}.",
parsed: parsed
)
_ ->
Gettext.dgettext(BackendWeb.Gettext, "errors", msg, opts)
end
else
if count = opts[:count] do
Gettext.dngettext(BackendWeb.Gettext, "errors", msg, msg, count, opts)
else
Gettext.dgettext(BackendWeb.Gettext, "errors", msg, opts)
end
end
end
@kip at least for changeset errors I’d consider a switch from inlined details to them being separte as a non breaking change. One needs to do the inlining of details for errors coming with ecto anyways. But if those are based on exceptions those exceptions structs would need to care enough detail to split those things up.