Provides helpers for filtering translations in Ecto.Queries.
This module requires Ecto.SQL to be available during the compilation.
Summary
Functions
Generates a SQL fragment for accessing a translated field in an Ecto.Query.
Generates a SQL fragment for use in an Ecto.Query select clause, aliased to the
original field name.
Functions
Generates a SQL fragment for accessing a translated field in an Ecto.Query.
The generated SQL fragment can be coupled with the rest of the functions and operators
provided by Ecto.Query and Ecto.Query.API.
Arguments
moduleis theEcto.Schemamodule that usesLocalize.Translate. Validated at compile time.translatableis either a query binding (such asa) for whole-record access, or a field access expression (such asa.title) for a specific translatable field.localeis either a single locale (atom or string) or a list of locales acting as a fallback chain. May be a literal, a variable, or a runtime expression.
Returns
A fragment/1 AST suitable for use in Ecto.Query clauses. The fragment evaluates to
the translated value with fallback to the base column, or NULL when no translation
exists for the requested locales.
Safety
This macro emits errors when used with untranslatable schema modules or fields. Errors are emitted during compilation so invalid queries fail before they can run.
Examples
Assuming the Article schema defined in Structured translations:
# Return all articles that have a Spanish translation
from a in Article, where: not is_nil(translated(Article, a, :es))
#=> SELECT a0."id", a0."title", a0."body", a0."translations"
#=> FROM "articles" AS a0
#=> WHERE (NOT (NULLIF((a0."translations"->'es'),'null') IS NULL))
# Query items with a certain translated value
from a in Article, where: translated(Article, a.title, :fr) == "Elixir"
#=> SELECT a0."id", a0."title", a0."body", a0."translations"
#=> FROM "articles" AS a0
#=> WHERE (COALESCE(a0."translations"->$1->>$2, a0."title") = 'Elixir')
# Query items using a case insensitive comparison
from a in Article, where: ilike(translated(Article, a.body, :es), "%elixir%")
#=> SELECT a0."id", a0."title", a0."body", a0."translations"
#=> FROM "articles" AS a0
#=> WHERE (COALESCE(a0."translations"->$1->>$2, a0."body") ILIKE '%elixir%')Structured translations vs free-form translations
Localize.Translate.QueryBuilder works with both structured translations and free-form
translations.
When using structured translations, the translations are saved as an embedded schema.
This means that the locale keys will be always present even if there is no
translation for that locale. In the database we have a NULL value (nil in
Elixir).
# If MyApp.Article uses structured translations
from a in Article, where: not is_nil(translated(Article, a, :es))
#=> SELECT a0."id", a0."title", a0."body", a0."translations"
#=> FROM "articles" AS a0
#=> WHERE (NOT (NULLIF((a0."translations"->'es'),'null') IS NULL))More complex queries
The translated/3 macro can also be used with relations and joined schemas. For more
complex examples take a look at the QueryBuilder tests (the file is located in
test/localize/translate/query_builder_test.exs).
Generates a SQL fragment for use in an Ecto.Query select clause, aliased to the
original field name.
Wraps translated/3 so the returned column carries the base column's name. Ecto can
therefore load the translated value directly into the schema struct without further
processing or conversion.
Arguments
moduleis theEcto.Schemamodule that usesLocalize.Translate.translatableis a field access expression such asa.title. The base field name is used as the column alias.localeis either a single locale or a list of locales acting as a fallback chain.
Returns
A fragment/1 AST that selects the translated value aliased to the original field
name. See translated/3 for the underlying SQL produced.