-
Notifications
You must be signed in to change notification settings - Fork 84
/
gettext.extract.ex
138 lines (110 loc) · 4.24 KB
/
gettext.extract.ex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
defmodule Mix.Tasks.Gettext.Extract do
use Mix.Task
@recursive true
@shortdoc "Extracts messages from source code"
@moduledoc """
Extracts messages by recompiling the Elixir source code.
```bash
mix gettext.extract [OPTIONS]
```
messages 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 message domain.
All automatically-extracted messages are assigned the `elixir-autogen` flag.
If a message from the POT is no longer present and has the `elixir-autogen`
flag, the message is removed.
Before `v0.19.0`, the `elixir-format` flag was used to detect automatically
extracted messages. This has been deprecated in `v0.19.0`. When extracting
with the newest version, the new `elixir-autogen` flag is added to all
automatically extracted messages.
All messages are assigned a format flag. When using the default
interpolation module, that flag is `elixir-format`. With other interpolation
modules, the flag name is defined by that implementation (see
`c:Gettext.Interpolation.message_format/0`).
If you would like to verify that your POT files are up to date with the
current state of the codebase, you can provide the `--check-up-to-date`
flag. This is particularly useful for automated checks and in CI systems.
This validation will fail even when the same calls to Gettext
only change location in the codebase:
```bash
mix gettext.extract --check-up-to-date
```
It is possible to pass the `--merge` option to perform merging
for every Gettext backend updated during merge:
```bash
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:
```bash
mix gettext.extract --merge --no-fuzzy
```
"""
@switches [merge: :boolean, check_up_to_date: :boolean]
@impl true
def run(args) do
Application.ensure_all_started(:gettext)
_ = Mix.Project.get!()
mix_config = Mix.Project.config()
{opts, _} = OptionParser.parse!(args, switches: @switches)
pot_files = extract(mix_config[:app], mix_config[:gettext] || [])
if opts[:check_up_to_date] do
run_up_to_date_check(pot_files)
else
run_message_extraction(pot_files, opts, args)
end
end
defp run_message_extraction(pot_files, opts, args) do
for {path, contents} <- pot_files do
File.mkdir_p!(Path.dirname(path))
File.write!(path, contents)
Mix.shell().info("Extracted #{Path.relative_to_cwd(path)}")
end
if opts[:merge] do
run_merge(pot_files, args)
end
:ok
end
defp run_up_to_date_check(pot_files) do
not_extracted_paths = for {path, _contents} <- pot_files, do: path
if pot_files == [] do
:ok
else
Mix.raise("""
mix gettext.extract failed due to --check-up-to-date.
The following POT files were not extracted or are out of date:
#{Enum.map_join(not_extracted_paths, "\n", &" * #{&1 |> Path.relative_to_cwd()}")}
""")
end
end
defp extract(app, gettext_config) do
Gettext.Extractor.enable()
force_compile()
Gettext.Extractor.pot_files(app, gettext_config)
after
Gettext.Extractor.disable()
end
defp force_compile do
Enum.map(Mix.Tasks.Compile.Elixir.manifests(), &make_old_if_exists/1)
# 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", ["--force"])
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