mathieuprog

mathieuprog

I18n Helpers - ease the use of embedded translations in Ecto Schemas

Hello everyone :wave:

I’ve been learning Elixir for a few months now and just published my first Hex package :tada:
Any feedback is welcome.

This library might be relevant to you if you need to store translations in the database (e.g. user-generated content), and want to store these translations in a JSON data type (as opposed to storing them in separate tables).

You can manage that by just using the Ecto’s :map field type, but the idea of this library is to provide a set of helpers to ease working with such embedded translations.

The library expects you to store a map of translations for each field. For example:

%Post{
  title: %{"en" => "The title", "fr" => "Le titre"},   
  body: %{"en" => "The content", "fr" => "Le contenu"}
}

In brief, the library helps you translating your Ecto struct and its associations for a given locale (in one call), with a fallback locale and a handler for missing translations.

post =
 Repo.all(Post)
 |> Repo.preload(:category)
 |> Repo.preload(:comments)
 |> Translator.translate("fr", fallback_locale: "en")

assert post.translated_title == "Le titre"
assert post.category.translated_name == "La catégorie"
assert List.first(post.comments).translated_text == "Un commentaire"

As you might already understand from the example above, by “translating an Ecto struct”, it is meant extracting the texts (from the different translations’ maps) for a given locale and fallback locale, and set them in a virtual field (which is named by the field it retrieved the text from prefixed by “translated_”).

It is done recursively for the struct and all their loaded associations.

It is particularly useful if you need to use different fallback locales throughout your application as is my case, or if you need to be notified for missing translations.

This library differs from other similar libraries where:

  • translations are stored in a JSON data type (in Postgres that will be jsonb type);
  • each field has its translations map (as opposed to one big translation map for all fields);
  • there is no notion of “main” locale, all the texts are stored in the map (but you can specify a fallback locale);
  • translations for a given locale are retrieved in one call for an Ecto struct and all its associations;
  • a fallback locale and a handler for missing translations may be provided.

:v:

Most Liked

mathieuprog

mathieuprog

It would look something like:

from(
  p in Post,
  where: ilike(fragment("(?->>'en')", p.title), "%elixir%"),
  select: p
)

Thank you for the suggestion; I think indeed a helper to build Ecto queries should be part of the library :+1: It’s not my priority right now as I don’t need a search feature in my project.

However, I’m now working on view helpers to make working with form and such embedded fields easier.
These view helpers would render something like:

These fields can be generated in one line.

This will be push’ed in a few days.

Phillipp

Phillipp

It’s indeed very useful for setups where you want to keep the DB schema rather simple. How would one query the DB for e.g. a search feature? I guess it’s possible to search inside JSON using Postgres, I haven’t done that yet, though.

Maybe you could provide a helper function that assembles the correct Ecto query part?

Where Next?

Popular in Libraries Top

josevalim
Hi everyone, We would like to announce that Plataformatec is working on a new MySQL driver called MyXQL. Our goal is to eventually integ...
New
kevinlang
Hey all, We have made an Ecto3 Adapter for SQLite3, ecto_sqlite3! We have successfully on-boarded the full suite of integration tests (...
New
sasajuric
I’d like to announce a small library called boundaries. This is an experimental project which explores the idea of enforcing boundaries ...
New
praveenperera
FastRSS Parse RSS feeds very quickly: This is rust NIF built using rustler Uses the RSS rust crate to do the actual RSS parsing Speed...
New
pkrawat1
Presenting Aviacommerce, open source e-commerce platform in Elixir Aviacommerce is an open source e-commerce platform in Elixir. We at...
New
woutdp
Hi! I wanted to introduce my latest project LiveSvelte. It allows you to render Svelte inside LiveView with end-to-end reactivity. It’s ...
New
benlime
I created a new library GitHub - benvp/ex_cva: Class Variance Authority for Elixir which aims to make it very easy to define different va...
New
Crowdhailer
I have been updating a library that allows you to pipe between functions that use the erlang result tuple convention. Assuming you have...
New
josevalim
Yes, yet another parser combinator library! Most of the parser combinators in the ecosystem are either compile-time, often using AST tra...
159 18262 141
New
mplatts
With HEEX released we decided to start a components library using Tailwind CSS - check it out here: Petal Components. We also have a boi...
New

Other popular topics Top

dotdotdotPaul
Okay, I'm having a heck of a time trying to figure out how to best handle the validation of belongs_to associations in Ecto. I'm sure I'...
New
yawaramin
In the Dialyzer docs ( http://erlang.org/doc/man/dialyzer.html#requesting-or-suppressing-warnings-in-source-files ), there is a way to tu...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
rms.mrcs
Hi, I need to transform a list of numbers into a map where the keys are the indexes and the values are the original values of the list....
New
fireproofsocks
Forgive me if this is obvious, but how does one delete a database record WITHOUT selecting it first? https://hexdocs.pm/ecto/Ecto.Repo.h...
New
skosch
To my knowledge, put_in, Map.update etc. all have the one limitation of not automatically creating intermediate keys when needed (for exa...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Sub Categories:

We're in Beta

About us Mission Statement