Repository: elixir-gettext/gettext (elixir)

Issue:
`gettext/1` and related macro do not support `~S` concatenated strings
Hello 👋 

I like to split my translations over multiple lines to avoid them being too long. I also like to use the `~S` sigil when there are `"` in the string to avoid escaping them. It appears both are not compatible currently 😄 

```elixir
gettext(
  "a multi-line" <>
    ~S(string with sigil)
)
```

This results in a compilation error: `** (ArgumentError) Gettext macros expect message keys (msgid and msgid_plural), domains, and comments to expand to strings at compile-time, but the given msgid doesn't.`

I would expect this to work, especially since `gettext(~S("quoted string"))` works fine 👌

Pull request description:
Fix concatenation of sigils
Add support for concatenation with sigils (e.g. `"Hello " <> ~s(world)`).

Fixes #411


Patch:
diff --git a/lib/gettext/macros.ex b/lib/gettext/macros.ex
index 0734395..f950ac6 100644
--- a/lib/gettext/macros.ex
+++ b/lib/gettext/macros.ex
@@ -709,15 +709,29 @@ defmodule Gettext.Macros do
       """
     end
 
-    # We support nil too in order to fall back to a nil context and always use the *p
-    # variants of the Gettext macros.
+    validated_expand_to_binary(term, env, raiser)
+  end
+
+  defp validated_expand_to_binary({:<>, _, pieces}, env, raiser) do
+    Enum.map_join(pieces, &validated_expand_to_binary(&1, env, raiser))
+  end
+
+  defp validated_expand_to_binary({:<<>>, _, pieces}, env, raiser) do
+    Enum.map_join(pieces, &validated_expand_to_binary(&1, env, raiser))
+  end
+
+  # We support nil too in order to fall back to a nil context and always use the *p
+  # variants of the Gettext macros.
+  defp validated_expand_to_binary(term, _env, _raiser)
+       when is_binary(term) or is_nil(term) do
+    term
+  end
+
+  defp validated_expand_to_binary(term, env, raiser) do
     case Macro.expand(term, env) do
       term when is_binary(term) or is_nil(term) ->
         term
 
-      {:<<>>, _, pieces} = term ->
-        if Enum.all?(pieces, &is_binary/1), do: Enum.join(pieces), else: raiser.(term)
-
       other ->
         raiser.(other)
     end


Test patch:
diff --git a/test/gettext/macros_test.exs b/test/gettext/macros_test.exs
index 8b9dcf8..3152e1b 100644
--- a/test/gettext/macros_test.exs
+++ b/test/gettext/macros_test.exs
@@ -15,12 +15,19 @@ defmodule Gettext.MacrosTest do
   @backend Gettext.MacrosTest.Translator
   @gettext_msgid "Hello world"
 
-  describe "gettext/2" do
+  describe "gettext/1" do
     test "supports binary-ish msgid at compile-time" do
       Gettext.put_locale(@backend, "it")
       assert gettext("Hello world") == "Ciao mondo"
       assert gettext(@gettext_msgid) == "Ciao mondo"
       assert gettext(~s(Hello world)) == "Ciao mondo"
+      assert gettext("Hello " <> "world") == "Ciao mondo"
+      assert gettext("Hello " <> "wor" <> "ld") == "Ciao mondo"
+      assert gettext(<<"Hello world">>) == "Ciao mondo"
+      assert gettext(<<"Hello ", "world">>) == "Ciao mondo"
+      assert gettext("Hello " <> <<"wor", "ld">>) == "Ciao mondo"
+      assert gettext("Hello " <> ~s(world)) == "Ciao mondo"
+      assert gettext(~S(Hello ) <> ~s(world)) == "Ciao mondo"
     end
   end