Skip to content

Commit 0bea16e

Browse files
authored
Unique Singular/Plural Messages (#366) (#379)
1 parent 002dee1 commit 0bea16e

7 files changed

Lines changed: 73 additions & 72 deletions

File tree

lib/gettext/compiler.ex

Lines changed: 46 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -622,7 +622,7 @@ defmodule Gettext.Compiler do
622622
kind,
623623
locale,
624624
%Message.Plural{} = message,
625-
_singular_fun,
625+
singular_fun,
626626
plural_fun,
627627
file,
628628
{plural_forms_fun, nplurals},
@@ -665,22 +665,54 @@ defmodule Gettext.Compiler do
665665
line: unquote(Message.source_line_number(message, :msgid))
666666
end
667667

668-
quote generated: true do
669-
Kernel.unquote(kind)(
670-
unquote(plural_fun)(
671-
unquote(msgctxt),
672-
unquote(msgid),
673-
unquote(msgid_plural),
674-
n,
675-
bindings
676-
)
677-
) do
678-
plural_form = unquote(plural_forms_fun)(n)
668+
singular_fun_impl =
669+
msgstr
670+
|> Enum.find(&match?({0, _msgstr}, &1))
671+
|> case do
672+
{0, ""} ->
673+
nil
674+
675+
{0, msgstr} ->
676+
quote do
677+
Kernel.unquote(kind)(
678+
unquote(singular_fun)(unquote(msgctxt), unquote(msgid), bindings)
679+
) do
680+
require unquote(interpolation_module)
681+
682+
unquote(interpolation_module).compile_interpolate(
683+
:translation,
684+
unquote(msgstr),
685+
bindings
686+
)
687+
end
688+
end
689+
690+
nil ->
691+
nil
692+
end
693+
694+
plural_fun_impl =
695+
quote generated: true do
696+
Kernel.unquote(kind)(
697+
unquote(plural_fun)(
698+
unquote(msgctxt),
699+
unquote(msgid),
700+
unquote(msgid_plural),
701+
n,
702+
bindings
703+
)
704+
) do
705+
plural_form = unquote(plural_forms_fun)(n)
679706

680-
var!(bindings) = Map.put(bindings, :count, n)
707+
var!(bindings) = Map.put(bindings, :count, n)
681708

682-
case plural_form, do: unquote(clauses ++ error_clause)
709+
case plural_form, do: unquote(clauses ++ error_clause)
710+
end
683711
end
712+
713+
quote do
714+
unquote(singular_fun_impl)
715+
unquote(plural_fun_impl)
684716
end
685717
end
686718
end

lib/gettext/extractor.ex

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -337,10 +337,7 @@ defmodule Gettext.Extractor do
337337
}
338338
end
339339

340-
defp merge_message(
341-
%Message.Singular{} = old,
342-
%Message.Singular{comments: []} = new
343-
) do
340+
defp merge_message(old, new) do
344341
ensure_empty_msgstr!(old)
345342
ensure_empty_msgstr!(new)
346343

@@ -353,36 +350,15 @@ defmodule Gettext.Extractor do
353350
old.flags
354351
end
355352

356-
%Message.Singular{
357-
msgid: old.msgid,
358-
msgstr: old.msgstr,
359-
msgctxt: new.msgctxt,
353+
old
354+
|> Message.merge(new)
355+
|> Map.merge(%{
360356
flags: flags,
361-
# The new in-memory message has no comments since it was extracted
362-
# from the source code.
363-
comments: old.comments,
364357
# We don't care about the references of the old message since the new
365358
# in-memory message has all the actual and current references.
366359
references: new.references,
367360
extracted_comments: new.extracted_comments
368-
}
369-
end
370-
371-
defp merge_message(%Message.Plural{} = old, %Message.Plural{comments: []} = new) do
372-
ensure_empty_msgstr!(old)
373-
ensure_empty_msgstr!(new)
374-
375-
# The logic here is the same as for %Message.Singular{}s.
376-
%Message.Plural{
377-
msgid: old.msgid,
378-
msgctxt: new.msgctxt,
379-
msgid_plural: old.msgid_plural,
380-
msgstr: old.msgstr,
381-
flags: old.flags,
382-
comments: old.comments,
383-
references: new.references,
384-
extracted_comments: new.extracted_comments
385-
}
361+
})
386362
end
387363

388364
defp ensure_empty_msgstr!(%Message.Singular{msgstr: msgstr} = message) do
@@ -392,8 +368,8 @@ defmodule Gettext.Extractor do
392368
end
393369
end
394370

395-
defp ensure_empty_msgstr!(%Message.Plural{msgstr: %{0 => str0, 1 => str1}} = message) do
396-
if not blank?(str0) or not blank?(str1) do
371+
defp ensure_empty_msgstr!(%Message.Plural{msgstr: msgstr} = message) do
372+
if Enum.any?(Map.values(msgstr), &(not blank?(&1))) do
397373
raise Error,
398374
"plural message with msgid '#{IO.iodata_to_binary(message.msgid)}' has a non-empty msgstr"
399375
end

