elixir-gettext / gettext

Internationalization and localization support for Elixir.
https://hexdocs.pm/gettext
469 stars 86 forks source link

Running `mix gettext.extract` doesn't extract new messages with Elixir 1.15 #367

Closed linusdm closed 1 year ago

linusdm commented 1 year ago

I'm seeing an issue on new Phoenix projects that run on elixir 1.15. When the mix gettext.extract task is run, it doesn't pick up new messages anymore (nor does the same mix task with the --check-up-to-date option signal missing messages).

Removing the _build folder triggers the task to pick new messages up again, so it appears to be a cache/recompilation problem.

Reproducing is straightforward:

The last step should result in a new message being extracted to the po/t files, but that's not the case anymore. Running the same procedure with elixir 1.14 does extract a new message.

linusdm commented 1 year ago

Diving deeper into this I can see the project is not actually being force-compiled, as is expected, with the extract mix task. The recompilation is needed to make sure all the calls to gettext end up in the pot files.

There are some steps involved to trigger a forced compilation: https://github.com/elixir-gettext/gettext/blob/main/lib/mix/tasks/gettext.extract.ex#L114-L125

I'm not sure how these mix tasks all come together.

When I replace this line, in the aforementioned function:

Mix.Task.run("compile")

with this line

Mix.Task.run("compile", ["--force"])

the compilation seems to be triggered again, resulting in the extract task to work as expected. I'm sure this is quite naive, and has undesired consequences.

It seems to me that the "trick" with making the compiler manifest stale, doesn't work anymore. When Mix.Task.run("compile") is called the first time, it now does a "normal" compilation, which in most cases is doing nothing, as it's not being forced. The second call to Mix.Task.run("compile.elixir", ["--force"]) is a no-op, as it has been run now by the first overarching task.

Replacing this whole implementation with a single call like this (explicitly omitting everything related to the manifest files, and calling the "regular" compile mix task) also works:

defp force_compile do
  Mix.Task.rerun("compile.elixir", ["--force"])
end

But I'd be surprised if that would be correct in all cases, as I suspect there were reasons to set things up as they are now. For example: is it enough to force compilation only with the elixir compiler, or can other compilers also add to the messages being extracted? Rerunning the regular "compile" instead of the "compile.elixir" task with the --force option can also work. But then again, why were things as complicated as they were with the manifest files. And all this doesn't explain why resetting the date of the manifest files doesn't trigger a force compile anymore since elixir 1.15 (which is my hypothesis).

linusdm commented 1 year ago

I’m suspecting this has something to do with this change: Store timestamps in manifests · elixir-lang/elixir@ce67dd6 · GitHub Manipulating the last-modified date of the manifest file alone isn’t enough anymore, as there are now timestamps being stored in the manifest file itself.