bonfire-app/lib/mix/tasks/localise/localise.extract.ex
Mayel de Borniol aa08dc4c64 misc
2022-10-17 23:01:44 +13:00

122 lines
3.4 KiB
Elixir
Executable file

defmodule Mix.Tasks.Bonfire.Localise.Extract do
use Mix.Task
import Untangle
@recursive true
@shortdoc "Extracts translations from source code"
@moduledoc """
Extracts translations by recompiling the Elixir source code.
mix gettext.extract [OPTIONS]
Translations are extracted into POT (Portable Object Template) files (with a
`.pot` extension). The location of these files is determined by the `:otp_app`
and `:priv` options given by Gettext modules when they call `use Gettext`. One
POT file is generated for each translation domain.
It is possible to give the `--merge` option to perform merging
for every Gettext backend updated during merge:
mix gettext.extract --merge
All other options passed to `gettext.extract` are forwarded to the
`gettext.merge` task (`Mix.Tasks.Gettext.Merge`), which is called internally
by this task. For example:
mix gettext.extract --merge --no-fuzzy
"""
@switches [merge: :boolean]
def run(args) do
Application.ensure_all_started(:gettext)
_ = Mix.Project.get!()
mix_config = Mix.Project.config()
{opts, _} = OptionParser.parse!(args, switches: @switches)
gettext_config =
(mix_config[:gettext] || [])
|> debug("gettext config")
exts_to_localise =
Bonfire.Mixer.deps_for(:localise)
|> debug("bonfire extensions to localise")
deps_to_localise =
Bonfire.Mixer.deps_for(:localise_self)
|> debug("other deps to localise")
touch_manifests()
# first extract strings from all deps that use the Gettext module in bonfire_common
pot_files = extract(:bonfire_common, gettext_config, exts_to_localise)
# then those that have their own Gettext
pot_files =
Enum.reduce(deps_to_localise, pot_files, fn dep, pot_files ->
pot_files ++ extract(String.to_atom(dep), gettext_config, dep)
end)
# pot_files |> debug("extracted pot_files")
for {path, contents} <- pot_files do
File.mkdir_p!(Path.dirname(path))
File.write!(path, contents)
info("Extracted strings to #{Path.relative_to_cwd(path)}")
end
if opts[:merge] do
run_merge(pot_files, args)
end
:ok
end
defp extract(app, gettext_config, deps_to_localise) do
Gettext.Extractor.enable()
force_compile(deps_to_localise)
Gettext.Extractor.pot_files(
app,
gettext_config
)
after
Gettext.Extractor.disable()
end
defp force_compile(deps_to_localise) do
# mark deps to be recompiled
Mix.Tasks.Bonfire.Dep.Compile.run(["--force"] ++ List.wrap(deps_to_localise))
# If "compile" was never called, the reenabling is a no-op and
# "compile.elixir" is a no-op as well (because it wasn't reenabled after
# running "compile"). If "compile" was already called, then running
# "compile" is a no-op and running "compile.elixir" will work because we
# manually reenabled it.
Mix.Task.reenable("compile.elixir")
Mix.Task.run("compile")
Mix.Task.run("compile.elixir")
end
defp touch_manifests() do
# |> debug("manifests")
Enum.map(Mix.Tasks.Compile.Elixir.manifests(), &make_old_if_exists/1)
end
defp make_old_if_exists(path) do
:file.change_time(path, {{2000, 1, 1}, {0, 0, 0}})
end
defp run_merge(pot_files, argv) do
pot_files
|> Enum.map(fn {path, _} -> Path.dirname(path) end)
|> Enum.uniq()
|> Task.async_stream(&Mix.Tasks.Gettext.Merge.run([&1 | argv]),
ordered: false
)
|> Stream.run()
end
end