lib/gettext/merger.ex

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -205,33 +205,15 @@ defmodule Gettext.Merger do
205205
# flags: we should take the new flags and preserve the fuzzy flag
206206
# references: new contains the updated and most recent references
207207

208-
defp merge_two_messages(
209-
%Message.Singular{} = old,
210-
%Message.Singular{} = new,
211-
custom_flags_to_keep
212-
) do
213-
%Message.Singular{
214-
msgctxt: new.msgctxt,
215-
msgid: new.msgid,
216-
msgstr: old.msgstr,
208+
defp merge_two_messages(old, new, custom_flags_to_keep) do
209+
old
210+
|> Message.merge(new)
211+
|> Map.merge(%{
217212
comments: old.comments,
218213
extracted_comments: new.extracted_comments,
219214
flags: merge_flags(old, new, custom_flags_to_keep),
220215
references: new.references
221-
}
222-
end
223-
224-
defp merge_two_messages(%Message.Plural{} = old, %Message.Plural{} = new, custom_flags_to_keep) do
225-
%Message.Plural{
226-
msgctxt: new.msgctxt,
227-
msgid: new.msgid,
228-
msgid_plural: new.msgid_plural,
229-
msgstr: old.msgstr,
230-
comments: old.comments,
231-
extracted_comments: new.extracted_comments,
232-
flags: merge_flags(old, new, custom_flags_to_keep),
233-
references: new.references
234-
}
216+
})
235217
end
236218

237219
defp merge_flags(old_message, new_message, custom_flags_to_keep) do

mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ defmodule Gettext.Mixfile do
4949

5050
defp deps do
5151
[
52-
{:expo, "~> 0.4.0"},
52+
{:expo, "~> 0.5.1"},
5353

5454
# Dev and test dependencies
5555
{:ex_doc, "~> 0.19", only: :dev},

mix.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"},
33
"ex_doc": {:hex, :ex_doc, "0.29.1", "b1c652fa5f92ee9cf15c75271168027f92039b3877094290a75abcaac82a9f77", [:mix], [{:earmark_parser, "~> 1.4.19", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "b7745fa6374a36daf484e2a2012274950e084815b936b1319aeebcf7809574f6"},
44
"excoveralls": {:hex, :excoveralls, "0.17.0", "279f124dba347903bb654bc40745c493ae265d45040001b4899ea1edf88078c7", [:mix], [{:castore, "~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "08b638d114387a888f9cb8d65f2a0021ec04c3e447b793efa7c1e734aba93004"},
5-
"expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"},
5+
"expo": {:hex, :expo, "0.5.0", "12035d6528e4fd6a9df5f71160ec114cce7f520f4c827fffe1f6760f1d8b4900", [:mix], [], "hexpm", "5a0231c3cf2fb221c313786cdc62aab91b99042c950d47bdb2e51b77d88df722"},
66
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
77
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
88
"makeup_elixir": {:hex, :makeup_elixir, "0.16.0", "f8c570a0d33f8039513fbccaf7108c5d750f47d8defd44088371191b76492b0b", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "28b2cbdc13960a46ae9a8858c4bebdec3c9a6d7b4b9e7f4ed1502f8159f338e7"},

test/gettext/extractor_test.exs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,8 +137,9 @@ defmodule Gettext.ExtractorTest do
137137

138138
ts2 = [
139139
%Message.Singular{msgid: ["non-matching non-autogenerated"]},
140-
%Message.Singular{
140+
%Message.Plural{
141141
msgid: ["matching autogenerated"],
142+
msgid_plural: ["matching non-autogenerated 2"],
142143
references: [{"foo.ex", 3}],
143144
extracted_comments: ["#. Bar"],
144145
flags: [["elixir-autogen"]]
@@ -152,8 +153,9 @@ defmodule Gettext.ExtractorTest do
152153
) ==
153154
%Messages{
154155
messages: [
155-
%Message.Singular{
156+
%Message.Plural{
156157
msgid: ["matching autogenerated"],
158+
msgid_plural: ["matching non-autogenerated 2"],
157159
references: [{"foo.ex", 3}],
158160
flags: [["elixir-autogen"]],
159161
extracted_comments: ["#. Bar"]

test/gettext_test.exs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,15 @@ defmodule GettextTest do
262262
)
263263
end
264264

265+
test "plural messages can be used for singular message" do
266+
import Translator, only: [lgettext: 5]
267+
268+
message =
269+
lgettext("it", "errors", nil, "There was an error", %{})
270+
271+
assert message == {:ok, "C'è stato un errore"}
272+
end
273+
265274
test "by default, non-found pluralized message behave like regular message" do
266275
assert Translator.lngettext("it", "not a domain", nil, "foo", "foos", 1, %{}) ==
267276
{:default, "foo"}

0 commit comments

Comments
 (0)