View Source Cldr.Trans (Cldr Trans v1.1.0)
Manage translations embedded into structs.
Although it can be used with any struct Trans
shines when paired with an Ecto.Schema
. It
allows you to keep the translations into a field of the schema and avoids requiring extra tables
for translation storage and complex joins when retrieving translations from the database.
Trans
is split into two main components:
Trans.Translator
- provides easy access to struct translations.Trans.QueryBuilder
- provides helpers for querying translations usingEcto.Query
(requiresEcto.SQL
).
When used, Trans
accepts the following options:
:translates
(required) - list of the fields that will be translated.:container
(optional) - name of the field that contains the embedded translations. Defaults to:translations
.:default_locale
(optional) - declares the locale of the base untranslated column. Defaults to thedefault_locale
configured for the Cldr backend.
structured-translations
Structured translations
Structured translations are the preferred and recommended way of using Trans
. To use structured
translations you must define the translations as embedded schemas:
defmodule MyApp.Article do
use Ecto.Schema
use MyApp.Cldr.Trans, translates: [:title, :body]
schema "articles" do
field :title, :string
field :body, :string
embeds_one :translations, Translations, on_replace: :update, primary_key: false do
embeds_one :es, MyApp.Article.Translations.Fields
embeds_one :fr, MyApp.Article.Translations.Fields
end
end
end
defmodule MyApp.Article.Translations.Fields do
use Ecto.Schema
@primary_key false
embedded_schema do
field :title, :string
field :body, :string
end
end
Although they required more code than free-form translations, structured translations provide
some nice benefits that make them the preferred way of using Trans
:
- High flexibility when making validations and transformation using the embedded schema's own changeset.
- Easy to integrate with HTML forms leveraging the capabilities of Phoenix.HTML.Form.inputs_for/2
- Easy navegability using the dot notation.
free-form-translations
Free-form translations
Free-form translations were the main way of using Trans
until the 2.3.0 version. They are still
supported for compatibility with older versions but not recommended for new projects.
To use free-form translations you must define the translations as a map:
defmodule MyApp.Article do
use Ecto.Schema
use MyApp.Cldr.Trans, translates: [:title, :body]
schema "articles" do
field :title, :string
field :body, :string
field :translations, :map
end
end
Although they require less code, free-form translations provide much less guarantees:
- There is no way to tell what content and which form will be stored in the translations field.
- Hard to integrate with HTML forms since the Phoenix helpers are not available.
- Difficult navigation requiring the braces notation from the
Access
protocol.
the-translation-container
The translation container
As we have seen in the previous examples, Trans
automatically stores and looks for translations
in a field called :translations
. This is known as the translations container.
In certain cases you may want to use a different field for storing the translations, this can
be specified when using Trans
in your module.
# Use the field `:locales` as translation container instead of the default `:translations`
use Trans, translates: [...], container: :locales
reflection
Reflection
Any module that uses Trans
will have an autogenerated __trans__
function that can be used for
runtime introspection of the translation metadata.
__trans__(:fields)
- Returns the list of translatable fields.__trans__(:container)
- Returns the name of the translation container.__trans__(:default_locale)
- Returns the name of default locale.
Link to this section Summary
Types
A struct field as an atom
When translating or querying either a single locale or a list of locales can be provided
A translatable struct that uses Trans
Functions
Checks whether the given field is translatable or not.
Link to this section Types
@type field() :: atom()
A struct field as an atom
@type locale_list() :: Cldr.Locale.locale_reference() | [Cldr.Locale.locale_name(), ...]
When translating or querying either a single locale or a list of locales can be provided
@type translatable() :: struct()
A translatable struct that uses Trans
Link to this section Functions
@spec translatable?(module() | translatable(), String.t() | atom()) :: boolean()
Checks whether the given field is translatable or not.
Returns true if the given field is translatable. Raises if the given module or struct does not use
Trans
.
examples
Examples
Assuming the Article schema defined in Structured translations.
If we want to know whether a certain field is translatable or not we can use this function as follows (we can also pass a struct instead of the module name itself):
iex> Trans.translatable?(Article, :title)
true
May be also used with translatable structs:
iex> article = %Article{}
iex> Trans.translatable?(article, :not_existing)
false
Raises if the given module or struct does not use Trans
:
iex> Trans.translatable?(Date, :day)
** (RuntimeError) Elixir.Date must use `Trans` in order to be translated