Module: Glossync

Defined in:
lib/glossync.rb,
lib/glossync/config.rb,
lib/glossync/railtie.rb,
lib/glossync/version.rb,
lib/glossync/exceptions.rb,
lib/glossync/missing_translation_handler.rb

Overview

Include into ActiveRecords to obtain some nice I18n features

Defined Under Namespace

Modules: MissingTranslationHandler Classes: NoTranslationStore, Railtie

Constant Summary collapse

METHOD_PATTERN =

methods that match this pattern will be responded to in method_missing()

/_translated$/.freeze
DEFAULT_CONFIG =
{
  reload_backend:              false,
  write_fallback_result:       false,
  missing_translation_handler: MissingTranslationHandler::Default.new,
  base_locale:                 :en,
}.freeze
VERSION =
'0.2.4'.freeze

Class Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

If you add _translated to the end of a glossync field, call tl_key on that field automatically



74
75
76
77
78
79
80
# File 'lib/glossync.rb', line 74

def method_missing(method, *args, &block)
  if respond_to_missing?(method)
    tl(method.to_s.gsub(METHOD_PATTERN, ''))
  else
    super
  end
end

Class Attribute Details

.optionsObject (readonly)

A hash which stores all of Glossync’s global options.



29
30
31
# File 'lib/glossync/config.rb', line 29

def options
  @options
end

.tl_storeObject



21
22
23
24
25
26
27
# File 'lib/glossync.rb', line 21

def tl_store
  return @tl_store unless @tl_store.nil?

  Translation
rescue NameError
  raise(Glossync::NoTranslationStore)
end

Class Method Details

.append_features(rcvr) ⇒ Object

called when a module is included, add methods to the base class



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/glossync.rb', line 30

def append_features(rcvr)
  super

  # attr_writer for @glossync
  rcvr.define_singleton_method(:has_translations_for) do |*keys|
    @glossync =
      keys.map(&:to_sym).reject { |k| glossync.include?(k) }.map do |k|
        # overwrite the reader method for the specified key to just return
        # the translation.
        rcvr.define_method(k) do
          tl(k)
        end

        # overwrite the writer method for the specified key to update the
        # translation for the key as well as update the key
        rcvr.define_method(:"#{k}=") do |val|
          tl_update(k, val)
          defined?(super) ? super(val) : val
        end

        k
      end + glossync
  end

  # attr_reader for @glossync
  rcvr.define_singleton_method(:glossync) do
    @glossync || []
  end
end

.config(&block) ⇒ Object

If called with a block, executes the block setting the argument to Glossync, else returns the options hash



33
34
35
36
# File 'lib/glossync/config.rb', line 33

def config(&block)
  @options ||= DEFAULT_CONFIG.dup
  block_given? ? block.call(Glossync) : @options
end

Instance Method Details

#respond_to_missing?(method, include_private = false) ⇒ Boolean

Determines is a missing method name can be handled

Returns:

  • (Boolean)


83
84
85
86
87
88
89
# File 'lib/glossync.rb', line 83

def respond_to_missing?(method, include_private = false)
  (METHOD_PATTERN.match?(method) &&
    self.class
        .glossync
        .include?(method.to_s.gsub(METHOD_PATTERN, '').to_sym)) ||
    super
end

#tl(field) ⇒ String

Call I18n.translate for the key corresponding to field

Examples:

QuizAnswer.first.tl(:answer) => “True”

Parameters:

  • field

    the field to translate

Returns:

  • (String)

    the translated string



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/glossync.rb', line 114

def tl(field)
  tl = catch(:exception) do
    I18n.translate(tl_key(field), throw: true)
  end

  if tl.is_a?(I18n::MissingTranslation)
    tlr = Glossync.missing_translation_handler
                  .handle(tl, self, field, I18n.locale)

    tl_update(field, tlr) if Glossync.options[:write_fallback_result]

    tlr
  else
    tl
  end
end

#tl_key(field) ⇒ String

Creates a key for the translation of a field, suitable for I18n.t()

The key consists of the name of the model downcased, the id of the model, and the name of the field translated, joined with a ‘.’

Examples:

QuizAnswer.first.tl_key(:answer) => “quizanswer.1.answer”

Parameters:

  • field

    the field to generate a key for

Returns:

  • (String)

    a key



100
101
102
103
104
105
106
# File 'lib/glossync.rb', line 100

def tl_key(field)
  [
    self.class.name.split('::').last.downcase,
    id,
    field.to_s
  ].join('.')
end

#tl_update(field, value, locale = nil) ⇒ Boolean

Update the translation associated with a field and locale

This method creates a new Translation if no pre-existing translation is found

Parameters:

  • field

    the field to update the translation of

  • value

    the new translation

  • locale (defaults to: nil)

    the locale of the new translation, if none is specified, the default locale will be used

Returns:

  • (Boolean)

    wether or not an update was performed



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/glossync.rb', line 141

def tl_update(field, value, locale = nil)
  locale ||= I18n.locale
  tls = Glossync.tl_store

  h = { locale: locale, key: tl_key(field) }

  if tls.exists?(h)
    tl = tls.find_by(h)
    return false if tl.value == value

    tl.update(value: value)
  else
    tls.create(h.merge(value: value))
  end

  I18n.backend.reload! if Glossync.options[:reload_backend]

  true
end

#update(hash) ⇒ Object

This sticks some code in front of #update that also updates any translations that were modified



63
64
65
66
67
68
69
70
# File 'lib/glossync.rb', line 63

def update(hash)
  hash.to_h.map { |k, v| [k, v] }.to_h # really convert it to a hash
      .transform_keys(&:to_sym)
      .select { |k, _| self.class.glossync.include?(k) }
      .each { |k, v| tl_update(k, v) }

  super if defined?(super)
end