Current section

Files

Jump to
exi18n lib exi18n.ex
Raw

lib/exi18n.ex

defmodule ExI18n do
@moduledoc """
ExI18n - key-based internationalization library.
"""
@doc "Default locale set in configuration."
def locale, do: Application.get_env(:exi18n, :default_locale)
@doc "Path to directory that contains all files with translations."
def path, do: Application.get_env(:exi18n, :path)
@doc "Storage type used to store translations."
def storage, do: Application.get_env(:exi18n, :storage)
@doc """
Search for translation in given `locale` based on provided `key`.
## Parameters
- `locale`: `String` with name of locale.
- `key`: `String` with path to translation.
- `values`: `Map` with values that will be interpolated.
## Examples
iex> ExI18n.t("en", "hello")
"Hello world"
iex> ExI18n.t("en", "hello_name", name: "Joe")
"Hello Joe"
iex> ExI18n.t("en", "invalid")
** (ArgumentError) Missing translation for key: invalid
iex> ExI18n.t("en", "incomplete.path")
** (ArgumentError) incomplete.path is incomplete path to translation.
iex> ExI18n.t("en", "hello_name", name: %{"1" => "2"})
** (Protocol.UndefinedError) protocol String.Chars not implemented for %{"1" => "2"}
"""
@spec t(String.t, String.t, Map.t) :: String.t
def t(locale, key, values \\ %{}) do
translation = load_locales(locale) |> get_in(extract_keys(key))
cond do
is_bitstring(translation) || is_list(translation) ->
ExI18n.Compiler.compile(translation, values)
is_number(translation) -> translation
is_nil(translation) -> raise ArgumentError, "Missing translation for key: #{key}"
true -> raise ArgumentError, "#{key} is incomplete path to translation."
end
end
defp extract_keys(key), do: String.split(key, ".")
defp load_locales(locale) do
init_cache()
case :ets.lookup(:exi18n_locales, locale) do
[result|_] -> elem(result, 1)
[] ->
translations = ExI18n.Loader.load(locale)
:ets.insert(:exi18n_locales, {locale, translations})
translations
end
end
defp init_cache do
if :ets.info(:exi18n_locales) == :undefined do
:ets.new(:exi18n_locales, [:named_table])
end
end
end