Module: Mobility

Defined in:
lib/mobility.rb,
lib/mobility/util.rb,
lib/mobility/plugin.rb,
lib/mobility/backend.rb,
lib/mobility/plugins.rb,
lib/mobility/version.rb,
lib/mobility/backends.rb,
lib/mobility/pluggable.rb,
lib/mobility/plugins/arel.rb,
lib/mobility/translations.rb,
lib/mobility/backends/hash.rb,
lib/mobility/backends/json.rb,
lib/mobility/backends/null.rb,
lib/mobility/plugins/cache.rb,
lib/mobility/plugins/dirty.rb,
lib/mobility/plugins/query.rb,
lib/mobility/backends/jsonb.rb,
lib/mobility/backends/table.rb,
lib/mobility/plugins/reader.rb,
lib/mobility/plugins/sequel.rb,
lib/mobility/plugins/writer.rb,
lib/mobility/backends/column.rb,
lib/mobility/backends/hstore.rb,
lib/mobility/backends/sequel.rb,
lib/mobility/plugins/backend.rb,
lib/mobility/plugins/default.rb,
lib/mobility/plugins/presence.rb,
lib/mobility/plugins/fallbacks.rb,
lib/mobility/backends/container.rb,
lib/mobility/backends/key_value.rb,
lib/mobility/plugins/arel/nodes.rb,
lib/mobility/plugins/attributes.rb,
lib/mobility/backends/serialized.rb,
lib/mobility/backends/hash_valued.rb,
lib/mobility/backends/sequel/json.rb,
lib/mobility/plugins/active_model.rb,
lib/mobility/plugins/sequel/cache.rb,
lib/mobility/plugins/sequel/dirty.rb,
lib/mobility/plugins/sequel/query.rb,
lib/mobility/backends/sequel/jsonb.rb,
lib/mobility/backends/sequel/table.rb,
lib/mobility/plugins/active_record.rb,
lib/mobility/backends/active_record.rb,
lib/mobility/backends/sequel/column.rb,
lib/mobility/backends/sequel/hstore.rb,
lib/mobility/plugins/backend_reader.rb,
lib/mobility/plugins/sequel/backend.rb,
lib/mobility/backends/sequel/pg_hash.rb,
lib/mobility/plugins/locale_accessors.rb,
lib/mobility/backends/sequel/container.rb,
lib/mobility/backends/sequel/key_value.rb,
lib/mobility/plugins/arel/nodes/pg_ops.rb,
lib/mobility/plugins/attribute_methods.rb,
lib/mobility/backends/sequel/serialized.rb,
lib/mobility/plugins/active_model/cache.rb,
lib/mobility/plugins/active_model/dirty.rb,
lib/mobility/backends/active_record/json.rb,
lib/mobility/plugins/active_record/cache.rb,
lib/mobility/plugins/active_record/dirty.rb,
lib/mobility/plugins/active_record/query.rb,
lib/mobility/backends/active_record/jsonb.rb,
lib/mobility/backends/active_record/table.rb,
lib/mobility/backends/active_record/column.rb,
lib/mobility/backends/active_record/hstore.rb,
lib/mobility/plugins/active_record/backend.rb,
lib/mobility/plugins/fallthrough_accessors.rb,
lib/mobility/backends/active_record/pg_hash.rb,
lib/mobility/backends/active_record/container.rb,
lib/mobility/backends/active_record/key_value.rb,
lib/mobility/backends/active_record/serialized.rb,
lib/rails/generators/mobility/install_generator.rb,
lib/rails/generators/mobility/translations_generator.rb,
lib/rails/generators/mobility/backend_generators/base.rb,
lib/mobility/plugins/active_record/uniqueness_validation.rb,
lib/rails/generators/mobility/backend_generators/table_backend.rb,
lib/rails/generators/mobility/backend_generators/column_backend.rb,
lib/rails/generators/mobility/active_record_migration_compatibility.rb

Overview

Mobility is a gem for storing and retrieving localized data through attributes on a class.

There are two ways to translate attributes on a class, both of which are variations on the same basic mechanism. The first and most common way is to extend the `Mobility` module, which adds a class method translates. Translated attributes can then be defined like this:

