Skip to content

Commit

Permalink
Unique Singular/Plural Messages (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
maennchen committed Nov 29, 2023
1 parent 002dee1 commit 6f62f07
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 72 deletions.
60 changes: 46 additions & 14 deletions lib/gettext/compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ defmodule Gettext.Compiler do
kind,
locale,
%Message.Plural{} = message,
_singular_fun,
singular_fun,
plural_fun,
file,
{plural_forms_fun, nplurals},
Expand Down Expand Up @@ -665,22 +665,54 @@ defmodule Gettext.Compiler do
line: unquote(Message.source_line_number(message, :msgid))
end

quote generated: true do
Kernel.unquote(kind)(
unquote(plural_fun)(
unquote(msgctxt),
unquote(msgid),
unquote(msgid_plural),
n,
bindings
)
) do
plural_form = unquote(plural_forms_fun)(n)
singular_fun_impl =
msgstr
|> Enum.find(&match?({0, _msgstr}, &1))
|> case do
{0, ""} ->
nil

{0, msgstr} ->
quote do
Kernel.unquote(kind)(
unquote(singular_fun)(unquote(msgctxt), unquote(msgid), bindings)
) do
require unquote(interpolation_module)

unquote(interpolation_module).compile_interpolate(
:translation,
unquote(msgstr),
bindings
)
end
end

nil ->
nil
end

plural_fun_impl =
quote generated: true do
Kernel.unquote(kind)(
unquote(plural_fun)(
unquote(msgctxt),
unquote(msgid),
unquote(msgid_plural),
n,
bindings
)
) do
plural_form = unquote(plural_forms_fun)(n)

var!(bindings) = Map.put(bindings, :count, n)
var!(bindings) = Map.put(bindings, :count, n)

case plural_form, do: unquote(clauses ++ error_clause)
case plural_form, do: unquote(clauses ++ error_clause)
end
end

quote do
unquote(singular_fun_impl)
unquote(plural_fun_impl)
end
end
end
Expand Down
38 changes: 7 additions & 31 deletions lib/gettext/extractor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -337,10 +337,7 @@ defmodule Gettext.Extractor do
}
end

defp merge_message(
%Message.Singular{} = old,
%Message.Singular{comments: []} = new
) do
defp merge_message(old, new) do
ensure_empty_msgstr!(old)
ensure_empty_msgstr!(new)

Expand All @@ -353,36 +350,15 @@ defmodule Gettext.Extractor do
old.flags
end

%Message.Singular{
msgid: old.msgid,
msgstr: old.msgstr,
msgctxt: new.msgctxt,
old
|> Message.merge(new)
|> Map.merge(%{
flags: flags,
# The new in-memory message has no comments since it was extracted
# from the source code.
comments: old.comments,
# We don't care about the references of the old message since the new
# in-memory message has all the actual and current references.
references: new.references,
extracted_comments: new.extracted_comments
}
end

defp merge_message(%Message.Plural{} = old, %Message.Plural{comments: []} = new) do
ensure_empty_msgstr!(old)
ensure_empty_msgstr!(new)

# The logic here is the same as for %Message.Singular{}s.
%Message.Plural{
msgid: old.msgid,
msgctxt: new.msgctxt,
msgid_plural: old.msgid_plural,
msgstr: old.msgstr,
flags: old.flags,
comments: old.comments,
references: new.references,
extracted_comments: new.extracted_comments
}
})
end

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

defp ensure_empty_msgstr!(%Message.Plural{msgstr: %{0 => str0, 1 => str1}} = message) do
if not blank?(str0) or not blank?(str1) do
defp ensure_empty_msgstr!(%Message.Plural{msgstr: msgstr} = message) do
if Enum.any?(Map.values(msgstr), &(not blank?(&1))) do
raise Error,
"plural message with msgid '#{IO.iodata_to_binary(message.msgid)}' has a non-empty msgstr"
end
Expand Down
28 changes: 5 additions & 23 deletions lib/gettext/merger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -205,33 +205,15 @@ defmodule Gettext.Merger do
# flags: we should take the new flags and preserve the fuzzy flag
# references: new contains the updated and most recent references

defp merge_two_messages(
%Message.Singular{} = old,
%Message.Singular{} = new,
custom_flags_to_keep
) do
%Message.Singular{
msgctxt: new.msgctxt,
msgid: new.msgid,
msgstr: old.msgstr,
defp merge_two_messages(old, new, custom_flags_to_keep) do
old
|> Message.merge(new)
|> Map.merge(%{
comments: old.comments,
extracted_comments: new.extracted_comments,
flags: merge_flags(old, new, custom_flags_to_keep),
references: new.references
}
end

defp merge_two_messages(%Message.Plural{} = old, %Message.Plural{} = new, custom_flags_to_keep) do
%Message.Plural{
msgctxt: new.msgctxt,
msgid: new.msgid,
msgid_plural: new.msgid_plural,
msgstr: old.msgstr,
comments: old.comments,
extracted_comments: new.extracted_comments,
flags: merge_flags(old, new, custom_flags_to_keep),
references: new.references
}
})
end

defp merge_flags(old_message, new_message, custom_flags_to_keep) do
Expand Down
2 changes: 1 addition & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ defmodule Gettext.Mixfile do

defp deps do
[
{:expo, "~> 0.4.0"},
{:expo, "~> 0.5.1"},

# Dev and test dependencies
{:ex_doc, "~> 0.19", only: :dev},
Expand Down
2 changes: 1 addition & 1 deletion mix.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"earmark_parser": {:hex, :earmark_parser, "1.4.29", "149d50dcb3a93d9f3d6f3ecf18c918fb5a2d3c001b5d3305c926cddfbd33355b", [:mix], [], "hexpm", "4902af1b3eb139016aed210888748db8070b8125c2342ce3dcae4f38dcc63503"},
"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"},
"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"},
"expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"},
"expo": {:hex, :expo, "0.5.0", "12035d6528e4fd6a9df5f71160ec114cce7f520f4c827fffe1f6760f1d8b4900", [:mix], [], "hexpm", "5a0231c3cf2fb221c313786cdc62aab91b99042c950d47bdb2e51b77d88df722"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"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"},
"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"},
Expand Down
6 changes: 4 additions & 2 deletions test/gettext/extractor_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,9 @@ defmodule Gettext.ExtractorTest do

ts2 = [
%Message.Singular{msgid: ["non-matching non-autogenerated"]},
%Message.Singular{
%Message.Plural{
msgid: ["matching autogenerated"],
msgid_plural: ["matching non-autogenerated 2"],
references: [{"foo.ex", 3}],
extracted_comments: ["#. Bar"],
flags: [["elixir-autogen"]]
Expand All @@ -152,8 +153,9 @@ defmodule Gettext.ExtractorTest do
) ==
%Messages{
messages: [
%Message.Singular{
%Message.Plural{
msgid: ["matching autogenerated"],
msgid_plural: ["matching non-autogenerated 2"],
references: [{"foo.ex", 3}],
flags: [["elixir-autogen"]],
extracted_comments: ["#. Bar"]
Expand Down
9 changes: 9 additions & 0 deletions test/gettext_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,15 @@ defmodule GettextTest do
)
end

test "plural messages can be used for singular message" do
import Translator, only: [lgettext: 5]

message =
lgettext("it", "errors", nil, "There was an error", %{})

assert message == {:ok, "C'è stato un errore"}
end

test "by default, non-found pluralized message behave like regular message" do
assert Translator.lngettext("it", "not a domain", nil, "foo", "foos", 1, %{}) ==
{:default, "foo"}
Expand Down

0 comments on commit 6f62f07

Please sign in to comment.