Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Unreleased

* Call `c:Gettext.Plural.init/1` once per PO file at compile time instead of twice.
* Add experimental `mix gettext.generate` task: messages are persisted as module attributes during normal compilation (for backends with `automatic_extraction: true` in the application environment, for example `config :gettext, MyApp.Gettext, automatic_extraction: true` in `config/dev.exs`) and read back from the compiled BEAM files, so extraction no longer needs to force-recompile the project.

## v1.1.0
Expand Down
16 changes: 7 additions & 9 deletions lib/gettext/compiler.ex
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,9 @@ defmodule Gettext.Compiler do

plural_forms_fun = :"#{locale}_#{domain}_plural"

plural_forms = compile_plural_forms(locale, messages_struct, plural_mod, plural_forms_fun)
nplurals = nplurals(locale, messages_struct, plural_mod)
plural_info = Plural.plural_info(locale, messages_struct, plural_mod)
plural_forms = compile_plural_forms(plural_info, plural_mod, plural_forms_fun)
nplurals = nplurals(plural_info, plural_mod)

singular_fun = :"#{locale}_#{domain}_lgettext"
plural_fun = :"#{locale}_#{domain}_lngettext"
Expand Down Expand Up @@ -552,17 +553,14 @@ defmodule Gettext.Compiler do
{locale, domain, singular_fun, plural_fun, quoted}
end

defp nplurals(locale, messages_struct, plural_mod) do
plural_mod.nplurals(Plural.plural_info(locale, messages_struct, plural_mod))
defp nplurals(plural_info, plural_mod) do
plural_mod.nplurals(plural_info)
end

defp compile_plural_forms(locale, messages_struct, plural_mod, plural_fun) do
defp compile_plural_forms(plural_info, plural_mod, plural_fun) do
quote do
defp unquote(plural_fun)(n) do
unquote(plural_mod).plural(
unquote(Macro.escape(Plural.plural_info(locale, messages_struct, plural_mod))),
n
)
unquote(plural_mod).plural(unquote(Macro.escape(plural_info)), n)
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/gettext/extractor.ex
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@ defmodule Gettext.Extractor do

defp read_contents_and_parse(path) do
contents = File.read!(path)
{contents, PO.parse_file!(path, file: path)}
{contents, PO.parse_string!(contents, file: path)}
end

# This function "tags" a {path, _} tuple in order to distinguish POT files
Expand Down
20 changes: 18 additions & 2 deletions lib/gettext/interpolation/default.ex
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,30 @@ defmodule Gettext.Interpolation.Default do
@doc false
@spec to_interpolatable(String.t()) :: interpolatable()
def to_interpolatable(string) when is_binary(string) do
start_pattern = :binary.compile_pattern("%{")
end_pattern = :binary.compile_pattern("}")
{start_pattern, end_pattern} = patterns()

string
|> to_interpolatable(_current = "", _acc = [], start_pattern, end_pattern)
|> Enum.reverse()
end

# The patterns are constant, but a compiled pattern is a reference, so it
# cannot be a module attribute. Compiling them on every call costs more than
# the split itself for short strings, so they are compiled once per VM.
@patterns_key {__MODULE__, :patterns}

defp patterns do
case :persistent_term.get(@patterns_key, nil) do
nil ->
patterns = {:binary.compile_pattern("%{"), :binary.compile_pattern("}")}
:persistent_term.put(@patterns_key, patterns)
patterns

patterns ->
patterns
end
end

defp to_interpolatable(string, current, acc, start_pattern, end_pattern) do
case :binary.split(string, start_pattern) do
# If we have one element, no %{ was found so this is the final part of the
Expand Down
Loading