class Post
  extend Mobility
  translates :title, backend: :key_value
end

Behind the scenes, translates simply creates an instance of Mobility.translations_class, passes it whatever arguments are passed to translates, and includes the instance (which is a module) into the class.

So the above example is equivalent to:

class Post
  Mobility.translations_class.new(:title, backend: :key_value)
end

`Mobility.translations_class` is a subclass of `Mobility::Translations` created when `Mobility.configure` is called to configure Mobility. In fact, when you call `Mobility.configure`, it is the subclass of `Mobility::Translations` which is passed to the block as `config` (or as `self` if no argument is passed to the block). Plugins and plugin configuration is all applied to the same `Mobility.translations_class`.

There is another way to use Mobility, which is to create your own subclass or subclasses of Mobility::Translations and include them explicitly, without using translates.

For example:

class Translations < Mobility::Translations
  plugins do
    backend :key_value
    # ...
  end
end

class Post
  include Translations.new(:title)
end

This usage might be handy if, for example, you want to have more complex configuration, where some models use some plugins while others do not. Since `Mobility::Translations` is a class like any other, you can subclass it and define plugins specifically on the subclass which are not present on its parent:

class TranslationsWithFallbacks < Translations
  plugins do
    fallbacks
  end
end

class Comment
  include TranslationsWithFallbacks.new(:author)
end

In this case, Comment uses TranslationsWithFallbacks and thus has the fallbacks plugin, whereas Post uses Translations which does not have that plugin enabled.

Defined Under Namespace

Modules: ActiveRecordMigrationCompatibility, Backend, BackendGenerators, Backends, Plugin, Plugins, Util, VERSION Classes: Error, InstallGenerator, InvalidLocale, NotImplementedError, Pluggable, Translations, TranslationsGenerator

Locale Accessors collapse

Class Method Summary collapse

Class Method Details

.available_localesArray<Symbol>

Note:

The special case for Rails is necessary due to the fact that Rails may load the model before setting I18n.available_locales. If we simply default to I18n.available_locales, we may define many more methods (in LocaleAccessors) than is really necessary.

Returns available locales. Defaults to I18n.available_locales, but will use Rails.application.config.i18n.available_locales if Rails is loaded and config is non-nil.

Returns:

  • (Array<Symbol>)

    Available locales


226
227
228
229
230
231
232
# File 'lib/mobility.rb', line 226

def available_locales
  if defined?(Rails) && Rails.respond_to?(:application) && Rails.application
    Rails.application.config.i18n.available_locales&.map(&:to_sym) || I18n.available_locales
  else
    I18n.available_locales
  end
end

.configure {|Mobility::Translations| ... } ⇒ Object

Configure Mobility


114
115
116
117
118
119
120
121
# File 'lib/mobility.rb', line 114

def configure(&block)
  translates_with(Class.new(Translations)) unless @translations_class
  if block.arity == 0
    translations_class.instance_exec(&block)
  else
    yield translations_class
  end
end

.default_backendSymbol, Class

Alias to default backend defined on *translations_class+.

Returns:

  • (Symbol, Class)

108
109
110
# File 'lib/mobility.rb', line 108

def default_backend
  translations_class.defaults[:backend]&.first
end

.enforce_available_locales!(locale) ⇒ Object

Raises InvalidLocale exception if the locale passed in is present but not available.

Parameters:

  • locale (String, Symbol)

Raises:


214
215
216
# File 'lib/mobility.rb', line 214

def enforce_available_locales!(locale)
  raise Mobility::InvalidLocale.new(locale) unless (locale.nil? || available_locales.include?(locale.to_sym))
end

.extended(model_class) ⇒ Object


93
94
95
96
97
# File 'lib/mobility.rb', line 93

def extended(model_class)
  def model_class.translates(*args, **options)
    include Mobility.translations_class.new(*args, **options)
  end
end

.gem_versionObject


4
5
6
# File 'lib/mobility/version.rb', line 4

def self.gem_version
  Gem::Version.new VERSION::STRING
end

.included(model_class) ⇒ Object

Extends model with this class so that include Mobility is equivalent to extend Mobility (but extend is preferred).

