### ActiveRecord KeyValue Backend Setup Example Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-Backends Example of the `setup` block within the ActiveRecord KeyValue backend, demonstrating how to define a `has_many` association for translations on the model. ```ruby setup do |attributes, options| association_name = options[:association_name] translations_class = options[:class_name] # ... has_many association_name, ->{ where key: attributes }, as: :translatable, class_name: translations_class.name, dependent: :destroy, inverse_of: :translatable, autosave: true # ... end ``` -------------------------------- ### KeyValue Backend Migration Source: https://context7.com/shioyama/mobility/llms.txt Example of a migration file for setting up the KeyValue backend for translations. ```ruby # Migration (auto-generated by rails generate mobility:install) # Creates mobility_string_translations and mobility_text_translations tables ``` -------------------------------- ### Mobility 0.8.x Configuration Example Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0 Illustrates the configuration structure in Mobility 0.8.x using global settings and default options. ```ruby Mobility.configure do |config| config.default_backend = :key_value config.accessor_method = :translates config.query_method = :i18n config.default_options[:fallbacks] = true config.default_options[:type] = :text end ``` -------------------------------- ### Basic Model Setup with Translates Source: https://context7.com/shioyama/mobility/llms.txt Define translated attributes on a model using the `translates` method. This example sets up string and text translations for a `Post` model, demonstrating creation, saving, and accessing translations in different locales. ```ruby class Post < ApplicationRecord extend Mobility translates :title, type: :string translates :content, type: :text end ``` ```ruby post = Post.new post.title = "Hello World" post.content = "This is the content" post.save I18n.locale = :ja post.title = "こんにちは世界" post.content = "これは内容です" post.save I18n.locale = :en post.title #=> "Hello World" I18n.locale = :ja post.title #=> "こんにちは世界" post.title? #=> true post.title = nil post.title? #=> false ``` -------------------------------- ### Configure Mobility Plugins (Table Backend) Source: https://github.com/shioyama/mobility/blob/master/README.md Example of configuring Mobility plugins, changing the default backend to :table. ```ruby Mobility.configure do # PLUGINS plugins do backend :table active_record reader writer # ... end end ``` -------------------------------- ### Enable Fallbacks Plugin Source: https://github.com/shioyama/mobility/blob/master/README.md Example of how to enable the fallbacks plugin within the Mobility plugins configuration. ```ruby plugins do # ... fallbacks locale_accessors ``` -------------------------------- ### Configure Mobility Plugins (Default KeyValue) Source: https://github.com/shioyama/mobility/blob/master/README.md Example of configuring Mobility plugins, setting the default backend to :key_value, and enabling ActiveRecord, reader, and writer plugins. ```ruby Mobility.configure do # PLUGINS plugins do backend :key_value active_record reader writer # ... end end ``` -------------------------------- ### Querying with Table Backend Source: https://context7.com/shioyama/mobility/llms.txt Example SQL query generated when searching for records using the Table backend. ```ruby # Query with table backend Post.i18n.where(title: "Hello") # SELECT "posts".* FROM "posts" # INNER JOIN "post_translations" "post_translations_en" # ON "post_translations_en"."post_id" = "posts"."id" # AND "post_translations_en"."locale" = 'en' # WHERE "post_translations_en"."title" = 'Hello' ``` -------------------------------- ### Configure Mobility Plugins with Backend Option Source: https://github.com/shioyama/mobility/blob/master/README.md Example of configuring Mobility plugins, setting the default backend to :key_value with a type option set to :string. ```ruby Mobility.configure do # PLUGINS plugins do backend :key_value, type: :string active_record reader writer # ... end end ``` -------------------------------- ### KeyValue Backend Custom Options Source: https://context7.com/shioyama/mobility/llms.txt Example of configuring custom association names and translation classes for the KeyValue backend. ```ruby class Article < ApplicationRecord extend Mobility translates :headline, backend: :key_value, type: :string, association_name: :headline_translations, # Custom association name class_name: 'CustomTranslation' # Custom translation class end ``` -------------------------------- ### Querying with Container Backend Source: https://context7.com/shioyama/mobility/llms.txt Example SQL query for searching records using the Container backend's JSONB column. ```ruby # Query on container backend Post.i18n.where(title: "Hello") # SELECT "posts".* FROM "posts" # WHERE ((("posts"."translations" -> 'en') -> 'title') = '"Hello"') ``` -------------------------------- ### Create a Custom Mobility Backend (MyHashBackend) Source: https://context7.com/shioyama/mobility/llms.txt Implement the Mobility::Backend interface to create a custom translation storage solution. This example demonstrates a simple hash-based backend. ```ruby class MyHashBackend include Mobility::Backend # Configure backend options def self.valid_keys [:storage_key] end def self.configure(options) options[:storage_key] ||= :_translations end # Setup model class (runs in model context) setup do |attributes, options| storage_key = options[:storage_key] # Add storage accessor to model attr_accessor storage_key after_initialize do send("#{storage_key}", {}) if send(storage_key).nil? end end # Read translation def read(locale, **options) storage[locale.to_s] end # Write translation def write(locale, value, **options) storage[locale.to_s] = value end # Iterate through available locales def each_locale storage.each_key { |locale| yield locale.to_sym } end private def storage model.send(options[:storage_key])[attribute] ||= {} end end ``` ```ruby # Use custom backend class Note < ApplicationRecord extend Mobility translates :content, backend: MyHashBackend, storage_key: :my_translations end note = Note.new note.content = "Hello" Mobility.with_locale(:ja) { note.content = "こんにちは" } note.my_translations #=> {"content" => {"en" => "Hello", "ja" => "こんにちは"}} ``` -------------------------------- ### Testing Mobility Backends with Shared Examples Source: https://github.com/shioyama/mobility/blob/master/README.md Demonstrates how to set up a model and extend helpers to run shared specs for Mobility backends. Ensure your model has translated attributes and the specified untranslated columns. ```ruby describe MyBackend do extend Helpers::ActiveRecord before do stub_const 'MyPost', Class.new(ActiveRecord::Base) MyPost.extend Mobility MyPost.translates :title, :content, backend: MyBackend end include_accessor_examples 'MyPost' include_querying_examples 'MyPost' # ... end ``` -------------------------------- ### Configure Mobility with Plugins and Backend Source: https://context7.com/shioyama/mobility/llms.txt Set up default plugins and the storage backend for Mobility in a Rails initializer. This example configures the key_value backend, ActiveRecord ORM plugin, and enables features like readers, writers, caching, dirty tracking, fallbacks, locale accessors, fallthrough accessors, and querying. ```ruby gem 'mobility', '~> 1.3.2' ``` ```ruby # Terminal - Generate initializer and migration for KeyValue backend # rails generate mobility:install ``` ```ruby Mobility.configure do plugins do backend :key_value active_record reader writer cache dirty fallbacks locale_accessors [:en, :ja, :fr] fallthrough_accessors query default 'Untitled' end end ``` -------------------------------- ### Define a Custom Mobility Backend Source: https://github.com/shioyama/mobility/blob/master/README.md Example of how to define and use a custom backend class with Mobility. Ensure your custom backend includes the Mobility::Backend module. ```ruby class MyBackend include Mobility::Backend # ... end class MyClass extend Mobility translates :foo, backend: MyBackend end ``` -------------------------------- ### Querying with JSONB/JSON Backend Source: https://context7.com/shioyama/mobility/llms.txt Example SQL query for searching records using the JSONB backend with attribute-specific columns. ```ruby # Querying Post.i18n.where(title: "Hello") # SELECT "posts".* FROM "posts" ``` -------------------------------- ### Define Translatable Attributes in a Model Source: https://github.com/shioyama/mobility/blob/master/README.md Use the 'translates' method with attribute names to mark them for translation. This example shows basic translation setup for 'name' and 'meaning' attributes. ```ruby class Word < ApplicationRecord extend Mobility translates :name, :meaning end ``` -------------------------------- ### Mobility Initializer Configuration (0.8) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Configure Mobility to use the 'table' backend and enable 'dirty' and 'locale_accessors' options. This setup is for Mobility version 0.8. ```ruby Mobility.configure do |config| + config.default_backend = :table - config.default_backend = :key_value config.accessor_method = :translates config.query_method = :i18n + config.default_options[:dirty] = true + config.default_options[:locale_accessors] = true # recommended end ``` -------------------------------- ### Mobility Initializer Configuration (1.0) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Configure Mobility to use the 'table' backend and enable 'dirty' and 'locale_accessors' plugins. This setup is for Mobility version 1.0. ```ruby Mobility.configure do plugins do backend :table - backend :key_value # default plugins + dirty + locale_accessors # recommended end end ``` -------------------------------- ### Configure Mobility for Sequel ORM Source: https://context7.com/shioyama/mobility/llms.txt Set up Mobility to work with the Sequel ORM by configuring the plugins. This example includes key_value backend, Sequel integration, reader, writer, cache, and query plugins. ```ruby # Configuration Mobility.configure do plugins do backend :key_value sequel # Use Sequel instead of active_record reader writer cache query end end ``` -------------------------------- ### Create Translation Table Migration Source: https://github.com/shioyama/mobility/wiki/Table-Backend This is an example of a generated migration for a 'post_translations' table. It includes columns for translated attributes, locale, foreign key, timestamps, and indices for efficient retrieval. ```ruby create_table "post_translations", force: :cascade do |t| t.string "title" t.text "content" t.string "locale", null: false t.bigint "post_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index ["locale"], name: "index_post_translations_on_locale" t.index ["post_id", "locale"], name: "index_post_translations_on_post_id_and_locale", unique: true end ``` -------------------------------- ### Mobility Backend Interface Definition Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-Backends Defines the standard interface for a Mobility backend, including `read`, `write`, `configure`, `each_locale`, and `setup` methods. Custom backends must implement these. ```ruby class MyBackend include Mobility::Backend def read(locale, **options) # ... end def write(locale, value, **options) # ... end def self.configure(options) # ... end def each_locale # iterate through each locale, yielding the locale end setup do |attributes, options| # Do something with attributes and options in context of model class. end end ``` -------------------------------- ### Container Backend Custom Column Name Source: https://context7.com/shioyama/mobility/llms.txt Example of specifying a custom column name for the JSONB translations column in the Container backend. ```ruby class Article < ApplicationRecord extend Mobility translates :title, backend: :container, column_name: :localizations end ``` -------------------------------- ### Migration for Column Backend Translations Source: https://github.com/shioyama/mobility/wiki/Column-Backend This is an example migration generated by Mobility for adding translation columns to a model. It adds columns with locale suffixes for specified attributes. ```ruby class CreatePostTitleAndContentTranslationsForMobilityColumnBackend < ActiveRecord::Migration[5.0] def change add_column :posts, :title_en, :string add_column :posts, :title_fr, :string add_column :posts, :title_ja, :string add_column :posts, :content_en, :text add_column :posts, :content_fr, :text add_column :posts, :content_ja, :text end end ``` -------------------------------- ### Query Translated Attributes with Mobility Source: https://github.com/shioyama/mobility/wiki/Column-Backend Query translated attributes using the `i18n` scope on your model. This example shows how to find a post by translated attributes. ```ruby Post.i18n.find_by(foo: "fooval", bar: "barval") #=> SELECT "posts".* FROM "posts" WHERE "posts"."foo_en" = "fooval" AND "posts"."bar_en" = "barval" LIMIT 1 ``` -------------------------------- ### Mobility Dirty Attribute Tracking Example Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Demonstrates how Mobility tracks changes to translated attributes, appending the locale suffix to the attribute name (e.g., 'title_en', 'title_ja'). This differs from Globalize's behavior. ```ruby post.changed ["title_en", "title_ja"] ``` -------------------------------- ### Create Specialized Mobility Translation Classes Source: https://context7.com/shioyama/mobility/llms.txt Define custom `Mobility::Translations` subclasses to encapsulate specific plugin configurations for different models. This allows for varied translation setups within the same application. ```ruby # Create specialized translation classes class BasicTranslations < Mobility::Translations plugins do backend :key_value active_record reader writer end end class AdvancedTranslations < BasicTranslations plugins do fallbacks dirty cache end end ``` ```ruby # Apply different configurations to models class SimplePost < ApplicationRecord include BasicTranslations.new(:title) end class ComplexPost < ApplicationRecord include AdvancedTranslations.new(:title, :content, fallbacks: { de: :en }) end # SimplePost has no fallbacks or dirty tracking # ComplexPost has all features enabled ``` -------------------------------- ### Querying Translated Attributes with i18n Scope Source: https://github.com/shioyama/mobility/wiki/Container-Backend Shows how to use the `i18n` scope to query records based on the translated attributes stored within the JSONB column. This example constructs a SQL query for filtering by title. ```ruby Post.i18n.where(title: "foo").to_sql #=> SELECT "posts".* FROM "posts" WHERE ((("posts"."translations" -> 'en') -> 'title') = "foo") ``` -------------------------------- ### Mobility 1.0 Configuration with Explicit Plugins Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0 Demonstrates the new configuration syntax in Mobility 1.0, emphasizing explicit plugin declaration and option passing. ```ruby Mobility.configure do plugins do backend :key_value, type: :text # default_options[:type] is a backend option, so it must be passed to the `backend` plugin reader # Explicitly declare readers, writer # writers, and backend_reader # backend reader (post.title_backend, etc). active_record # You must now also explicitly ask for ActiveRecord (or Sequel) query # i18n is the default scope cache # previously implicit fallbacks presence # previously implicit default # previously implicit # attribute_methods # uncomment this to get methods like `translated_attributes` end end ``` -------------------------------- ### Mobility 1.0 Configuration with Backend, Fallbacks, and Dirty Tracking Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0 Shows how to set the default backend to :key_value and enable fallbacks and dirty tracking in Mobility 1.0. ```ruby Mobility.configure do plugins do backend :key_value fallbacks dirty end end ``` -------------------------------- ### Configure KeyValue Backend with Options Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0 When configuring a backend like `:key_value`, ensure that any provided options are valid for that specific backend. Passing unrecognized options will result in an exception. ```ruby Mobility.configure do plugins do backend :key_value, foo: 'bar' end end ``` -------------------------------- ### Enable Sequel PG Hstore Extension Source: https://github.com/shioyama/mobility/wiki/Postgres-Backends-(Column-Attribute) For Sequel users, explicitly enable the `pg_hstore` extension before using hstore columns to avoid errors. ```ruby DB.extension :pg_hstore ``` -------------------------------- ### Access Translated Attributes in Different Locales Source: https://github.com/shioyama/mobility/blob/master/README.md Translated attribute values change based on the current I18n.locale. This example shows how to set and retrieve translations for English and Japanese locales. ```ruby I18n.locale = :ja word.name #=> nil word.meaning #=> nil word.name = "モビリティ" word.meaning = "(名詞):動きやすさ、可動性" word.name #=> "モビリティ" word.meaning #=> "(名詞):動きやすさ、可動性" word.save word = Word.first I18n.locale = :en word.name #=> "mobility" word.meaning #=> "(noun): quality of being changeable, adaptable or versatile" I18n.locale = :ja word.name #=> "モビリティ" word.meaning #=> "(名詞):動きやすさ、可動性" ``` -------------------------------- ### Accessing and Updating Table Backend Translations Source: https://context7.com/shioyama/mobility/llms.txt Demonstrates creating, updating, and accessing translations with the Table backend, including locale switching. ```ruby post = Post.create(title: "Hello", content: "World") Mobility.with_locale(:ja) { post.update(title: "こんにちは") } # Access translation association post.translations #=> [#] post.translations.first.locale #=> "en" post.translations.first.title #=> "Hello" ``` -------------------------------- ### Generate Mobility Initializer and Migration Source: https://github.com/shioyama/mobility/blob/master/README.md Run this Rails generator to create an initializer and a migration for the default KeyValue backend. ```ruby rails generate mobility:install ``` -------------------------------- ### Accessing KeyValue Backend Translations Source: https://context7.com/shioyama/mobility/llms.txt Shows how to access and eager load translations stored with the KeyValue backend. ```ruby post = Post.create(title: "Hello", content: "World content") # Access associated translations post.string_translations #=> [#] post.text_translations #=> [#] # Eager load to avoid N+1 queries Post.i18n.where(title: "Hello").eager_load(:string_translations) Post.i18n.where(content: "World").eager_load(:text_translations) # Both types Post.i18n.where(title: "Hello").eager_load(:string_translations, :text_translations) ``` -------------------------------- ### Enable ActiveRecord or Sequel Plugin Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-v1.0 Explicitly enable the `active_record` or `sequel` plugin within the Mobility configuration. This replaces the previous method of inspecting constants. ```ruby Mobility.configure do plugins do backend :key_value active_record # or sequel # ... end end ``` -------------------------------- ### Locale Accessors for Direct Translation Access Source: https://context7.com/shioyama/mobility/llms.txt Access translations directly using locale-suffixed methods, defined via `locale_accessors`. This allows for explicit setting and getting of translations for specified locales on a model. ```ruby class Article < ApplicationRecord extend Mobility translates :title, locale_accessors: [:en, :ja, :fr] end article = Article.new article.title_en = "English Title" article.title_ja = "日本語タイトル" article.title_fr = "Titre Français" article.title_en #=> "English Title" article.title_ja #=> "日本語タイトル" article.title_fr #=> "Titre Français" article.title_en? #=> true article.title_de? #=> NoMethodError (not in configured locales) article.title(locale: :es) article.send(:title=, "Título", locale: :es) ``` -------------------------------- ### Configure Fallbacks in Mobility (1.0) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Set up locale fallbacks within the Mobility configuration for version 1.0. This ensures translations are available in fallback locales when the primary locale is missing. ```ruby Mobility.configure do plugins do # ... + fallbacks { en: :ja, ja: :en } # or whatever fallbacks you had in Globalize end end ``` -------------------------------- ### Enable Sequel PG JSON Extension Source: https://github.com/shioyama/mobility/wiki/Postgres-Backends-(Column-Attribute) For Sequel users, explicitly enable the `pg_json` extension before using json/jsonb columns to avoid errors. ```ruby DB.extension :pg_json ``` -------------------------------- ### Run Specs with Specific Database Source: https://github.com/shioyama/mobility/blob/master/CONTRIBUTING.md Execute the test suite against a specific database (e.g., PostgreSQL) with ActiveRecord. Ensure the database is created and migrated before running. ```ruby ORM=active_record DB=postgres bundle exec rspec ``` -------------------------------- ### Configure Sequel Plugin for Mobility Source: https://github.com/shioyama/mobility/blob/master/README.md Add the 'sequel' plugin to your Mobility configuration to enable translation support for Sequel models. This is done within the 'plugins' block. ```diff plugins do backend :key_value - active_record + sequel ``` -------------------------------- ### Use pluck, order, select on translated attributes Source: https://context7.com/shioyama/mobility/llms.txt Demonstrates basic attribute access and ordering for translated fields using Mobility's i18n scope. ```ruby Post.i18n.pluck(:title) #=> ["Hello", "World", ...] Post.i18n.order(:title) Post.i18n.select(:id, :title) ``` -------------------------------- ### Accessing and Updating Container Backend Translations Source: https://context7.com/shioyama/mobility/llms.txt Shows how to create, update, and view raw translations stored in the JSONB column with the Container backend. ```ruby post = Post.create(title: "Hello", content: "World") Mobility.with_locale(:ja) { post.update(title: "こんにちは", content: "世界") } # View raw translations column post.translations #=> {"en" => {"title" => "Hello", "content" => "World"}, # "ja" => {"title" => "こんにちは", "content" => "世界"}} ``` -------------------------------- ### Run Pure Ruby Specs Source: https://github.com/shioyama/mobility/blob/master/CONTRIBUTING.md Execute the test suite for pure Ruby specs without ORM dependencies. Ensure existing functionality is not broken before submitting changes. ```ruby bundle exec rspec ``` -------------------------------- ### Enable Query Plugin (Mobility 1.0+) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Enable the 'query' plugin in your Mobility initializer to allow querying on translated attributes. The default i18n scope can be customized by passing its name as an argument. ```diff Mobility.configure do plugins do # ... query # uses default i18n scope, or customize by passing the name of the scope as argument end end ``` -------------------------------- ### Run ActiveRecord Specs Source: https://github.com/shioyama/mobility/blob/master/CONTRIBUTING.md Execute the test suite with ActiveRecord integration. This requires setting the ORM environment variable. ```ruby ORM=active_record bundle exec rspec ``` -------------------------------- ### Table Backend Custom Options Source: https://context7.com/shioyama/mobility/llms.txt Configures custom table names, foreign keys, and association names for the Table backend. ```ruby class Article < ApplicationRecord extend Mobility translates :title, backend: :table, table_name: :article_localizations, # Custom table name foreign_key: :article_id, # Custom foreign key association_name: :localizations # Custom association name end ``` -------------------------------- ### Enable Query Plugin Source: https://github.com/shioyama/mobility/blob/master/README.md Include the `query` plugin in your `plugins` block. Ensure an ORM plugin like `active_record` is also enabled. ```ruby plugins do # ... active_record + query ``` -------------------------------- ### Define Translatable Attributes with KeyValue Backend Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-Backends Sets up translatable attributes 'title' and 'content' on a model using the default KeyValue backend. Ensure the Mobility gem is included in your application. ```ruby class Post < ApplicationRecord extend Mobility translates :title, type: :string translates :content, type: :text end ``` -------------------------------- ### Enable Dirty Tracking in Mobility (1.0) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Enable the 'dirty' plugin in the Mobility initializer for version 1.0 to track changes to translated attributes. ```ruby Mobility.configure do plugins do # ... + dirty end end ``` -------------------------------- ### Read and Write Translation via Backend Source: https://github.com/shioyama/mobility/blob/master/README.md Directly interact with the storage backend using `read` and `write` methods for a given attribute to manage translations. ```ruby word.name_backend.read(:en) #=> "mobility" word.name_backend.read(:nl) #=> "mobiliteit" word.name_backend.write(:en, "foo") word.name_backend.read(:en) #=> "foo" ``` -------------------------------- ### SQL Query for Eager Loading Text Translations Source: https://github.com/shioyama/mobility/wiki/KeyValue-Backend This SQL query demonstrates how eager loading text translations results in multiple joins to fetch post data and associated text translations efficiently. ```sql SELECT "posts"."id" AS t0_r0, "posts"."created_at" AS t0_r1, "posts"."updated_at" AS t0_r2, "text_translations_posts"."id" AS t1_r0, "text_translations_posts"."locale" AS t1_r1, "text_translations_posts"."key" AS t1_r2, "text_translations_posts"."value" AS t1_r3, "text_translations_posts"."translatable_id" AS t1_r4, "text_translations_posts"."translatable_type" AS t1_r5, "text_translations_posts"."created_at" AS t1_r6, "text_translations_posts"."updated_at" AS t1_r7 FROM "posts" LEFT OUTER JOIN "mobility_text_translations" "text_translations_posts" ON "text_translations_posts"."translatable_id" = "posts"."id" AND "text_translations_posts"."key" = 'title' AND "text_translations_posts"."translatable_type" = $1 INNER JOIN "mobility_text_translations" "Post_title_en_text_translations" ON "Post_title_en_text_translations"."key" = 'title' AND "Post_title_en_text_translations"."locale" = 'en' AND "Post_title_en_text_translations"."translatable_type" = 'Post' AND "Post_title_en_text_translations"."translatable_id" = "posts"."id" WHERE "Post_title_en_text_translations"."value" = $2 [["translatable_type", "Post"], ["value", "foo"]] ``` -------------------------------- ### Configure Post Model with Container Backend Source: https://github.com/shioyama/mobility/wiki/Container-Backend Set the default backend to :container and define the translatable attributes in your ActiveRecord model. This enables Mobility to store translations in the specified JSONB column. ```ruby class Post < ApplicationRecord extend Mobility translates :title, :content end ``` -------------------------------- ### Accessing JSONB/JSON Backend Translations Source: https://context7.com/shioyama/mobility/llms.txt Shows how to view the raw JSONB column content for translated attributes. ```ruby post = Post.create(title: "Hello") Mobility.with_locale(:ja) { post.title = "こんにちは" } post.save # View raw JSONB column post.title_translations #=> {"en" => "Hello", "ja" => "こんにちは"} ``` -------------------------------- ### Mobility.locale and Mobility.with_locale Usage Source: https://context7.com/shioyama/mobility/llms.txt Manage translations independently of `I18n.locale` using Mobility's locale settings. Demonstrates setting Mobility's locale directly and using `with_locale` for temporary changes, along with locale normalization. ```ruby I18n.locale = :en Mobility.locale #=> :en Mobility.locale = :fr Mobility.locale #=> :fr I18n.locale #=> :en (unchanged) Mobility.locale = :en Mobility.with_locale(:ja) do post = Post.new post.title = "日本語タイトル" Mobility.locale #=> :ja end Mobility.locale #=> :en (restored) Mobility.normalize_locale(:ja) #=> "ja" Mobility.normalize_locale("pt-BR") #=> "pt_br" ``` -------------------------------- ### Retrieve Translation Value Source: https://github.com/shioyama/mobility/wiki/KeyValue-Backend This pseudocode illustrates how the KeyValue backend retrieves a translation value. It looks for a translation matching the current locale and key, building one if it doesn't exist. ```ruby locale = Mobility.locale translation = mobility_string_translations.find { |t| t.key == "title" && t.locale == locale.to_s } translation ||= translations.build(locale: locale, key: "title") translation.value ``` -------------------------------- ### Generate Migration for Jsonb Columns Source: https://github.com/shioyama/mobility/wiki/Postgres-Backends-(Column-Attribute) Use this command to generate a Rails migration for adding jsonb columns to your model. Replace 'jsonb' with 'json' or 'hstore' as needed. ```bash rails generate migration AddTitleAndContentToPosts title:jsonb content:jsonb ``` -------------------------------- ### Direct Backend Access in Mobility Source: https://context7.com/shioyama/mobility/llms.txt Access the backend directly for low-level read/write operations on translations. Allows reading, writing, and iterating through locales. ```ruby class Comment < ApplicationRecord extend Mobility translates :body, type: :text end comment = Comment.create comment.body = "Hello" Mobility.with_locale(:ja) { comment.body = "こんにちは" } comment.save # Access backend directly backend = comment.body_backend #=> # # Read from specific locales backend.read(:en) #=> "Hello" backend.read(:ja) #=> "こんにちは" backend.read(:fr) #=> nil # Write to specific locale backend.write(:fr, "Bonjour") backend.read(:fr) #=> "Bonjour" # Iterate available locales backend.locales #=> [:en, :ja, :fr] backend.each { |translation| puts "#{translation.locale}: #{translation.read}" } # Check presence backend.present?(:en) #=> true backend.present?(:de) #=> false ``` -------------------------------- ### Extend Sequel Models with Mobility Source: https://context7.com/shioyama/mobility/llms.txt Apply Mobility translations to Sequel models. This shows both using `extend Mobility` and the `plugin :mobility` syntax. ```ruby # Using extend class Post < Sequel::Model extend Mobility translates :title, :content, type: :string end ``` ```ruby # Using plugin syntax class Article < Sequel::Model plugin :mobility translates :title, type: :string end ``` -------------------------------- ### Enable Dirty Tracking in Mobility (0.8) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Enable dirty tracking using default options in Mobility for version 0.8. This tracks changes to translated attributes. ```ruby Mobility.configure do |config| config.default_backend = :table config.accessor_method = :translates config.query_method = :i18n + config.default_options[:dirty] = true end ``` -------------------------------- ### Block syntax for complex Arel predicates Source: https://context7.com/shioyama/mobility/llms.txt Shows how to use a block with the i18n scope for complex Arel queries on translated attributes. ```ruby Post.i18n do title.matches("%ruby%").and(content.matches("%rails%")) end ``` -------------------------------- ### Configure Fallbacks in Mobility (0.8) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Configure locale fallbacks using default options for Mobility version 0.8. This sets the default fallback behavior for all models. ```ruby Mobility.configure do |config| config.default_backend = :table config.accessor_method = :translates config.query_method = :i18n config.default_options[:dirty] = true + config.default_options[:fallbacks] = { en: :ja, ja: :en } end ``` -------------------------------- ### Define Translated Attributes with Fallbacks Source: https://github.com/shioyama/mobility/blob/master/README.md Illustrates how to define translated attributes on a model, specifying fallback locales for specific languages. ```ruby class Word < ApplicationRecord extend Mobility translates :name, fallbacks: { de: :ja, fr: :ja } translates :meaning, fallbacks: { de: :ja, fr: :ja } end ``` -------------------------------- ### Query by Title using Table Backend Source: https://github.com/shioyama/mobility/wiki/Table-Backend Find a record by its translated title. This requires joining the translation table. ```ruby Post.i18n.find_by(title: "foo") ``` -------------------------------- ### SQL generated for Arel block format query Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Shows the SQL generated from an Arel block query, using ILIKE for case-insensitive matching on translated attribute values. ```sql SELECT "posts".* FROM "posts" ... WHERE "Post_title_en_string_translations"."value" ILIKE 'foo' AND "Post_content_en_text_translations"."value" ILIKE 'bar' ``` -------------------------------- ### Table Backend Migration Generation Source: https://context7.com/shioyama/mobility/llms.txt Command to generate a migration for the Table backend, specifying translated attributes and their types. ```ruby # Generate migration for translation table # rails generate mobility:translations post title:string content:text # Creates post_translations table with: # - title (string), content (text) columns # - locale (string), post_id (foreign key) # - unique index on [post_id, locale] ``` -------------------------------- ### Configure Backend for Translated Attribute Source: https://github.com/shioyama/mobility/blob/master/README.md Explicitly set the backend for a translated attribute using the `backend` option. Note that backend-specific options like `type` are omitted when not using the default KeyValue backend. ```ruby class Word < ApplicationRecord translates :name, backend: :table end ``` -------------------------------- ### Add Translated Columns for Posts (Column Backend) Source: https://context7.com/shioyama/mobility/llms.txt Use this migration to add locale-suffixed columns for storing translations directly in the posts table. This backend is suitable when you need direct column access for translations. ```ruby class AddTranslatedColumnsToPosts < ActiveRecord::Migration[7.0] def change add_column :posts, :title_en, :string add_column :posts, :title_ja, :string add_column :posts, :title_fr, :string end end ``` ```ruby class Post < ApplicationRecord extend Mobility translates :title, backend: :column end ``` ```ruby post = Post.create(title: "Hello") I18n.locale = :ja post.title = "こんにちは" post.save # Values stored directly in columns post.title_en #=> "Hello" post.title_ja #=> "こんにちは" # Direct column access post[:title_en] #=> "Hello" post.read_attribute(:title_ja) #=> "こんにちは" ``` -------------------------------- ### Enable Fallthrough Accessors Source: https://github.com/shioyama/mobility/blob/master/README.md Include the `fallthrough_accessors` plugin to implicitly define locale methods for any locale using `method_missing`. ```ruby plugins do # ... fallthrough_accessors ``` -------------------------------- ### Enable Dirty Tracking Plugin Source: https://github.com/shioyama/mobility/blob/master/README.md Enable the `dirty` plugin to track changes to translated attributes. Ensure an ORM plugin like `active_record` or `sequel` is also enabled. ```diff plugins do # ... active_record + dirty ``` ```ruby class Post < ApplicationRecord extend Mobility translates :title end ``` ```ruby post = Post.create(title: "Introducing Mobility") Mobility.with_locale(:ja) { post.title = "モビリティの紹介" } post.save ``` ```ruby post = Post.first post.title #=> "Introducing Mobility" post.title = "a new title" Mobility.with_locale(:ja) do post.title #=> "モビリティの紹介" post.title = "新しいタイトル" post.title #=> "新しいタイトル" end ``` ```ruby post.title_was #=> "Introducing Mobility" Mobility.locale = :ja post.title_was #=> "モビリティの紹介" post.changed ["title_en", "title_ja"] post.save ``` ```ruby post.previous_changes #=> { "title_en" => [ "Introducing Mobility", "a new title" ], "title_ja" => [ "モビリティの紹介", "新しいタイトル" ] } ``` -------------------------------- ### Enable Locale Accessors Source: https://github.com/shioyama/mobility/blob/master/README.md Include the `locale_accessors` plugin and specify the locales for which to generate accessors. ```ruby plugins do # ... locale_accessors [:en, :ja] ``` -------------------------------- ### Define Post Model with Key-Value Translation Source: https://github.com/shioyama/mobility/wiki/KeyValue-Backend Define a Post model with a text-based translated title using the key_value backend. Ensure Mobility is extended. ```ruby class Post < ApplicationRecord extend Mobility translates :title, backend: :key_value, type: :text end ``` -------------------------------- ### Querying Translated Attributes Source: https://github.com/shioyama/mobility/wiki/Postgres-Backends-(Column-Attribute) Shows how to use the `i18n` scope to query records based on translated attribute values. The generated SQL targets the correct locale. ```ruby Post.i18n.where(title: "foo").to_sql #=> SELECT "posts".* FROM "posts" WHERE (("posts"."title" -> 'en') = "foo") ``` -------------------------------- ### Update Gemfile for Mobility Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Replace the globalize gem with the mobility gem in your application's Gemfile. ```diff -gem 'globalize' +gem 'mobility' ``` -------------------------------- ### Set Mobility Locale Independently Source: https://github.com/shioyama/mobility/blob/master/README.md Demonstrates how to set and retrieve the Mobility locale, which can differ from the global I18n.locale. ```ruby I18n.locale = :en Mobility.locale #=> :en Mobility.locale = :fr Mobility.locale #=> :fr I18n.locale #=> :en ``` -------------------------------- ### Container Backend Model Definition Source: https://context7.com/shioyama/mobility/llms.txt Defines a model to use the Container backend, storing all translations in a single JSONB column. ```ruby class Post < ApplicationRecord extend Mobility translates :title, :content, backend: :container end ``` -------------------------------- ### Container Backend Migration Source: https://context7.com/shioyama/mobility/llms.txt Migration to add a JSONB column for storing translations using the Container backend. ```ruby # Migration # rails generate migration AddTranslationsToPosts translations:jsonb class AddTranslationsToPosts < ActiveRecord::Migration[7.0] def change add_column :posts, :translations, :jsonb, default: {} end end ``` -------------------------------- ### Use Mobility Locale within a Block Source: https://github.com/shioyama/mobility/blob/master/README.md Shows how to temporarily set the Mobility locale for a specific block of code using Mobility.with_locale. ```ruby Mobility.locale = :en Mobility.with_locale(:ja) do Mobility.locale #=> :ja end Mobility.locale #=> :en ``` -------------------------------- ### Configure Cache Plugin Source: https://github.com/shioyama/mobility/blob/master/README.md The `cache` plugin is included by default to store fetched localized values for faster retrieval. It can be disabled per model or for individual fetches. ```diff plugins do # ... + cache ``` ```ruby class Word < ApplicationRecord extend Mobility translates :name, cache: false end ``` ```ruby post.title(cache: false) ``` -------------------------------- ### Translation Fetching Logic Source: https://github.com/shioyama/mobility/wiki/Table-Backend This illustrates the internal logic Mobility uses to fetch a translation for the current locale. It first tries to find an existing translation and builds a new one if none is found. ```ruby locale = Mobility.locale translation = translations.find { |t| t.locale == locale.to_s } translation ||= translations.build(locale: locale) translation ``` -------------------------------- ### Accessing Mobility Backend Instances Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-Backends Retrieves the backend instance associated with a specific translated attribute on a model. Each attribute has its own backend instance. ```ruby post.title_backend #=> #<#:0x005626d7a8ea90 @model=#, @attribute="title", @association_name=:mobility_string_translations, @fallbacks=nil> ``` ```ruby post.content_backend #=> #<#:0x005626d7a5c950 @model=#, @attribute="content", @association_name=:mobility_text_translations, @fallbacks=nil> ``` -------------------------------- ### Define Sequel Model with Mobility Plugin Source: https://github.com/shioyama/mobility/blob/master/README.md Apply the 'mobility' plugin directly to a Sequel model class to enable translations. This allows you to define translatable attributes using the 'translates' method. ```ruby class Word < ::Sequel::Model plugin :mobility translates :name, :meaning end ``` -------------------------------- ### Define Translatable Attributes with Types (KeyValue Backend) Source: https://github.com/shioyama/mobility/blob/master/README.md When using the KeyValue backend, specify the data type for each translatable attribute using the 'type' option. This helps Mobility route translations to the correct tables. ```ruby class Word < ApplicationRecord extend Mobility translates :name, type: :string translates :meaning, type: :text end ``` -------------------------------- ### Defining a model with translated attributes and uniqueness validation in Ruby Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Demonstrates how to set up a model with Mobility translations and apply uniqueness validation. Ensure `validates` is called after `extend Mobility`. ```ruby class Post < ApplicationRecord extend Mobility translates :title validates :title, uniqueness: true end ``` -------------------------------- ### SQL Generated for Multi-Locale Query Source: https://github.com/shioyama/mobility/wiki/Table-Backend Shows the SQL generated for querying translated attributes across different locales. ```sql SELECT "posts".* FROM "posts" INNER JOIN "post_translations" "post_translations_ja" ON "post_translations_ja"."post_id" = "posts"."id" AND "post_translations_ja"."locale" = 'ja' INNER JOIN "post_translations" "post_translations_en" ON "post_translations_en"."post_id" = "posts"."id" AND "post_translations_en"."locale" = 'en' WHERE "post_translations_ja"."title" = 'foo' AND "post_translations_en"."title" = 'bar' ``` -------------------------------- ### SQL Generated for Single Locale Query Source: https://github.com/shioyama/mobility/wiki/Table-Backend Illustrates the SQL generated when querying a translated attribute in a single locale. ```sql SELECT "posts".* FROM "posts" INNER JOIN "post_translations" "post_translations_en" ON "post_translations_en"."post_id" = "posts"."id" AND "post_translations_en"."locale" = 'en' WHERE "post_translations_en"."title" = 'foo' ``` -------------------------------- ### SQL for Querying Translated Title (Multiple Locales) Source: https://github.com/shioyama/mobility/wiki/KeyValue-Backend The SQL generated for querying posts by translated titles in multiple locales. This involves multiple INNER JOINs, one for each locale. ```sql SELECT "posts".* FROM "posts" INNER JOIN "mobility_text_translations" "Post_title_ja_text_translations" ON "Post_title_ja_text_translations"."key" = 'title' AND "Post_title_ja_text_translations"."locale" = 'ja' AND "Post_title_ja_text_translations"."translatable_type" = 'Post' AND "Post_title_ja_text_translations"."translatable_id" = "posts"."id" INNER JOIN "mobility_text_translations" "Post_title_en_text_translations" ON "Post_title_en_text_translations"."key" = 'title' AND "Post_title_en_text_translations"."locale" = 'en' AND "Post_title_en_text_translations"."translatable_type" = 'Post' AND "Post_title_en_text_translations"."translatable_id" = "posts"."id" WHERE "Post_title_ja_text_translations"."value" = 'foo' AND "Post_title_en_text_translations"."value" = 'bar' ``` -------------------------------- ### Generated SQL for Exact Array Query Source: https://github.com/shioyama/mobility/wiki/Postgres-Backends-(Column-Attribute) This SQL demonstrates how Mobility generates a query to match an exact array-valued translation in a jsonb column. ```sql SELECT "posts".* FROM "posts" WHERE (("posts"."translations" -> 'en') -> 'title') = '["foo","bar"]' ``` -------------------------------- ### Enable locale_accessors Plugin (Mobility 1.0) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Enable the locale_accessors plugin in your Mobility initializer for Mobility version 1.0 and later. ```ruby Mobility.configure do plugins do # ... locale_accessors end end ``` -------------------------------- ### JSONB/JSON Backend Migration Source: https://context7.com/shioyama/mobility/llms.txt Migration to add JSONB columns for each translated attribute when using the JSONB/JSON backend. ```ruby # Migration - add jsonb column for each translated attribute class AddTranslatedColumnsToPosts < ActiveRecord::Migration[7.0] def change add_column :posts, :title_translations, :jsonb, default: {} add_column :posts, :content_translations, :jsonb, default: {} end end ``` -------------------------------- ### Accessing and Modifying Translations Source: https://github.com/shioyama/mobility/wiki/Container-Backend Demonstrates how to create a record, access translated attributes, modify them in different locales, and save the changes. The `translations` column will store all localized values. ```ruby post = Post.create(title: "foo") post.title #=> "foo" post.content = "bar" Mobility.with_locale(:ja) { post.title = "あああ" } post.save post = Post.first post.translations #=> {"en"=>{"title"=>"foo", "content"=>"bar"}, "ja"=>{"title"=>"あああ"}} ``` -------------------------------- ### Set Fallback Locales for a Single Read Source: https://github.com/shioyama/mobility/blob/master/README.md Demonstrates how to specify one or more fallback locales for a single attribute read operation. ```ruby Mobility.with_locale(:fr) do word.meaning = "(nf): aptitude à bouger, à se déplacer, à changer, à évoluer" end word.save Mobility.locale = :de word.meaning(fallback: false) #=> nil word.meaning(fallback: :fr) #=> "(nf): aptitude à bouger, à se déplacer, à changer, à évoluer" word.meaning(fallback: [:ja, :fr]) #=> "(名詞):動きやすさ、可動性" ``` -------------------------------- ### Fallthrough Accessors for Dynamic Locale Methods Source: https://context7.com/shioyama/mobility/llms.txt Enable dynamic locale methods for any locale without predefinition using `fallthrough_accessors: true`. This utilizes `method_missing` to handle translations for locales not explicitly configured. ```ruby class Product < ApplicationRecord extend Mobility translates :name, fallthrough_accessors: true end product = Product.new product.name_de = "Deutscher Name" product.name_de #=> "Deutscher Name" product.name_pt_br = "Nome Brasileiro" product.name_pt_br #=> "Nome Brasileiro" product.name_zh_cn = "中文名称" product.name_zh_cn #=> "中文名称" ``` -------------------------------- ### Fetch or Build Translation Source: https://github.com/shioyama/mobility/wiki/Introduction-to-Mobility-Backends Fetches an existing translation for a locale and attribute, or builds a new one if none exists. Used internally by `read`. ```ruby def translation_for(locale, _) translation = translations.find { |t| t.key == attribute && t.locale == locale.to_s } translation ||= translations.build(locale: locale, key: attribute) translation end ``` -------------------------------- ### Add Mobility Gem to Gemfile Source: https://github.com/shioyama/mobility/blob/master/README.md Add this line to your application's Gemfile to include the Mobility gem. ```ruby gem 'mobility', '~> 1.3.2' ``` -------------------------------- ### Compare Translation Locale to Default Locale (Symbol) Source: https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize Convert the translation locale to a symbol before comparing it with the default frontend locale. This is necessary because Mobility does not override the `locale` method to automatically convert the value to a symbol, unlike Globalize. ```ruby def translated_to_default_locale? persisted? && translations.any? { |t| t.locale.to_sym == Refinery::I18n.default_frontend_locale} end ```