Skip to content

Commit 57c6249

Browse files
authored
Avoid compile-time dependency to Gettext backend (#391)
1 parent c602ea9 commit 57c6249

9 files changed

Lines changed: 575 additions & 285 deletions

File tree

lib/gettext.ex

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -627,19 +627,36 @@ defmodule Gettext do
627627

628628
@doc false
629629
defmacro __using__(opts) do
630-
quote do
631-
opts = unquote(opts)
632-
633-
if Keyword.has_key?(opts, :backend) do
634-
raise "not implemented yet"
630+
opts =
631+
if Macro.quoted_literal?(opts) do
632+
Macro.prewalk(opts, &expand_alias(&1, __CALLER__))
635633
else
636-
# TODO: Deprecate this branch
637-
require Gettext.Backend
638-
Gettext.Backend.__using__(opts)
634+
opts
639635
end
636+
637+
case Keyword.keyword?(opts) && Keyword.fetch(opts, :backend) do
638+
{:ok, backend} ->
639+
quote do
640+
@__gettext_backend__ unquote(backend)
641+
import Gettext.Macros
642+
end
643+
644+
_other ->
645+
quote do
646+
# TODO: Deprecate this branch
647+
use Gettext.Backend, unquote(opts)
648+
end
640649
end
641650
end
642651

652+
defp expand_alias({:__aliases__, _, _} = als, env) do
653+
Macro.expand(als, %{env | function: {:__gettext__, 1}})
654+
end
655+
656+
defp expand_alias(other, _env) do
657+
other
658+
end
659+
643660
@doc """
644661
Gets the global Gettext locale for the current process.
645662

lib/gettext/backend.ex

Lines changed: 24 additions & 245 deletions
Original file line numberDiff line numberDiff line change
@@ -175,255 +175,34 @@ defmodule Gettext.Backend do
175175
{:ok, String.t()} | {:default, String.t()} | {:missing_bindings, String.t(), [atom]}
176176

177177
@doc """
178-
Translates the given `msgid` with a given context (`msgctxt`) in the given `domain`.
178+
Translates a message.
179179
180-
`bindings` is a map of bindings to support interpolation.
181-
182-
See also `Gettext.dpgettext/5`.
183-
"""
184-
@macrocallback dpgettext(
185-
domain :: Macro.t(),
186-
msgctxt :: String.t(),
187-
msgid :: String.t(),
188-
bindings :: Macro.t()
189-
) :: Macro.t()
190-
191-
@doc """
192-
Same as `dpgettext(domain, msgctxt, msgid, %{})`.
193-
194-
See also `Gettext.dpgettext/5`.
195-
"""
196-
@macrocallback dpgettext(domain :: Macro.t(), msgctxt :: String.t(), msgid :: String.t()) ::
197-
Macro.t()
198-
199-
@doc """
200-
Translates the given `msgid` in the given `domain`.
201-
202-
`bindings` is a map of bindings to support interpolation.
203-
204-
See also `Gettext.dgettext/4`.
205-
"""
206-
@macrocallback dgettext(domain :: Macro.t(), msgid :: String.t(), bindings :: Macro.t()) ::
207-
Macro.t()
208-
209-
@doc """
210-
Same as `dgettext(domain, msgid, %{})`.
211-
212-
See also `Gettext.dgettext/4`.
213-
"""
214-
@macrocallback dgettext(domain :: Macro.t(), msgid :: String.t()) :: Macro.t()
215-
216-
@doc """
217-
Translates the given `msgid` with the given context (`msgctxt`).
218-
219-
`bindings` is a map of bindings to support interpolation.
220-
221-
See also `Gettext.pgettext/4`.
222-
"""
223-
@macrocallback pgettext(msgctxt :: String.t(), msgid :: String.t(), bindings :: Macro.t()) ::
224-
Macro.t()
225-
226-
@doc """
227-
Same as `pgettext(msgctxt, msgid, %{})`.
228-
229-
See also `Gettext.pgettext/4`.
230-
"""
231-
@macrocallback pgettext(msgctxt :: String.t(), msgid :: String.t()) :: Macro.t()
232-
233-
@doc """
234-
Same as `dgettext("default", msgid, %{})`, but will use a per-backend
235-
configured default domain if provided.
236-
237-
See also `Gettext.gettext/3`.
238-
"""
239-
@macrocallback gettext(msgid :: String.t(), bindings :: Macro.t()) :: Macro.t()
240-
241-
@doc """
242-
Same as `gettext(msgid, %{})`.
243-
244-
See also `Gettext.gettext/3`.
245-
"""
246-
@macrocallback gettext(msgid :: String.t()) :: Macro.t()
247-
248-
@doc """
249-
Translates the given plural message (`msgid` + `msgid_plural`) with the given context (`msgctxt`)
250-
in the given `domain`.
251-
252-
`n` is an integer used to determine how to pluralize the
253-
message. `bindings` is a map of bindings to support interpolation.
254-
255-
See also `Gettext.dpngettext/7`.
256-
"""
257-
@macrocallback dpngettext(
258-
domain :: Macro.t(),
259-
msgctxt :: String.t(),
260-
msgid :: String.t(),
261-
msgid_plural :: String.t(),
262-
n :: Macro.t(),
263-
bindings :: Macro.t()
264-
) :: Macro.t()
265-
266-
@doc """
267-
Same as `dpngettext(domain, msgctxt, msgid, msgid_plural, n, %{})`.
268-
269-
See also `Gettext.dpngettext/7`.
270-
"""
271-
@macrocallback dpngettext(
272-
domain :: Macro.t(),
273-
msgctxt :: String.t(),
274-
msgid :: String.t(),
275-
msgid_plural :: String.t(),
276-
n :: Macro.t()
277-
) :: Macro.t()
278-
279-
@doc """
280-
Translates the given plural message (`msgid` + `msgid_plural`) in the
281-
given `domain`.
282-
283-
`n` is an integer used to determine how to pluralize the
284-
message. `bindings` is a map of bindings to support interpolation.
285-
286-
See also `Gettext.dngettext/6`.
287-
"""
288-
@macrocallback dngettext(
289-
domain :: Macro.t(),
290-
msgid :: String.t(),
291-
msgid_plural :: String.t(),
292-
n :: Macro.t(),
293-
bindings :: Macro.t()
294-
) :: Macro.t()
295-
296-
@doc """
297-
Same as `dngettext(domain, msgid, msgid_plural, n, %{})`.
298-
299-
See also `Gettext.dngettext/6`.
300-
"""
301-
@macrocallback dngettext(
302-
domain :: Macro.t(),
303-
msgid :: String.t(),
304-
msgid_plural :: String.t(),
305-
n :: Macro.t()
306-
) :: Macro.t()
307-
308-
@doc """
309-
Translates the given plural message (`msgid` + `msgid_plural`) with the given context (`msgctxt`).
310-
311-
`n` is an integer used to determine how to pluralize the
312-
message. `bindings` is a map of bindings to support interpolation.
313-
314-
See also `Gettext.pngettext/6`.
180+
See `Gettext.gettext/3` for more information.
315181
"""
316-
@macrocallback pngettext(
317-
msgctxt :: String.t(),
318-
msgid :: String.t(),
319-
msgid_plural :: String.t(),
320-
n :: Macro.t(),
321-
bindings :: Macro.t()
322-
) :: Macro.t()
323-
324-
@doc """
325-
Same as `pngettext(msgctxt, msgid, msgid_plural, n, %{})`.
326-
327-
See also `Gettext.pngettext/6`.
328-
"""
329-
@macrocallback pngettext(
330-
msgctxt :: String.t(),
331-
msgid :: String.t(),
332-
msgid_plural :: String.t(),
333-
n :: Macro.t()
334-
) :: Macro.t()
335-
336-
@doc """
337-
Same as `dngettext("default", msgid, msgid_plural, n, bindings)`, but will
338-
use a per-backend configured default domain if provided.
339-
340-
See also `Gettext.ngettext/5`.
341-
"""
342-
@macrocallback ngettext(
343-
msgid :: String.t(),
344-
msgid_plural :: String.t(),
345-
n :: Macro.t(),
346-
bindings :: Macro.t()
347-
) :: Macro.t()
348-
349-
@doc """
350-
Same as `ngettext(msgid, msgid_plural, n, %{})`.
351-
352-
See also `Gettext.ngettext/5`.
353-
"""
354-
@macrocallback ngettext(msgid :: String.t(), msgid_plural :: String.t(), n :: Macro.t()) ::
355-
Macro.t()
356-
357-
@doc """
358-
Marks the given message for extraction and returns it unchanged.
359-
360-
This macro can be used to mark a message for extraction when `mix
361-
gettext.extract` is run. The return value is the given string, so that this
362-
macro can be used seamlessly in place of the string to extract.
363-
364-
## Examples
365-
366-
MyApp.Gettext.dgettext_noop("errors", "Error found!")
367-
#=> "Error found!"
368-
369-
"""
370-
@macrocallback dgettext_noop(domain :: String.t(), msgid :: String.t()) :: Macro.t()
371-
372-
@doc """
373-
Same as `dgettext_noop("default", msgid)`.
374-
"""
375-
@macrocallback gettext_noop(msgid :: String.t()) :: Macro.t()
376-
377-
@doc """
378-
Marks the given message for extraction and returns
379-
`{msgid, msgid_plural}`.
380-
381-
This macro can be used to mark a message for extraction when `mix
382-
gettext.extract` is run. The return value of this macro is `{msgid,
383-
msgid_plural}`.
384-
385-
## Examples
386-
387-
my_fun = fn {msgid, msgid_plural} ->
388-
# do something with msgid and msgid_plural
389-
end
390-
391-
my_fun.(MyApp.Gettext.dngettext_noop("errors", "One error", "%{count} errors"))
392-
393-
"""
394-
@macrocallback dngettext_noop(
395-
domain :: Macro.t(),
396-
msgid :: String.t(),
397-
msgid_plural :: String.t()
398-
) :: Macro.t()
399-
400-
@doc """
401-
Same as `dngettext_noop("default", msgid, mgsid_plural)`, but will use a
402-
per-backend configured default domain if provided.
403-
"""
404-
@macrocallback ngettext_noop(msgid :: String.t(), msgid_plural :: String.t()) :: Macro.t()
182+
@doc since: "0.26.0"
183+
@callback lgettext(
184+
Gettext.locale(),
185+
domain :: String.t(),
186+
msgctxt :: String.t() | nil,
187+
msgid :: String.t(),
188+
bindings :: map()
189+
) ::
190+
{:ok, String.t()} | {:default, String.t()} | {:missing_bindings, String.t(), [atom]}
405191

406192
@doc """
407-
Stores an "extracted comment" for the next message.
408-
409-
This macro can be used to add comments (Gettext refers to such
410-
comments as *extracted comments*) to the next message that will
411-
be extracted. Extracted comments will be prefixed with `#.` in POT
412-
files.
413-
414-
Calling this function multiple times will accumulate the comments;
415-
when another Gettext macro (such as `c:gettext/2`) is called,
416-
the comments will be extracted and attached to that message, and
417-
they will be flushed so as to start again.
418-
419-
This macro always returns `:ok`.
420-
421-
## Examples
422-
423-
MyApp.Gettext.gettext_comment("The next message is awesome")
424-
MyApp.Gettext.gettext_comment("Another comment for the next message")
425-
MyApp.Gettext.gettext("The awesome message")
193+
Translates a plural message.
426194
195+
See `Gettext.ngettext/5` for more information.
427196
"""
428-
@macrocallback gettext_comment(comment :: String.t()) :: :ok
197+
@doc since: "0.26.0"
198+
@callback lngettext(
199+
Gettext.locale(),
200+
domain :: String.t(),
201+
msgctxt :: String.t() | nil,
202+
msgid :: String.t(),
203+
msgid_plural :: String.t(),
204+
n :: non_neg_integer(),
205+
bindings :: map()
206+
) ::
207+
{:ok, String.t()} | {:default, String.t()} | {:missing_bindings, String.t(), [atom]}
429208
end

lib/gettext/compiler.ex

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,12 @@ defmodule Gettext.Compiler do
6363

6464
unquote(macros())
6565

66-
# These are the two functions we generated inside the backend.
66+
# These are the two functions we generate inside the backend.
67+
68+
@impl Gettext.Backend
6769
def lgettext(locale, domain, msgctxt \\ nil, msgid, bindings)
70+
71+
@impl Gettext.Backend
6872
def lngettext(locale, domain, msgctxt \\ nil, msgid, msgid_plural, n, bindings)
6973

7074
unquote(compile_po_files(env, known_po_files, opts))

lib/gettext/extractor.ex

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,10 +68,23 @@ defmodule Gettext.Extractor do
6868
6969
Note that this function doesn't perform any operation on the filesystem.
7070
"""
71-
@spec extract(Macro.Env.t(), module, binary, binary, binary | {binary, binary}, [binary]) :: :ok
71+
@spec extract(
72+
Macro.Env.t(),
73+
backend :: module,
74+
domain :: binary | :default,
75+
msgctxt :: binary,
76+
id :: binary | {binary, binary},
77+
extracted_comments :: [binary]
78+
) :: :ok
7279
def extract(%Macro.Env{} = caller, backend, domain, msgctxt, id, extracted_comments) do
7380
format_flag = backend.__gettext__(:interpolation).message_format()
7481

82+
domain =
83+
case domain do
84+
:default -> backend.__gettext__(:default_domain)
85+
string when is_binary(string) -> string
86+
end
87+
7588
message =
7689
create_message_struct(
7790
id,

0 commit comments

Comments
 (0)