Parameters:

  • model_class

102
103
104
# File 'lib/mobility.rb', line 102

def included(model_class)
  model_class.extend self
end

.localeSymbol

Returns Mobility locale.

Returns:

  • (Symbol)

    Mobility locale


140
141
142
# File 'lib/mobility.rb', line 140

def locale
  read_locale || I18n.locale
end

.locale=(locale) ⇒ Symbol

Sets Mobility locale

Parameters:

  • locale (Symbol)

    Locale to set

Returns:

  • (Symbol)

    Locale

Raises:

  • (InvalidLocale)

    if locale is nil or not in Mobility.available_locales (if I18n.enforce_available_locales is true)


149
150
151
# File 'lib/mobility.rb', line 149

def locale=(locale)
  set_locale(locale)
end

.normalize_locale(locale = Mobility.locale) ⇒ String Also known as: normalized_locale

Return normalized locale

Examples:

Mobility.normalize_locale(:ja)
#=> "ja"
Mobility.normalize_locale("pt-BR")
#=> "pt_br"

Parameters:

  • locale (String, Symbol) (defaults to: Mobility.locale)

Returns:

  • (String)

    Normalized locale


180
181
182
# File 'lib/mobility.rb', line 180

def normalize_locale(locale = Mobility.locale)
  "#{locale.to_s.downcase.tr("-", "_")}"
end

.normalize_locale_accessor(attribute, locale = Mobility.locale) ⇒ String

Return normalized locale accessor name

Examples:

Mobility.normalize_locale_accessor(:foo, :ja)
#=> "foo_ja"
Mobility.normalize_locale_accessor(:bar, "pt-BR")
#=> "bar_pt_br"

Parameters:

  • attribute (String, Symbol)
  • locale (String, Symbol) (defaults to: Mobility.locale)

Returns:

  • (String)

    Normalized locale accessor name

Raises:

  • (ArgumentError)

    if generated accessor has an invalid format


195
196
197
198
199
200
201
# File 'lib/mobility.rb', line 195

def normalize_locale_accessor(attribute, locale = Mobility.locale)
  "#{attribute}_#{normalize_locale(locale)}".tap do |accessor|
    unless CALL_COMPILABLE_REGEXP.match(accessor)
      raise ArgumentError, "#{accessor.inspect} is not a valid accessor"
    end
  end
end

.reset_translations_classObject


134
135
136
# File 'lib/mobility.rb', line 134

def reset_translations_class
  @translations_class = nil
end

.storageRequestStore

Returns Request store.

Returns:

  • (RequestStore)

    Request store


168
169
170
# File 'lib/mobility.rb', line 168

def storage
  RequestStore.store
end

.translates_with(pluggable) ⇒ Object

Raises:

  • (ArgumentError)

123
124
125
126
# File 'lib/mobility.rb', line 123

def translates_with(pluggable)
  raise ArgumentError, "translations class must be a subclass of Module." unless Module === pluggable
  @translations_class = pluggable
end

.translations_classObject


128
129
130
131
132
# File 'lib/mobility.rb', line 128

def translations_class
  @translations_class ||
    raise(Error, "Mobility has not been configured. "\
          "Configure with Mobility.configure, or assign a translations class with Mobility.translates_with(<class>)")
end

.validate_locale!(locale) ⇒ Object

Check that a non-nil locale is valid. (Does not actually parse locale to check its format.)

Raises:


206
207
208
209
# File 'lib/mobility.rb', line 206

def validate_locale!(locale)
  raise Mobility::InvalidLocale.new(locale) unless Symbol === locale
  enforce_available_locales!(locale) if I18n.enforce_available_locales
end

.with_locale(locale) {|Symbol| ... } ⇒ Object

Sets Mobility locale around block

Parameters:

  • locale (Symbol)

    Locale to set in block

Yields:

  • (Symbol)

    Locale


156
157
158
159
160
161
162
163
164
# File 'lib/mobility.rb', line 156

def with_locale(locale)
  previous_locale = read_locale
  begin
    set_locale(locale)
    yield(locale)
  ensure
    set_locale(previous_locale)
  end
end