Search code examples
elixirgettext

Marking list of strings for translation with elixir gettext (at compile time)


I'm trying to mark this list of strings translatable so that it appears in .pot files.

import XXXWeb.Gettext

@crop_types ~w(grape strawberry potato tomato rice wheat corn peas hops carrot soy sunflower other) 
    |> Enum.map(&(XXXWeb.Gettext.dgettext_noop("crop_types", &1)))

According to the documentation, that should result in the strings being translatable in the usual .pot files when I run mix gettext.extract --merge.

I want to avoid the "usual" dgettext dynamic translations and explicitly mark the strings for translation at compile time so that nothing will be missing in the future when I add strings and forget the translations in one of the languages.

The error I'm getting is:

== Compilation error in file lib/XXX/fields/crop_types.ex ==
** (ArgumentError) Gettext macros expect translation keys (msgid and msgid_plural),
domains, and comments to expand to strings at compile-time, but the given msgid
doesn't. This is what the macro received:

{:x1, [line: 5], :elixir_fn}

I read that this is due to how the AST first tries to run gettext and then runs the enum function, which is exactly not what I want. But I'm not sure about that part, so please correct me.

How can I get this done?

EDIT: Just to be safe, here is my gettext module:

defmodule MyAppWeb.Gettext do
  use Gettext, otp_app: :myapp
end

Solution

  • I think this approach should work (edited answer):

    defmodule XXXWeb.Gettext do
      use Gettext, otp_app: :thing
    
      defmacro extract_gettext_strings(crops) do
        {crop_types, _} = Code.eval_quoted(crops)
    
        for crop <- crop_types do
          quote do
            XXXWeb.Gettext.dgettext_noop("crop_types", unquote(crop))
          end
        end
      end
    end
    
    defmodule G do
      require XXXWeb.Gettext
    
      XXXWeb.Gettext.extract_gettext_strings(~w(grape strawberry potato tomato rice wheat corn peas hops carrot soy sunflower other))
    
    end