The project is in a healthy, maintained state
This gem uses PostgreSQL's JSONB datatype to store and retrieve translations for ActiveRecord models without extra columns or tables
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

>= 0
>= 0
>= 0

Runtime

 Project Readme

Awesome JSONB Translate Gem Version

This gem uses PostgreSQL's JSONB datatype and ActiveRecord models to translate model data.

  • No extra columns or tables needed to operate
  • Clean naming in the database model
  • Everything is well tested
  • Uses modern JSONB type for better performance and flexibility
  • Falls back to default locale

Features

  • v0.1.3 Fix redundant fallbacks when translation is nil

Requirements

  • I18n
  • PostgreSQL with JSONB support (9.4+)

Installation

Add this line to your application's Gemfile:

gem 'awesome_jsonb_translate'

And then execute:

$ bundle

Or install it yourself as:

$ gem install awesome_jsonb_translate

Usage

Include AwesomeJsonbTranslate in your model class.

Use translates in your models, to define the attributes, which should be translateable:

class Model < ApplicationRecord
  include AwesomeJsonbTranslate
  translates :title, :description
end

Examples of Supported Usage

Assigning and Retrieving Translations

p = Page.new(title_en: 'English title', title_de: 'Deutscher Titel')
p = Page.new(title: { en: 'English title', de: 'Deutscher Titel'})
p.title_en # => 'English title'
p.title_de # => 'Deutscher Titel'

I18n.with_locale(:en) { p.title } # => 'English title'
I18n.with_locale(:de) { p.title } # => 'Deutscher Titel'

Fallbacks

It always falls back to default locale

# Behavior with fallbacks enabled
p = Page.new(title_en: 'English title')
I18n.with_locale(:de) { p.title } # => 'English title' (falls back to English)
p.title_de # => nil

# Behavior with empty string
p = Page.new(title_en: 'English title', title_de: '')
I18n.with_locale(:de) { p.title } # => 'English title' (falls back since German is empty)
p.title_de # => ''

Assigning a Hash Directly

p = Page.new(title: { en: 'English title', de: 'Deutscher Titel' })
p.title_raw # => { 'en' => 'English title', 'de' => 'Deutscher Titel' }

Locale Accessors

p.title_en = 'Updated English title'
p.title_de = 'Aktualisierter Deutscher Titel'

Querying by Translated Value (JSONB-aware)

# Find records by current locale value
Page.find_by(title_en: 'English title')

# which transforms to
Page.where("title->>'en' = ?", 'English title') # queries current locale

# Use with other conditions
Page.find_by(title_en: 'English title', author: 'John')

# which transforms to
Page.where("title->>'en' = ?", 'English title').where(author: 'John')

Finding or Initializing Records

# Find existing record by translated attribute
Page.find_or_initialize_by(title_en: 'English title')

# Initialize new record if not found
new_page = Page.find_or_initialize_by(title_en: 'New Page', slug: 'new')
new_page.persisted? # => false

# Find with combined attributes
Page.find_or_initialize_by(title_en: 'English title', slug: 'english-title')

# Find or create records
existing = Page.find_or_create_by(title_en: 'English title')
new_record = Page.find_or_create_by(title_en: 'Brand New', slug: 'brand-new') # Creates and saves the record

Ordering Records

# Sort by translated field in current locale
Page.order("title->>'en' ASC")

Other Useful Methods

# List translated attributes
Page.translated_attributes # => [:title, :content]

# List all accessor methods
Page.translated_accessors # => [:title_en, :title_de, :content_en, :content_de]

# Check translation presence
page.translated?(:title) # => true
page.translated?(:title, :fr) # => false

# Check translation availability
page.translation_available?(:title, :en) # => true

# Get all locales that have a translation
page.available_translations(:title) # => ["en", "de"]

# Get all available locales for the record
page.available_locales # => [:en, :de]

class Page < ActiveRecord::Base
  include AwesomeJsonbTranslate
  translates :title, :content
end

Make sure that the datatype of this columns is jsonb:

class CreatePages < ActiveRecord::Migration
  def change
    create_table :pages do |t|
      t.column :title, :jsonb
      t.column :content, :jsonb
      t.timestamps
    end
  end
end

Use the model attributes per locale:

p = Page.create(title_en: "English title", title_de: "Deutscher Titel")

I18n.locale = :en
p.title # => English title

I18n.locale = :de
p.title # => Deutscher Titel

I18n.with_locale :en do
  p.title # => English title
end

The raw data is available via the suffix _raw:

p = Page.new(title: {en: 'English title', de: 'Deutscher Titel'})

p.title_raw # => {'en' => 'English title', 'de' => 'Deutscher Titel'}

Find

awesome_jsonb_translate created a find_by helper.

Page.create!(:title_en => 'English title', :title_de => 'Deutscher Titel')
Page.create!(:title_en => 'Another English title', :title_de => 'Noch ein Deutscher Titel')

Page.find_by(title_en: 'English title')  # => Find by a specific language

To Param

For generating URLs with translated slugs:

class Page < ActiveRecord::Base
  translates :title

  def to_param
    # Or use parameterize for URL-friendly slugs
    title_en.parameterize
  end
end

Limitations

awesome_jsonb_translate patches ActiveRecord, which create the limitation, that a with where chained first_or_create and first_or_create! doesn't work as expected. Here is an example, which won't work:

Page.where(title_en: 'Titre français').first_or_create!

A workaround is:

Page.find_or_create_by(title_en: 'Titre français')

Development

bundle
bin/setup
bundle exec rspec

Testing

To run the tests:

  1. Ensure PostgreSQL is installed and running
  2. Set up the test environment:
bin/setup

This script will:

  • Install required gem dependencies
  • Create the PostgreSQL test database if it doesn't exist
  1. Run the tests:
bundle exec rspec

You can also set custom database connection details with environment variables:

DB_NAME=custom_db_name DB_USER=your_username DB_PASSWORD=your_password bundle exec rspec

Troubleshooting

If you encounter issues running tests:

  1. Make sure PostgreSQL is installed and running
  2. Ensure the user has permissions to create databases
  3. Check that the database 'awesome_jsonb_translate_test' exists or can be created
  4. Run bin/setup to prepare the test environment
  5. For more detailed database errors, run with debug flag:
    DB_DEBUG=true bundle exec rspec