Skip to content

zebbra/gettext_sigils

Repository files navigation

Gettext Sigils

An Elixir library that provides a ~t sigil for using Gettext translations with less boilerplate and improved readability:

# before
gettext("Hello, %{name}", name: user.name)

# after
~t"Hello, #{user.name}"

Installation

If available in Hex, the package can be installed by adding gettext_sigils to your list of dependencies in mix.exs:

def deps do
  [
    {:gettext_sigils, "~> 0.1.0"}
  ]
end

Basic Usage

To use the ~t sigil in your module, just use GettextSigils instead of the default Gettext module (for example in MyAppWeb.html_helpers/0 when using Phoenix):

# replace this
use Gettext, backend: MyApp.Gettext

# with this
use GettextSigils, backend: MyApp.Gettext

You can then use the ~t sigil instead of the gettext macro:

~t"Hello, World!"
# same as
gettext("Hello, World")

Note: The default Gettext macros (gettext, pgettext, dgettext, ...) are still available if required.

Domain & Context

Gettext domain and context are provided under the sigils key when using the module. All other options are passed through to use Gettext.

defmodule MyApp.Errors.NotFound do
  use GettextSigils,
    backend: MyApp.Gettext,
    sigils: [
      domain: "errors",
      context: inspect(__MODULE__)
    ]

  def description(path) do
    # uses domain and context from sigils options
    ~t[The file "#{path}" does not exist]

    # is equivalent to
    dpgettext(
      "errors",
      inspect(__MODULE__),
      ~s[The file "%{path}" does not exist],
      path: path
    )
  end
end

Modifiers

Sigil modifiers (single lowercase letters appended to the sigil) can be used to override the domain and context on a per-translation basis. Define modifiers in the sigils options:

defmodule MyApp.Frontend do
  use GettextSigils,
    backend: MyApp.Gettext,
    sigils: [
      domain: "frontend",
      modifiers: [
        e: [domain: "errors"],
        g: [domain: "default", context: nil],
        m: [context: inspect(__MODULE__)]
      ]
    ]

  def example do
    ~t"Welcome"           # domain: "frontend", context: nil
    ~t"Yes"g              # domain: "default",  context: nil
    ~t"Not found"e        # domain: "errors",   context: nil
    ~t"Hello"m            # domain: "frontend", context: "MyApp.Frontend"
    ~t"Oops"em            # domain: "errors",   context: "MyApp.Frontend"
  end
end

Each modifier key must be a single lowercase letter (az) and accepts the options :domain and :context. Using an undefined modifier results in a compile-time error.

Interpolation

Gettext interpolation works similar to regular Elixir strings. Keys are derived automatically from the expression:

~t"The #{fruit.name} is #{color}"
# => gettext("The %{fruit_name} is %{color}", fruit_name: fruit.name, color: color)

~t"Status: #{String.upcase(status)}"
# => gettext("Status: %{string_upcase}", string_upcase: String.upcase(status))

~t"Value: #{1 + 2}"
# => gettext("Value: %{var}", var: 1 + 2)

Duplicate keys are allowed if they refer to the same expression. Otherwise, an ambiguous key error is raised.

# This is allowed:
~t"#{name} is #{name}"
# => gettext("%{name} is %{name}", name: name)

# This is NOT allowed:
~t"This is invalid: #{Foo.bar()} != #{foo.bar}"
# => raises ArgumentError (foo_bar)

Use explicit keys to disambiguate between expressions with the same key.

Explicit keys

Explicit keys can be used with the :: syntax for more control to disambiguate between multiple bindings with the same key:

~t"Order status: #{status :: order_status(resp[field])}"
# => gettext("Order status: %{status}", status: order_status(resp[field]))

~t"Valid: #{x :: Foo.bar()} != #{y :: foo_bar}"
# => gettext("Valid: %{x} != %{y}", x: Foo.bar(), y: foo_bar)

Pluralization

Gettext pluralization (ngettext, ...) is currently not supported. See open issue #3.

About

An Elixir library that provides a `~t` sigil for using Gettext

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages