From a26f0b97e69c15852d26846fbe7029872d57855c Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sun, 3 Apr 2022 17:29:24 +0100 Subject: [PATCH 01/12] feat: runtime translations --- lib/gettext/compiler.ex | 91 ++++++++++++++++++++++++++++++++++------- lib/gettext/repo.ex | 26 ++++++++++++ test/gettext_test.exs | 65 +++++++++++++++++++++++++++++ 3 files changed, 167 insertions(+), 15 deletions(-) create mode 100644 lib/gettext/repo.ex diff --git a/lib/gettext/compiler.ex b/lib/gettext/compiler.ex index 5830cba5..76f37bf9 100644 --- a/lib/gettext/compiler.ex +++ b/lib/gettext/compiler.ex @@ -36,6 +36,11 @@ defmodule Gettext.Compiler do default_domain = opts[:default_domain] || @default_domain interpolation = opts[:interpolation] || Gettext.Interpolation.Default + repo = opts[:repo] + + plural_mod = + Keyword.get(opts, :plural_forms) || + Application.get_env(:gettext, :plural_forms, Gettext.Plural) quote do @behaviour Gettext.Backend @@ -62,17 +67,15 @@ defmodule Gettext.Compiler do unquote(macros()) - # These are the two functions we generated inside the backend. - def lgettext(locale, domain, msgctxt \\ nil, msgid, bindings) - def lngettext(locale, domain, msgctxt \\ nil, msgid, msgid_plural, n, bindings) + unquote(public_functions(repo, interpolation, plural_mod)) - unquote(compile_po_files(env, known_po_files, opts)) + unquote(compile_po_files(env, known_po_files, plural_mod, opts)) # Catch-all clauses. - def lgettext(locale, domain, msgctxt, msgid, bindings), + defp lgettext_compiled(locale, domain, msgctxt, msgid, bindings), do: handle_missing_translation(locale, domain, msgctxt, msgid, bindings) - def lngettext(locale, domain, msgctxt, msgid, msgid_plural, n, bindings), + defp lngettext_compiled(locale, domain, msgctxt, msgid, msgid_plural, n, bindings), do: handle_missing_plural_translation( locale, @@ -311,6 +314,52 @@ defmodule Gettext.Compiler do end end + defp public_functions(nil, _interpolation, _plural_mod) do + quote do + def lgettext(locale, domain, msgctxt \\ nil, msgid, bindings) do + lgettext_compiled(locale, domain, msgctxt, msgid, bindings) + end + + def lngettext(locale, domain, msgctxt \\ nil, msgid, msgid_plural, n, bindings) do + lngettext_compiled(locale, domain, msgctxt, msgid, msgid_plural, n, bindings) + end + end + end + + defp public_functions(repo, interpolation, plural_mod) do + quote do + def lgettext(locale, domain, msgctxt, msgid, bindings) do + case unquote(repo).get_translation(locale, domain, msgctxt, msgid) do + {:ok, msgstr} -> + unquote(interpolation).runtime_interpolate(msgstr, bindings) + + _ -> + lgettext_compiled(locale, domain, msgctxt, msgid, bindings) + end + end + + def lngettext(locale, domain, msgctxt, msgid, msgid_plural, n, bindings) do + plural_form = unquote(plural_mod).plural(locale, n) + + case unquote(repo).get_plural_translation( + locale, + domain, + msgctxt, + msgid, + plural_form + ) do + {:ok, msgstr} -> + bindings = Map.put(bindings, :count, n) + unquote(interpolation).runtime_interpolate(msgstr, bindings) + + _ -> + unquote(interpolation).runtime_interpolate(msgid, bindings) + lngettext_compiled(locale, domain, msgctxt, msgid, msgid_plural, n, bindings) + end + end + end + end + @doc """ Expands the given `msgid` in the given `env`, raising if it doesn't expand to a binary. @@ -390,11 +439,7 @@ defmodule Gettext.Compiler do # Compiles all the `.po` files in the given directory (`dir`) into `lgettext/4` # and `lngettext/6` function clauses. - defp compile_po_files(env, known_po_files, opts) do - plural_mod = - Keyword.get(opts, :plural_forms) || - Application.get_env(:gettext, :plural_forms, Gettext.Plural) - + defp compile_po_files(env, known_po_files, plural_mod, opts) do opts = if opts[:one_module_per_locale] do IO.warn( @@ -451,11 +496,19 @@ defmodule Gettext.Compiler do quote do unquote(quoted) - def lgettext(unquote(locale), unquote(domain), msgctxt, msgid, bindings) do + defp lgettext_compiled(unquote(locale), unquote(domain), msgctxt, msgid, bindings) do unquote(singular_fun)(msgctxt, msgid, bindings) end - def lngettext(unquote(locale), unquote(domain), msgctxt, msgid, msgid_plural, n, bindings) do + defp lngettext_compiled( + unquote(locale), + unquote(domain), + msgctxt, + msgid, + msgid_plural, + n, + bindings + ) do unquote(plural_fun)(msgctxt, msgid, msgid_plural, n, bindings) end end @@ -479,11 +532,19 @@ defmodule Gettext.Compiler do current_module_quoted = quote do - def lgettext(unquote(locale), unquote(domain), msgctxt, msgid, bindings) do + defp lgettext_compiled(unquote(locale), unquote(domain), msgctxt, msgid, bindings) do unquote(module).unquote(singular_fun)(msgctxt, msgid, bindings) end - def lngettext(unquote(locale), unquote(domain), msgctxt, msgid, msgid_plural, n, bindings) do + defp lngettext_compiled( + unquote(locale), + unquote(domain), + msgctxt, + msgid, + msgid_plural, + n, + bindings + ) do unquote(module).unquote(plural_fun)(msgctxt, msgid, msgid_plural, n, bindings) end end diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex new file mode 100644 index 00000000..acd5cded --- /dev/null +++ b/lib/gettext/repo.ex @@ -0,0 +1,26 @@ +defmodule Gettext.Repo do + @moduledoc """ + A module that implements this behaviour loads translation strings. + + See `Gettext.ETSRepo` for an example. + """ + + @type locale() :: binary() + @type domain() :: binary() + @type msgctxt() :: binary() | nil + @type msgid() :: binary() + @type plural_form() :: integer() + @type msgstr() :: binary() + + @doc """ + Should return a singular translation string. + """ + @callback get_translation(locale(), domain(), msgctxt(), msgid()) :: + {:ok, msgstr()} | {:error, :translation_not_found} + + @doc """ + Should return a plural translation string. + """ + @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), plural_form()) :: + {:ok, msgstr()} | {:error, :translation_not_found} +end diff --git a/test/gettext_test.exs b/test/gettext_test.exs index 9d7b5038..4934841f 100644 --- a/test/gettext_test.exs +++ b/test/gettext_test.exs @@ -904,4 +904,69 @@ defmodule GettextTest do assert "quack foo %{} quack" = gettext("foo") end + + defmodule GettextTest.TranslatorWithRuntimeRepo do + use Gettext, + otp_app: :test_application, + repo: GettextTest.PersistentTermRepo + end + + defmodule GettextTest.PersistentTermRepo do + @behaviour Gettext.Repo + + use Agent + + def start_link(_opts) do + Agent.start_link(fn -> nil end, name: __MODULE__) + end + + def set_msgstr(msgstr) do + Agent.update(__MODULE__, fn _ -> msgstr end) + end + + def get_msgstr do + case Agent.get(__MODULE__, & &1) do + nil -> {:error, :translation_not_found} + msgstr -> {:ok, msgstr} + end + end + + @impl Gettext.Repo + def get_translation(_locale, _domain, _msgctxt, _msgid) do + get_msgstr() + end + + @impl Gettext.Repo + def get_plural_translation(_locale, _domain, _msgctxt, _msgid, _plural_form) do + get_msgstr() + end + end + + test "uses runtime repo" do + import GettextTest.TranslatorWithRuntimeRepo, only: [lgettext: 5, lngettext: 7] + + {:ok, repo} = GettextTest.PersistentTermRepo.start_link([]) + + get_singular = fn -> lgettext("it", "default", nil, "Hello world", %{}) end + + get_plural = fn -> + lngettext( + "it", + "errors", + nil, + "There was an error", + "There were %{count} errors", + 1, + %{} + ) + end + + assert get_singular.() == {:ok, "Ciao mondo"} + assert get_plural.() == {:ok, "C'è stato un errore"} + + GettextTest.PersistentTermRepo.set_msgstr("Runtime") + + assert get_singular.() == {:ok, "Runtime"} + assert get_plural.() == {:ok, "Runtime"} + end end From fa94a8e0cea25c1b87965459aca694e3b546aae3 Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 16 Apr 2022 15:29:57 +0100 Subject: [PATCH 02/12] return just :not_found instead of a tuple --- lib/gettext/repo.ex | 4 ++-- test/gettext_test.exs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex index acd5cded..8039456f 100644 --- a/lib/gettext/repo.ex +++ b/lib/gettext/repo.ex @@ -16,11 +16,11 @@ defmodule Gettext.Repo do Should return a singular translation string. """ @callback get_translation(locale(), domain(), msgctxt(), msgid()) :: - {:ok, msgstr()} | {:error, :translation_not_found} + {:ok, msgstr()} | :not_found @doc """ Should return a plural translation string. """ @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), plural_form()) :: - {:ok, msgstr()} | {:error, :translation_not_found} + {:ok, msgstr()} | :not_found end diff --git a/test/gettext_test.exs b/test/gettext_test.exs index 4934841f..d1937d01 100644 --- a/test/gettext_test.exs +++ b/test/gettext_test.exs @@ -926,7 +926,7 @@ defmodule GettextTest do def get_msgstr do case Agent.get(__MODULE__, & &1) do - nil -> {:error, :translation_not_found} + nil -> :not_found msgstr -> {:ok, msgstr} end end From 63aea14c08c3d01a02992b9a04c4b78dbe9a2a08 Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 16 Apr 2022 15:49:43 +0100 Subject: [PATCH 03/12] feat: configurable repository with init function --- lib/gettext/compiler.ex | 19 ++++++++----- lib/gettext/repo.ex | 10 +++++-- test/gettext_test.exs | 60 +++++++++++++++++++++++++++++------------ 3 files changed, 64 insertions(+), 25 deletions(-) diff --git a/lib/gettext/compiler.ex b/lib/gettext/compiler.ex index 76f37bf9..787f7f3f 100644 --- a/lib/gettext/compiler.ex +++ b/lib/gettext/compiler.ex @@ -36,7 +36,13 @@ defmodule Gettext.Compiler do default_domain = opts[:default_domain] || @default_domain interpolation = opts[:interpolation] || Gettext.Interpolation.Default - repo = opts[:repo] + + {repo, repo_opts} = + case opts[:repo] do + nil -> {nil, nil} + mod when is_atom(mod) -> {mod, mod.init([])} + {mod, opts} when is_atom(mod) -> {mod, mod.init(opts)} + end plural_mod = Keyword.get(opts, :plural_forms) || @@ -67,7 +73,7 @@ defmodule Gettext.Compiler do unquote(macros()) - unquote(public_functions(repo, interpolation, plural_mod)) + unquote(public_functions(repo, repo_opts, interpolation, plural_mod)) unquote(compile_po_files(env, known_po_files, plural_mod, opts)) @@ -314,7 +320,7 @@ defmodule Gettext.Compiler do end end - defp public_functions(nil, _interpolation, _plural_mod) do + defp public_functions(nil, _repo_opts, _interpolation, _plural_mod) do quote do def lgettext(locale, domain, msgctxt \\ nil, msgid, bindings) do lgettext_compiled(locale, domain, msgctxt, msgid, bindings) @@ -326,10 +332,10 @@ defmodule Gettext.Compiler do end end - defp public_functions(repo, interpolation, plural_mod) do + defp public_functions(repo, repo_opts, interpolation, plural_mod) do quote do def lgettext(locale, domain, msgctxt, msgid, bindings) do - case unquote(repo).get_translation(locale, domain, msgctxt, msgid) do + case unquote(repo).get_translation(locale, domain, msgctxt, msgid, unquote(repo_opts)) do {:ok, msgstr} -> unquote(interpolation).runtime_interpolate(msgstr, bindings) @@ -346,7 +352,8 @@ defmodule Gettext.Compiler do domain, msgctxt, msgid, - plural_form + plural_form, + unquote(repo_opts) ) do {:ok, msgstr} -> bindings = Map.put(bindings, :count, n) diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex index 8039456f..9d063031 100644 --- a/lib/gettext/repo.ex +++ b/lib/gettext/repo.ex @@ -11,16 +11,22 @@ defmodule Gettext.Repo do @type msgid() :: binary() @type plural_form() :: integer() @type msgstr() :: binary() + @type opts() :: term() + + @doc """ + Called at compile time to configure the repository. + """ + @callback init(opts()) :: opts() @doc """ Should return a singular translation string. """ - @callback get_translation(locale(), domain(), msgctxt(), msgid()) :: + @callback get_translation(locale(), domain(), msgctxt(), msgid(), opts()) :: {:ok, msgstr()} | :not_found @doc """ Should return a plural translation string. """ - @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), plural_form()) :: + @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), plural_form(), opts()) :: {:ok, msgstr()} | :not_found end diff --git a/test/gettext_test.exs b/test/gettext_test.exs index d1937d01..7a34497b 100644 --- a/test/gettext_test.exs +++ b/test/gettext_test.exs @@ -905,47 +905,61 @@ defmodule GettextTest do assert "quack foo %{} quack" = gettext("foo") end - defmodule GettextTest.TranslatorWithRuntimeRepo do - use Gettext, - otp_app: :test_application, - repo: GettextTest.PersistentTermRepo - end - defmodule GettextTest.PersistentTermRepo do @behaviour Gettext.Repo use Agent - def start_link(_opts) do - Agent.start_link(fn -> nil end, name: __MODULE__) + def start_link(opts) do + name = Keyword.get(opts, :name, __MODULE__) + Agent.start_link(fn -> nil end, name: name) end - def set_msgstr(msgstr) do - Agent.update(__MODULE__, fn _ -> msgstr end) + def set_msgstr(msgstr, name \\ __MODULE__) do + Agent.update(name, fn _ -> msgstr end) end - def get_msgstr do - case Agent.get(__MODULE__, & &1) do + def get_msgstr(name \\ __MODULE__) do + case Agent.get(name, & &1) do nil -> :not_found msgstr -> {:ok, msgstr} end end @impl Gettext.Repo - def get_translation(_locale, _domain, _msgctxt, _msgid) do - get_msgstr() + def init(name) when is_atom(name) do + name end + def init(_), do: __MODULE__ + @impl Gettext.Repo - def get_plural_translation(_locale, _domain, _msgctxt, _msgid, _plural_form) do - get_msgstr() + def get_translation(_locale, _domain, _msgctxt, _msgid, name) do + get_msgstr(name) + end + + @impl Gettext.Repo + def get_plural_translation(_locale, _domain, _msgctxt, _msgid, _plural_form, name) do + get_msgstr(name) end end + defmodule GettextTest.TranslatorWithRuntimeRepo do + use Gettext, + otp_app: :test_application, + repo: GettextTest.PersistentTermRepo + end + + defmodule GettextTest.TranslatorWithConfigurableRuntimeRepo do + use Gettext, + otp_app: :test_application, + repo: {GettextTest.PersistentTermRepo, :gettext_test_repo_name} + end + test "uses runtime repo" do import GettextTest.TranslatorWithRuntimeRepo, only: [lgettext: 5, lngettext: 7] - {:ok, repo} = GettextTest.PersistentTermRepo.start_link([]) + {:ok, _repo} = GettextTest.PersistentTermRepo.start_link([]) get_singular = fn -> lgettext("it", "default", nil, "Hello world", %{}) end @@ -969,4 +983,16 @@ defmodule GettextTest do assert get_singular.() == {:ok, "Runtime"} assert get_plural.() == {:ok, "Runtime"} end + + test "runtime repo can be initialized with config value" do + import GettextTest.TranslatorWithConfigurableRuntimeRepo, only: [lgettext: 5] + + {:ok, _repo1} = GettextTest.PersistentTermRepo.start_link([]) + {:ok, _repo2} = GettextTest.PersistentTermRepo.start_link(name: :gettext_test_repo_name) + + GettextTest.PersistentTermRepo.set_msgstr("Not this one") + GettextTest.PersistentTermRepo.set_msgstr("This one", :gettext_test_repo_name) + + assert lgettext("it", "default", nil, "Hello world", %{}) == {:ok, "This one"} + end end From 1aca9b308c23548f965a0343fdda0f3a24a99888 Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 20 Aug 2022 21:14:22 +0100 Subject: [PATCH 04/12] rename agent-based test repo --- test/gettext_test.exs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/test/gettext_test.exs b/test/gettext_test.exs index 7a34497b..991bd396 100644 --- a/test/gettext_test.exs +++ b/test/gettext_test.exs @@ -905,7 +905,7 @@ defmodule GettextTest do assert "quack foo %{} quack" = gettext("foo") end - defmodule GettextTest.PersistentTermRepo do + defmodule GettextTest.TestRepo do @behaviour Gettext.Repo use Agent @@ -947,19 +947,19 @@ defmodule GettextTest do defmodule GettextTest.TranslatorWithRuntimeRepo do use Gettext, otp_app: :test_application, - repo: GettextTest.PersistentTermRepo + repo: GettextTest.TestRepo end defmodule GettextTest.TranslatorWithConfigurableRuntimeRepo do use Gettext, otp_app: :test_application, - repo: {GettextTest.PersistentTermRepo, :gettext_test_repo_name} + repo: {GettextTest.TestRepo, :gettext_test_repo_name} end test "uses runtime repo" do import GettextTest.TranslatorWithRuntimeRepo, only: [lgettext: 5, lngettext: 7] - {:ok, _repo} = GettextTest.PersistentTermRepo.start_link([]) + {:ok, _repo} = GettextTest.TestRepo.start_link([]) get_singular = fn -> lgettext("it", "default", nil, "Hello world", %{}) end @@ -978,7 +978,7 @@ defmodule GettextTest do assert get_singular.() == {:ok, "Ciao mondo"} assert get_plural.() == {:ok, "C'è stato un errore"} - GettextTest.PersistentTermRepo.set_msgstr("Runtime") + GettextTest.TestRepo.set_msgstr("Runtime") assert get_singular.() == {:ok, "Runtime"} assert get_plural.() == {:ok, "Runtime"} @@ -987,11 +987,11 @@ defmodule GettextTest do test "runtime repo can be initialized with config value" do import GettextTest.TranslatorWithConfigurableRuntimeRepo, only: [lgettext: 5] - {:ok, _repo1} = GettextTest.PersistentTermRepo.start_link([]) - {:ok, _repo2} = GettextTest.PersistentTermRepo.start_link(name: :gettext_test_repo_name) + {:ok, _repo1} = GettextTest.TestRepo.start_link([]) + {:ok, _repo2} = GettextTest.TestRepo.start_link(name: :gettext_test_repo_name) - GettextTest.PersistentTermRepo.set_msgstr("Not this one") - GettextTest.PersistentTermRepo.set_msgstr("This one", :gettext_test_repo_name) + GettextTest.TestRepo.set_msgstr("Not this one") + GettextTest.TestRepo.set_msgstr("This one", :gettext_test_repo_name) assert lgettext("it", "default", nil, "Hello world", %{}) == {:ok, "This one"} end From 32c1339ea276a8c837f9fd5d92f96e275d54fa36 Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 20 Aug 2022 21:14:41 +0100 Subject: [PATCH 05/12] fix: remove unused runtime interpolate call --- lib/gettext/compiler.ex | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/gettext/compiler.ex b/lib/gettext/compiler.ex index 787f7f3f..af9b764d 100644 --- a/lib/gettext/compiler.ex +++ b/lib/gettext/compiler.ex @@ -360,7 +360,6 @@ defmodule Gettext.Compiler do unquote(interpolation).runtime_interpolate(msgstr, bindings) _ -> - unquote(interpolation).runtime_interpolate(msgid, bindings) lngettext_compiled(locale, domain, msgctxt, msgid, msgid_plural, n, bindings) end end From 5fb99e1a53f1617e9ee802ed62bb2a392d72af02 Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 20 Aug 2022 21:19:47 +0100 Subject: [PATCH 06/12] doc: remove old reference to ETSRepo --- lib/gettext/repo.ex | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex index 9d063031..623c3657 100644 --- a/lib/gettext/repo.ex +++ b/lib/gettext/repo.ex @@ -1,8 +1,6 @@ defmodule Gettext.Repo do @moduledoc """ A module that implements this behaviour loads translation strings. - - See `Gettext.ETSRepo` for an example. """ @type locale() :: binary() From 35dfb302494744a1aae28c9fbccb480dda33c1fe Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 20 Aug 2022 21:23:21 +0100 Subject: [PATCH 07/12] feat: include msgid_plural in get_plural_translation --- lib/gettext/compiler.ex | 1 + lib/gettext/repo.ex | 3 ++- test/gettext_test.exs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/gettext/compiler.ex b/lib/gettext/compiler.ex index af9b764d..44c61645 100644 --- a/lib/gettext/compiler.ex +++ b/lib/gettext/compiler.ex @@ -352,6 +352,7 @@ defmodule Gettext.Compiler do domain, msgctxt, msgid, + msgid_plural, plural_form, unquote(repo_opts) ) do diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex index 623c3657..aab24dc3 100644 --- a/lib/gettext/repo.ex +++ b/lib/gettext/repo.ex @@ -7,6 +7,7 @@ defmodule Gettext.Repo do @type domain() :: binary() @type msgctxt() :: binary() | nil @type msgid() :: binary() + @type msgid_plural() :: binary() @type plural_form() :: integer() @type msgstr() :: binary() @type opts() :: term() @@ -25,6 +26,6 @@ defmodule Gettext.Repo do @doc """ Should return a plural translation string. """ - @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), plural_form(), opts()) :: + @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), msgid_plural(), plural_form(), opts()) :: {:ok, msgstr()} | :not_found end diff --git a/test/gettext_test.exs b/test/gettext_test.exs index 991bd396..17c4fbbf 100644 --- a/test/gettext_test.exs +++ b/test/gettext_test.exs @@ -939,7 +939,7 @@ defmodule GettextTest do end @impl Gettext.Repo - def get_plural_translation(_locale, _domain, _msgctxt, _msgid, _plural_form, name) do + def get_plural_translation(_locale, _domain, _msgctxt, _msgid, _msgid_plural, _plural_form, name) do get_msgstr(name) end end From 6991fb984976ccbe1e2f22452cb39a75b0e7d57d Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sun, 21 Aug 2022 18:42:04 +0100 Subject: [PATCH 08/12] fix: test translators need to specify priv now --- test/gettext_test.exs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/gettext_test.exs b/test/gettext_test.exs index 17c4fbbf..72cc5298 100644 --- a/test/gettext_test.exs +++ b/test/gettext_test.exs @@ -947,12 +947,14 @@ defmodule GettextTest do defmodule GettextTest.TranslatorWithRuntimeRepo do use Gettext, otp_app: :test_application, + priv: "test/fixtures/single_messages", repo: GettextTest.TestRepo end defmodule GettextTest.TranslatorWithConfigurableRuntimeRepo do use Gettext, otp_app: :test_application, + priv: "test/fixtures/single_messages", repo: {GettextTest.TestRepo, :gettext_test_repo_name} end From 853fec514495db4ed85f341a0d84a187522428b5 Mon Sep 17 00:00:00 2001 From: Andrea Leopardi Date: Sun, 21 Aug 2022 08:44:37 +0200 Subject: [PATCH 09/12] Apply suggestions from code review --- lib/gettext/repo.ex | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex index aab24dc3..3d15f491 100644 --- a/lib/gettext/repo.ex +++ b/lib/gettext/repo.ex @@ -1,13 +1,13 @@ defmodule Gettext.Repo do @moduledoc """ - A module that implements this behaviour loads translation strings. + A behaviour for modules that can fetch Gettext translations. """ - @type locale() :: binary() - @type domain() :: binary() - @type msgctxt() :: binary() | nil - @type msgid() :: binary() - @type msgid_plural() :: binary() + @type locale() :: String.t() + @type domain() :: String.t() + @type msgctxt() :: String.t() | nil + @type msgid() :: String.t() + @type msgid_plural() :: String.t() @type plural_form() :: integer() @type msgstr() :: binary() @type opts() :: term() From 17d8397ef1001936fc2e4725f87b2da473a78f4c Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 21 Jan 2023 12:47:26 +0000 Subject: [PATCH 10/12] Pass count to repo.get_plural_translation instead of plural_form --- lib/gettext/compiler.ex | 22 ++++++++++------------ lib/gettext/repo.ex | 4 ++-- test/gettext_test.exs | 2 +- 3 files changed, 13 insertions(+), 15 deletions(-) diff --git a/lib/gettext/compiler.ex b/lib/gettext/compiler.ex index 6a569b4c..d0f86fbe 100644 --- a/lib/gettext/compiler.ex +++ b/lib/gettext/compiler.ex @@ -45,10 +45,6 @@ defmodule Gettext.Compiler do {mod, opts} when is_atom(mod) -> {mod, mod.init(opts)} end - plural_mod = - Keyword.get(opts, :plural_forms) || - Application.get_env(:gettext, :plural_forms, Gettext.Plural) - quote do @behaviour Gettext.Backend @@ -74,9 +70,9 @@ defmodule Gettext.Compiler do unquote(macros()) - unquote(public_functions(repo, repo_opts, interpolation, plural_mod)) + unquote(public_functions(repo, repo_opts, interpolation)) - unquote(compile_po_files(env, known_po_files, plural_mod, opts)) + unquote(compile_po_files(env, known_po_files, opts)) # Catch-all clauses. defp lgettext_compiled(locale, domain, msgctxt, msgid, bindings), @@ -321,7 +317,7 @@ defmodule Gettext.Compiler do end end - defp public_functions(nil, _repo_opts, _interpolation, _plural_mod) do + defp public_functions(nil, _repo_opts, _interpolation) do quote do def lgettext(locale, domain, msgctxt \\ nil, msgid, bindings) do lgettext_compiled(locale, domain, msgctxt, msgid, bindings) @@ -333,7 +329,7 @@ defmodule Gettext.Compiler do end end - defp public_functions(repo, repo_opts, interpolation, plural_mod) do + defp public_functions(repo, repo_opts, interpolation) do quote do def lgettext(locale, domain, msgctxt, msgid, bindings) do case unquote(repo).get_translation(locale, domain, msgctxt, msgid, unquote(repo_opts)) do @@ -346,15 +342,13 @@ defmodule Gettext.Compiler do end def lngettext(locale, domain, msgctxt, msgid, msgid_plural, n, bindings) do - plural_form = unquote(plural_mod).plural(locale, n) - case unquote(repo).get_plural_translation( locale, domain, msgctxt, msgid, msgid_plural, - plural_form, + n, unquote(repo_opts) ) do {:ok, msgstr} -> @@ -447,7 +441,11 @@ defmodule Gettext.Compiler do # Compiles all the `.po` files in the given directory (`dir`) into `lgettext/4` # and `lngettext/6` function clauses. - defp compile_po_files(env, known_po_files, plural_mod, opts) do + defp compile_po_files(env, known_po_files, opts) do + plural_mod = + Keyword.get(opts, :plural_forms) || + Application.get_env(:gettext, :plural_forms, Gettext.Plural) + opts = if opts[:one_module_per_locale] do IO.warn( diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex index 3d15f491..5b5fc09e 100644 --- a/lib/gettext/repo.ex +++ b/lib/gettext/repo.ex @@ -8,7 +8,7 @@ defmodule Gettext.Repo do @type msgctxt() :: String.t() | nil @type msgid() :: String.t() @type msgid_plural() :: String.t() - @type plural_form() :: integer() + @type count() :: integer() @type msgstr() :: binary() @type opts() :: term() @@ -26,6 +26,6 @@ defmodule Gettext.Repo do @doc """ Should return a plural translation string. """ - @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), msgid_plural(), plural_form(), opts()) :: + @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), msgid_plural(), count(), opts()) :: {:ok, msgstr()} | :not_found end diff --git a/test/gettext_test.exs b/test/gettext_test.exs index 9e24f094..e7270404 100644 --- a/test/gettext_test.exs +++ b/test/gettext_test.exs @@ -955,7 +955,7 @@ defmodule GettextTest do end @impl Gettext.Repo - def get_plural_translation(_locale, _domain, _msgctxt, _msgid, _msgid_plural, _plural_form, name) do + def get_plural_translation(_locale, _domain, _msgctxt, _msgid, _msgid_plural, _count, name) do get_msgstr(name) end end From cb5aabb893ffe35e0fa36ebcc00351fb2e1fd57d Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 21 Jan 2023 13:13:33 +0000 Subject: [PATCH 11/12] Fix formatting --- lib/gettext/repo.ex | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/gettext/repo.ex b/lib/gettext/repo.ex index 5b5fc09e..b00b7626 100644 --- a/lib/gettext/repo.ex +++ b/lib/gettext/repo.ex @@ -26,6 +26,14 @@ defmodule Gettext.Repo do @doc """ Should return a plural translation string. """ - @callback get_plural_translation(locale(), domain(), msgctxt(), msgid(), msgid_plural(), count(), opts()) :: + @callback get_plural_translation( + locale(), + domain(), + msgctxt(), + msgid(), + msgid_plural(), + count(), + opts() + ) :: {:ok, msgstr()} | :not_found end From 8eb0bce139838fc0384b51027c033bb64a0de618 Mon Sep 17 00:00:00 2001 From: Bernardo Amorim Date: Sat, 21 Jan 2023 15:54:17 +0000 Subject: [PATCH 12/12] Keep underscored arg name when matching argument Co-authored-by: Andrea Leopardi --- lib/gettext/compiler.ex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gettext/compiler.ex b/lib/gettext/compiler.ex index d0f86fbe..c5434694 100644 --- a/lib/gettext/compiler.ex +++ b/lib/gettext/compiler.ex @@ -317,7 +317,7 @@ defmodule Gettext.Compiler do end end - defp public_functions(nil, _repo_opts, _interpolation) do + defp public_functions(nil = _repo, _repo_opts, _interpolation) do quote do def lgettext(locale, domain, msgctxt \\ nil, msgid, bindings) do lgettext_compiled(locale, domain, msgctxt, msgid, bindings)