Skip to content

Commit 528e9cb

Browse files
authored
Warn user if conflicting plural messages are defined (#400) (#401)
1 parent b41445e commit 528e9cb

2 files changed

Lines changed: 77 additions & 4 deletions

File tree

lib/gettext/extractor_agent.ex

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ defmodule Gettext.ExtractorAgent do
33

44
use Agent
55

6+
require Logger
7+
68
alias Expo.Message
79

810
@name __MODULE__
@@ -75,12 +77,45 @@ defmodule Gettext.ExtractorAgent do
7577
end)
7678
end
7779

78-
defp merge_messages(message_1, message_2) do
80+
defp merge_messages(%Message.Singular{} = message_1, %Message.Plural{} = message_2) do
81+
# Flipping the arguments to make sure that the pluaral message (more information) is used as the base message
82+
merge_messages(message_2, message_1)
83+
end
84+
85+
defp merge_messages(%Message.Plural{} = message_1, %Message.Plural{} = message_2) do
86+
# Make sure message choice is deterministic
87+
[message_1, message_2] =
88+
Enum.sort_by([message_1, message_2], &IO.iodata_to_binary(&1.msgid_plural))
89+
90+
if IO.iodata_to_binary(message_1.msgid_plural) != IO.iodata_to_binary(message_2.msgid_plural) do
91+
Logger.warning("""
92+
Plural message for '#{IO.iodata_to_binary(message_1.msgid)}' is not matching:
93+
Using '#{IO.iodata_to_binary(message_2.msgid_plural)}' instead of '#{IO.iodata_to_binary(message_1.msgid_plural)}'.
94+
References: #{dump_references(message_1.references ++ message_2.references)}\
95+
""")
96+
end
97+
98+
merge_messages_after_checks(message_1, message_2)
99+
end
100+
101+
defp merge_messages(message_1, message_2), do: merge_messages_after_checks(message_1, message_2)
102+
103+
defp merge_messages_after_checks(message_1, message_2) do
79104
message_1
80105
|> Map.put(:references, message_1.references ++ message_2.references)
81106
|> Map.put(
82107
:extracted_comments,
83108
Enum.uniq(message_1.extracted_comments ++ message_2.extracted_comments)
84109
)
85110
end
111+
112+
defp dump_references(references) do
113+
references
114+
|> List.flatten()
115+
|> Enum.map(fn
116+
{file, line} -> [file, ":", Integer.to_string(line)]
117+
file -> file
118+
end)
119+
|> Enum.intersperse(", ")
120+
end
86121
end

test/gettext/extractor_test.exs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule Gettext.ExtractorTest do
22
use ExUnit.Case
33

4+
import ExUnit.CaptureLog
5+
46
alias Expo.Message
57
alias Expo.Messages
68
alias Gettext.Extractor
@@ -322,6 +324,8 @@ defmodule Gettext.ExtractorTest do
322324
Gettext.Macros.gettext_comment("repeated comment")
323325
Gettext.Macros.gettext_with_backend(Gettext.ExtractorTest.MyGettext, "foo")
324326
Gettext.Macros.dngettext_with_backend(Gettext.ExtractorTest.MyGettext, "errors", "one error", "%{count} errors", 2)
327+
Gettext.Macros.dngettext_with_backend(Gettext.ExtractorTest.MyGettext, "errors", "one error", "%{count} errors", 2)
328+
Gettext.Macros.dgettext_with_backend(Gettext.ExtractorTest.MyGettext, "errors", "one error")
325329
Gettext.Macros.gettext_comment("one more comment")
326330
Gettext.Macros.gettext_comment("repeated comment")
327331
Gettext.Macros.gettext_comment("repeated comment")
@@ -345,12 +349,12 @@ defmodule Gettext.ExtractorTest do
345349
#. repeated comment
346350
#. one more comment
347351
#: foo.ex:16
348-
#: foo.ex:21
352+
#: foo.ex:23
349353
#, elixir-autogen, elixir-format
350354
msgid "foo"
351355
msgstr ""
352356
353-
#: foo.ex:23
357+
#: foo.ex:25
354358
#, elixir-autogen, elixir-format
355359
msgctxt "test"
356360
msgid "context based message"
@@ -362,6 +366,8 @@ defmodule Gettext.ExtractorTest do
362366
msgstr ""
363367
364368
#: foo.ex:17
369+
#: foo.ex:18
370+
#: foo.ex:19
365371
#, elixir-autogen, elixir-format
366372
msgid "one error"
367373
msgid_plural "%{count} errors"
@@ -373,7 +379,7 @@ defmodule Gettext.ExtractorTest do
373379
msgid ""
374380
msgstr ""
375381
376-
#: foo.ex:22
382+
#: foo.ex:24
377383
#, elixir-autogen, elixir-format
378384
msgid "hi"
379385
msgstr ""
@@ -435,6 +441,38 @@ defmodule Gettext.ExtractorTest do
435441
Extractor.disable()
436442
end
437443

444+
test "warns on conflicting plural messages" do
445+
refute Extractor.extracting?()
446+
Extractor.enable()
447+
assert Extractor.extracting?()
448+
449+
code = """
450+
defmodule Gettext.ExtractorTest.ConflictingPlural.Gettext do
451+
use Gettext.Backend, otp_app: :test_conflicting_plural
452+
end
453+
454+
defmodule Gettext.ExtractorTest.ConflictingPlural.Foo do
455+
require Gettext.Macros
456+
457+
def bar do
458+
Gettext.Macros.dngettext_with_backend(Gettext.ExtractorTest.ConflictingPlural.Gettext, "errors", "one error", "%{count} errors", 2)
459+
Gettext.Macros.dngettext_with_backend(Gettext.ExtractorTest.ConflictingPlural.Gettext, "errors", "one error", "multiple errors", 2)
460+
end
461+
end
462+
"""
463+
464+
assert capture_log(fn ->
465+
Code.compile_string(code, Path.join(File.cwd!(), "foo.ex"))
466+
end) =~
467+
"""
468+
Plural message for 'one error' is not matching:
469+
Using 'multiple errors' instead of '%{count} errors'.
470+
References: foo.ex:9, foo.ex:10
471+
"""
472+
after
473+
Extractor.disable()
474+
end
475+
438476
defp write_file(path, contents) do
439477
path |> Path.dirname() |> File.mkdir_p!()
440478
File.write!(path, contents)

0 commit comments

Comments
 (0)