All Projects → crbelaus → Trans

crbelaus / Trans

Licence: apache-2.0
Embedded translations for Elixir

Programming Languages

elixir
2628 projects

Projects that are alternatives of or similar to Trans

Django Intro Zh
Django 官方文档的 intro 部分的中文翻译
Stars: ✭ 141 (-17.06%)
Mutual labels:  translation
C2rust
Migrate C code to Rust
Stars: ✭ 2,111 (+1141.76%)
Mutual labels:  translation
I18n Extract
Manage localization with static analysis. 🔍
Stars: ✭ 152 (-10.59%)
Mutual labels:  translation
I18n Debug
Ever wondered which translations are being looked up by Rails, a gem, or simply your app? Wonder no more!
Stars: ✭ 143 (-15.88%)
Mutual labels:  translation
Deepl Translator
This module provides promised methods for translating text using DeepL Translator (https://www.deepl.com/translator) undocumented API.
Stars: ✭ 145 (-14.71%)
Mutual labels:  translation
Rick And Morty Chinese Subtitles
Rick and Morty 中文字幕
Stars: ✭ 150 (-11.76%)
Mutual labels:  translation
Translateapp
📝 A translations app without interruptions, copy words and translate directly, show result by top view.
Stars: ✭ 1,722 (+912.94%)
Mutual labels:  translation
Strsync
A CLI tool for localization resource management on Xcode. Built with Google Translator.
Stars: ✭ 157 (-7.65%)
Mutual labels:  translation
Swiftui Tutorials
A code example and translation project of SwiftUI. / 一个 SwiftUI 的示例、翻译的教程项目。
Stars: ✭ 1,992 (+1071.76%)
Mutual labels:  translation
Deeply
PHP client for the DeepL.com translation API (unofficial)
Stars: ✭ 152 (-10.59%)
Mutual labels:  translation
Onnxt5
Summarization, translation, sentiment-analysis, text-generation and more at blazing speed using a T5 version implemented in ONNX.
Stars: ✭ 143 (-15.88%)
Mutual labels:  translation
Matsuri translation
夏色祭工坊烤推机
Stars: ✭ 144 (-15.29%)
Mutual labels:  translation
Plai Cn
Programming Languages: Application and Interpretation
Stars: ✭ 151 (-11.18%)
Mutual labels:  translation
Icopy Site.github.io
icopy.site github mirror
Stars: ✭ 142 (-16.47%)
Mutual labels:  translation
Ritabot
Real-Time Interchangeable Translating Assistant, an open-source free translation Bot for Discord.
Stars: ✭ 146 (-14.12%)
Mutual labels:  translation
Translateproject
Linux中国翻译项目
Stars: ✭ 1,847 (+986.47%)
Mutual labels:  translation
Pytorch Tutorials Kr
🇰🇷PyTorch에서 제공하는 튜토리얼의 한국어 번역을 위한 저장소입니다. (Translate PyTorch tutorials in Korean🇰🇷)
Stars: ✭ 148 (-12.94%)
Mutual labels:  translation
Bitextor
Bitextor generates translation memories from multilingual websites.
Stars: ✭ 168 (-1.18%)
Mutual labels:  translation
Ectranslation
Android Studio Plugin,Translate English to Chinese. Android Studio 翻译插件,可以将英文翻译为中文.
Stars: ✭ 1,842 (+983.53%)
Mutual labels:  translation
Rolisteam
Rolisteam is a virtual tabletop. It helps you to manage tabletop role playing games with remote friends/players. It provides many features to share maps, pictures, dice roller, manage background music and much more. The main git repository is available here: [https://invent.kde.org/kde/rolisteam].
Stars: ✭ 151 (-11.18%)
Mutual labels:  translation

Trans

CircleCI Hex.pm

Trans provides a way to manage and query translations embedded into schemas and removes the necessity of maintaining extra tables only for translation storage. It is inspired by the great hstore translate gem for Ruby.

Trans is published on hex.pm and the documentation is also available online. Source code is available in this same repository under the Apache2 License.

On April 17th, 2017, Trans was featured in HackerNoon

Optional Requirements

Having Ecto SQL and Postgrex in your application will allow you to use the Trans.QueryBuilder component to generate database queries based on translated data. You can still use the Trans.Translator component without those dependencies though.

  • Ecto SQL 3.0 or higher
  • PostgreSQL 9.4 or higher (since Trans leverages the JSONB datatype)

Support for MySQL JSON type (introduced in MySQL 5.7) will come also, but right now it is not yet implemented at the database adapter level.

Why Trans?

The traditional approach to content internationalization consists on using an additional table for each translatable schema. This table works only as a storage for the original schema translations. For example, we may have a posts and a posts_translations tables.

This approach has a few disadvantages:

  • It complicates the database schema because it creates extra tables that are coupled to the "main" ones.
  • It makes migrations and schemas more complicated, since we always have to keep the two tables in sync.
  • It requires constant JOINs in order to filter or fetch records along with their translations.

The approach used by Trans is based on modern RDBMSs support for unstructured datatypes. Instead of storing the translations in a different table, each translatable schema has an extra column that contains all of its translations. This approach drastically reduces the number of required JOINs when filtering or fetching records.

Trans is lightweight and modularized. The Trans module provides metadata that is used by the Trans.Translator and Trans.QueryBuilder modules, which implement the main functionality of this library.

Making a schema translatable

Every translatable schema needs a field in which the translations are stored. This field is known as the translation container.

The first step consists on adding a new column to the schema's table:

defmodule MyApp.Repo.Migrations.AddTranslationsToArticles do
  use Ecto.Migration

  def change do
    alter table(:articles) do
      add :translations, :map
    end
  end
end

The schema must be also updated, so the new column can be automatically mapped by Ecto.

defmodule Article do
  use Ecto.Schema

  schema "articles" do
    field :title, :string     # our previous fields...
    field :body, :string      # our previous fields...
    field :translations, :map # this is our translation container
  end
end

Then we must use Trans from our schema module to indicate which fields will be translated.

defmodule Article do
  use Ecto.Schema
  use Trans, translates: [:title, :body]

  schema "articles" do
    field :title, :string
    field :body, :string
    field :translations, :map
  end
end

Storing translations

Translations are stored as a map of maps in the translation container of our schema. For example:

iex> changeset = Article.changeset(%Article{}, %{
...>   title: "How to Write a Spelling Corrector",
...>   body: "A wonderful article by Peter Norvig",
...>   translations: %{
...>     "es" => %{
...>       title: "Cómo escribir un corrector ortográfico",
...>       body: "Un artículo maravilloso de Peter Norvig"
...>     },
...>     "fr" => %{
...>        title: "Comment écrire un correcteur orthographique",
...>        body: "Un merveilleux article de Peter Norvig"
...>      }
...>   }
...> })

iex> article = Repo.insert!(changeset)

Filtering queries by translations

We may want to fetch articles that are translated into a certain language. To do this we use the Trans.QueryBuilder.translated/3 macro, which generates the required SQL fragment for us.

iex> Repo.all(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 ((a0."translations"->"es") IS NULL))

We can also get more specific and fetch only those articles for which their Spanish title matches "Elixir".

iex> Repo.all(from a in Article,
...>   where: translated(Article, a.title, :es) == "Elixir")
# SELECT a0."id", a0."title", a0."body", a0."translations"
# FROM "articles" AS a0
# WHERE ((a0."translations"->"fr"->>"title") = "Elixir")

The SQL fragment generated by the Trans.QueryBuilder.translated/3 macro is compatible with the rest of functions and macros provided by Ecto.Query and Ecto.Query.Api.

iex> Repo.all(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 ((a0."translations"->"es"->>"body") ILIKE "%elixir%")

More complex queries such as adding conditions to joined schemas can be easily generated in the same way. Take a look at the documentation and tests for more examples.

Obtaining translations from a struct

In those examples we will be referring to this article:

iex> article = %Article{
...>   title: "How to Write a Spelling Corrector",
...>   body: "A wonderful article by Peter Norvig",
...>   translations: %{
...>     "es" => %{
...>       title: "Cómo escribir un corrector ortográfico",
...>       body: "Un artículo maravilloso de Peter Norvig"
...>     },
...>     "fr" => %{
...>        title: "Comment écrire un correcteur orthographique",
...>        body: "Un merveilleux article de Peter Norvig"
...>      }
...>   }
...> }

Once we have already loaded a struct, we may use the Trans.Translator.translate/3 function to easily access a translation of a certain field. Locale can be passed as an atom or a string

iex> Trans.Translator.translate(article, :title, :es)
"Cómo escribir un corrector ortográfico"
iex> Trans.Translator.translate(article, :title, "es")
"Cómo escribir un corrector ortográfico"

or

iex> Trans.Translator.translate(article, :title, Gettext.get_locale())
"Cómo escribir un corrector ortográfico"

The Trans.Translator.translate/3 function also provides a fallback mechanism that activates when the required translation does not exist:

iex> Trans.Translator.translate(article, :title, :de)
"How to Write a Spelling Corrector"

Using a different translation container

In the previous examples we have used translations as the name of the translation container and Trans looks automatically for translations into this field.

We can also give the translation container a different name, for example article_translations:

defmodule Article do
  use Ecto.Schema
  use Trans, translates: [:title, :body], container: :article_translations

  schema "articles" do
    field :title, :string
    field :body, :string
    field :article_translations, :map
  end
end

We can call the same functions as in previous examples and both Trans.Translator and Trans.QueryBuilder will automatically look for translations in the correct field.

iex> Repo.all(from a in Article,
...>   where: not is_nil(translated(Article, a, :es)))
# SELECT a0."id", a0."title", a0."body", a0."article_translations"
# FROM "articles" AS a0
# WHERE (NOT ((a0."article_translations"->"es") IS NULL))
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].