Skip to content

Commit

Permalink
Merge pull request #1 from change/wbarrett/add-pluralization-support
Browse files Browse the repository at this point in the history
Add pluralization support
  • Loading branch information
willbarrett authored Apr 16, 2018
2 parents 50b81eb + 1d76a85 commit 085f67a
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 38 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,3 +46,11 @@ iex> I18n.t!("en", "users.title")
"Users"
```

## Configuration

The key to use for pluralization is configurable, and should likely be an atom:

```
config :linguist, pluralization_key: :count
```
will cause the system to pluralize based on the `count` parameter passed to the `t` function.
22 changes: 2 additions & 20 deletions config/config.exs
Original file line number Diff line number Diff line change
@@ -1,22 +1,4 @@
# This file is responsible for configuring your application
# and its dependencies. The Mix.Config module provides functions
# to aid in doing so.
use Mix.Config

# Note this file is loaded before any dependency and is restricted
# to this project. If another project depends on this project, this
# file won't be loaded nor affect the parent project.

# Sample configuration:
#
# config :my_dep,
# key: :value,
# limit: 42

# It is also possible to import configuration files, relative to this
# directory. For example, you can emulate configuration per environment
# by uncommenting the line below and defining dev.exs, test.exs and such.
# Configuration from the imported file will override the ones defined
# here (which is why it is important to import them last).
#
# import_config "#{Mix.env}.exs"
config :linguist,
pluralization_key: :count
26 changes: 21 additions & 5 deletions lib/linguist/compiler.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
defmodule Linguist.Compiler do
alias Linguist.NoTranslationError
alias Cldr.Number.Cardinal

@doc ~S"""
Compiles keyword list of transactions into function definitions AST
Expand All @@ -14,7 +15,7 @@ defmodule Linguist.Compiler do
quote do
def t(locale, path, binding \\ [])
def t("en", "hello", bindings), do: "Hello " <> Dict.fetch!(bindings, :name)
def t("en", "hello", bindings), do: "Hello " <> Keyword.fetch!(bindings, :name)
def t("en", "alert", bindings), do: "Alert!"
def t(_locale, _path, _bindings), do: {:error, :no_translation}
Expand All @@ -38,7 +39,7 @@ defmodule Linguist.Compiler do
@simple_interpol "%{"

def compile(translations) do
langs = Dict.keys translations
langs = Keyword.keys translations
translations =
for {locale, source} <- translations do
deftranslations(to_string(locale), "", source)
Expand All @@ -47,7 +48,7 @@ defmodule Linguist.Compiler do
quote do
def t(locale, path, binding \\ [])
unquote(translations)
def t(_locale, _path, _bindings), do: {:error, :no_translation}
def do_t(_locale, _path, _bindings), do: {:error, :no_translation}
def t!(locale, path, bindings \\ []) do
case t(locale, path, bindings) do
{:ok, translation} -> translation
Expand All @@ -69,7 +70,22 @@ defmodule Linguist.Compiler do
deftranslations(locale, path, val)
else
quote do
def t(unquote(locale), unquote(path), bindings) do
def t(locale, path, bindings) do
pluralization_key = Application.fetch_env!(:linguist, :pluralization_key)
if Keyword.has_key?(bindings, pluralization_key) do
plural_atom =
Cardinal.plural_rule(
Keyword.get(bindings, pluralization_key),
locale
)
new_path = "#{path}.#{plural_atom}"
do_t(locale, new_path, bindings)
else
do_t(locale, path, bindings)
end
end

def do_t(unquote(locale), unquote(path), bindings) do
{:ok, unquote(interpolate(val, :bindings))}
end
end
Expand All @@ -85,7 +101,7 @@ defmodule Linguist.Compiler do
key = String.to_atom(String.rstrip(rest, ?}))
bindings = Macro.var(var, __MODULE__)
quote do
unquote(acc) <> to_string(Dict.fetch!(unquote(bindings), unquote(key)))
unquote(acc) <> to_string(Keyword.fetch!(unquote(bindings), unquote(key)))
end
segment, acc -> quote do: (unquote(acc) <> unquote(unescape(segment)))
end )
Expand Down
13 changes: 8 additions & 5 deletions lib/linguist/vocabulary.ex
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,14 @@ defmodule Linguist.Vocabulary do
"""
defmacro locale(name, source) do
quote bind_quoted: [name: name, source: source] do
if is_binary(source) do
@external_resource source
source = Code.eval_file(source) |> elem(0)
end
@locales {name, source}
loaded_source =
if is_binary(source) do
@external_resource source
Code.eval_file(source) |> elem(0)
else
source
end
@locales {name, loaded_source}
end
end

Expand Down
15 changes: 9 additions & 6 deletions mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@ defmodule Linguist.Mixfile do
[
app: :linguist,
version: "0.1.5",
elixir: "~> 1.0",
deps: deps,
elixir: "~> 1.6",
deps: deps(),
package: [
contributors: ["Chris McCord"],
contributors: ["Will Barrett, Chris McCord"],
licenses: ["MIT"],
links: %{github: "https://github.com/chrismccord/linguist"}
links: %{github: "https://github.com/change/linguist"}
],
description: """
Elixir Internationalization library
Elixir Internationalization library, extended to support translation files in the rails-i18n format
"""
]
end
Expand All @@ -25,6 +25,9 @@ defmodule Linguist.Mixfile do
end

defp deps do
[]
[
{:ex_cldr, "~> 1.5"},
{:jason, "~> 1.0"}
]
end
end
6 changes: 6 additions & 0 deletions mix.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
%{
"abnf2": {:hex, :abnf2, "0.1.2", "6f8792b8ac3288dba5fc889c2bceae9fe78f74e1a7b36bea9726ffaa9d7bef95", [:mix], [], "hexpm"},
"decimal": {:hex, :decimal, "1.5.0", "b0433a36d0e2430e3d50291b1c65f53c37d56f83665b43d79963684865beab68", [:mix], [], "hexpm"},
"ex_cldr": {:hex, :ex_cldr, "1.5.2", "5c8fe295fef680a821b9e0c19242ea34037af11eb59e6d98f194e6c9c3b4252e", [:mix], [{:abnf2, "~> 0.1", [hex: :abnf2, repo: "hexpm", optional: false]}, {:decimal, "~> 1.4", [hex: :decimal, repo: "hexpm", optional: false]}, {:gettext, "~> 0.13", [hex: :gettext, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.3", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: true]}, {:poison, "~> 2.1 or ~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:sweet_xml, "~> 0.6", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm"},
"jason": {:hex, :jason, "1.0.0", "0f7cfa9bdb23fed721ec05419bcee2b2c21a77e926bce0deda029b5adc716fe2", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"},
}
6 changes: 5 additions & 1 deletion test/en.exs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@
title: "Profiles",
]
],
escaped: "%%{escaped}"
escaped: "%%{escaped}",
apple: [
one: "%{count} apple",
other: "%{count} apples"
]
]


20 changes: 19 additions & 1 deletion test/vocabulary_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ defmodule LinguistTest do
hello: "salut %{first} %{last}"
],
interpolation_at_beginning: "%{name} at beginning",
],
apple: [
one: "%{count} Pomme",
other: "%{count} pommes"
]
]
end
Expand Down Expand Up @@ -63,7 +67,7 @@ defmodule LinguistTest do

test "t! raises NoTranslationError when translation is missing" do
assert_raise Linguist.NoTranslationError, fn ->
assert I18n.t!("en", "flash.not_exists")
I18n.t!("en", "flash.not_exists")
end
end

Expand All @@ -78,4 +82,18 @@ defmodule LinguistTest do
test "interpolations can exist as the first segment of the translation" do
assert I18n.t!("fr", "flash.interpolation_at_beginning", name: "chris") == "chris at beginning"
end

describe "pluralizations" do
test "pluralizes English correctly" do
assert I18n.t!("en", "apple", count: 1) == "1 apple"
assert I18n.t!("en", "apple", count: 2) == "2 apples"
end

test "throws an error when a pluralized string is not given a count" do
assert_raise Linguist.NoTranslationError, fn ->
I18n.t!("en", "apple")
end
end
end

end

0 comments on commit 085f67a

Please sign in to comment.