Module: I18n::Backend::Inflector

Defined in:
lib/i18n-inflector/backend.rb

Overview

This module contains methods that add tokenized inflection support to internal I18n classes. It is intened to be included in the Simple backend module so that it will patch translate method in order to interpolate additional inflection tokens present in translations. Usually you don't have to know what's here to use it.

Constant Summary collapse

InflectorCfg =

Shortcut to configuration module.

I18n::Inflector::Config

Instance Method Summary collapse

Instance Method Details

#inflection_subtree(locale) ⇒ Hash? (protected)

Note:

Under some very rare conditions this method may be called while translation data is loading. It must always return when translations are not initialized. Otherwise it will cause loops and someone in Poland will eat a kittien!

Gives an access to the internal structure containing configuration data for the given locale.

Parameters:

  • locale (Symbol)

    the locale to use

Returns:

  • (Hash, nil)

    part of the translation data that reflects inflections for the given locale or nil if translations are not initialized


164
165
166
167
# File 'lib/i18n-inflector/backend.rb', line 164

def inflection_subtree(locale)
  return nil unless initialized?
  lookup(locale, :"i18n.inflections", [], :fallback => true, :raise => :false)
end

#inflectorObject

This accessor allows to reach API methods of the inflector object associated with this class.


30
31
32
33
# File 'lib/i18n-inflector/backend.rb', line 30

def inflector
  inflector_try_init
  @inflector
end

#inflector_try_init (protected)

This method returns an undefined value.

Initializes internal hashes used for keeping inflections configuration.


129
130
131
132
133
134
# File 'lib/i18n-inflector/backend.rb', line 129

def inflector_try_init
  unless (defined?(@inflector) && !@inflector.nil?)
    @inflector = I18n::Inflector::API.new
    init_translations unless initialized?
  end
end

#init_translationsBoolean (protected)

Note:

It calls I18n::Backend::Simple#init_translations

Takes care of loading inflection tokens for all languages (locales) that have them defined.

Returns:

  • (Boolean)

    true if everything went fine

Raises:


146
147
148
149
150
151
# File 'lib/i18n-inflector/backend.rb', line 146

def init_translations
  unless (defined?(@inflector) && !@inflector.nil?)
    @inflector = I18n::Inflector::API.new
  end
  super
end

#load_inflection_tokens(locale) ⇒ I18n::Inflector::InflectionData? (protected) #load_inflection_tokens(locale, subtree) ⇒ I18n::Inflector::InflectionData? (protected)

Uses the inflections subtree and creates internal mappings to resolve kinds assigned to inflection tokens and aliases, including defaults.

Overloads:

  • #load_inflection_tokens(locale) ⇒ I18n::Inflector::InflectionData?
    Note:

    That version calls the #inflection_subtree method to obtain internal translations data.

    Loads inflection tokens for the given locale using internal hash of stored translations. Requires translations to be initialized.

    Parameters:

    • locale (Symbol)

      the locale to use and work for

    Returns:

  • #load_inflection_tokens(locale, subtree) ⇒ I18n::Inflector::InflectionData?

    Loads inflection tokens for the given locale using datthe given in an argument

    Parameters:

    • locale (Symbol)

      the locale to use and work for

    • subtree (Hash)

      the tree (in a form of nested Hashes) containing inflection tokens to scan

    Returns:

Returns:

Raises:


247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/i18n-inflector/backend.rb', line 247

def load_inflection_tokens(locale, subtree=nil)
  inflections_tree = subtree || inflection_subtree(locale)
  return nil if (inflections_tree.nil? || inflections_tree.empty?)
  inflections_tree = deep_symbolize(inflections_tree)

  idb         = I18n::Inflector::InflectionData.new(locale)
  idb_strict  = I18n::Inflector::InflectionData_Strict.new(locale)

  return nil if (idb.nil? || idb_strict.nil?)

  inflections = prepare_inflections(locale, inflections_tree, idb, idb_strict)

  # add inflection tokens and kinds to internal database
  inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|

    # validate token's kind
    if (kind.to_s.empty? || InflectorCfg::Reserved::Kinds.invalid?(orig_kind, :DB))
      raise I18n::BadInflectionKind.new(locale, orig_kind)
    end

    tokens.each_pair do |token, description|

      # test for duplicate
      if subdb.has_token?(token, strict_kind)
        raise I18n::DuplicatedInflectionToken.new(locale, token, orig_kind,
                                                  subdb.get_kind(token, strict_kind))
      end

      # validate token's name
      if InflectorCfg::Reserved::Tokens.invalid?(token, :DB)
        raise I18n::BadInflectionToken.new(locale, token, orig_kind)
      end

      # validate token's description
      if description.nil?
        raise I18n::BadInflectionToken.new(locale, token, orig_kind, description)
      elsif description.to_s[0..0] == InflectorCfg::Markers::ALIAS
        next
      end

      # skip default token for later processing
      next if token == :default

      subdb.add_token(token, kind, description)
    end
  end

  # handle aliases
  inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
    tokens.each_pair do |token, description|
      next if token == :default
      next if description.to_s[0..0] != InflectorCfg::Markers::ALIAS
      real_token = shorten_inflection_alias(token, orig_kind, locale, inflections_tree)
      subdb.add_alias(token, real_token, kind) unless real_token.nil?
    end
  end

  # handle default tokens
  inflections.each do |orig_kind, kind, strict_kind, subdb, tokens|
    next unless tokens.has_key?(:default)
    if subdb.has_default_token?(kind)
      raise I18n::DuplicatedInflectionToken.new(locale, :default, kind, orig_kind)
    end
    orig_target = tokens[:default]
    target = orig_target.to_s
    target = target[1..-1] if target[0..0] == InflectorCfg::Markers::ALIAS
    if target.empty?
      raise I18n::BadInflectionToken.new(locale, token, orig_kind, orig_target)
    end
    target = subdb.get_true_token(target.to_sym, kind)
    if target.nil?
      raise I18n::BadInflectionAlias.new(locale, :default, orig_kind, orig_target)
    end
    subdb.set_default_token(kind, target)
  end

  [idb, idb_strict]
end

#reload!Boolean

Note:

It calls I18n::Backend::Simple#reload!

Cleans up internal hashes containg kinds, inflections and aliases.

Returns:

  • (Boolean)

    the result of calling ancestor's method


40
41
42
43
# File 'lib/i18n-inflector/backend.rb', line 40

def reload!
  @inflector = nil
  super
end

#shorten_inflection_alias(token, kind, locale) ⇒ Symbol (protected) #shorten_inflection_alias(token, kind, locale, subtree) ⇒ Symbol (protected)

Note:

It does take care of aliasing loops (max traverses is set to 64).

Resolves an alias for a token if the given token is an alias.

Overloads:

  • #shorten_inflection_alias(token, kind, locale) ⇒ Symbol
    Note:

    This version uses internal subtree and needs the translation data to be initialized.

    Resolves an alias for a token if the given token is an alias for the given locale and kind.

    Parameters:

    • token (Symbol)

      the token name

    • kind (Symbol)

      the kind of the given token

    • locale (Symbol)

      the locale to use

    Returns:

    • (Symbol)

      the true token that alias points to if the given token is an alias or the given token if it is a true token

  • #shorten_inflection_alias(token, kind, locale, subtree) ⇒ Symbol

    Resolves an alias for a token if the given token is an alias for the given locale and kind.

    Parameters:

    • token (Symbol)

      the token name

    • kind (Symbol)

      the kind of the given token

    • locale (Symbol)

      the locale to use

    • subtree (Hash)

      the tree (in a form of nested Hashes) containing inflection tokens to scan

    Returns:

    • (Symbol)

      the true token that alias points to if the given token is an alias or the given token if it is a true token

Returns:

  • (Symbol)

    the true token that alias points to if the given token is an alias or the given token if it is a true token

Raises:


192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/i18n-inflector/backend.rb', line 192

def shorten_inflection_alias(token, kind, locale, subtree=nil, count=0)
  count += 1
  return nil if count > 64

  inflections_tree = subtree || inflection_subtree(locale)
  return nil if (inflections_tree.nil? || inflections_tree.empty?)

  kind_subtree  = inflections_tree[kind]
  value         = kind_subtree[token].to_s

  if value[0..0] != InflectorCfg::Markers::ALIAS
    if kind_subtree.has_key?(token)
      return token
    else
      raise I18n::BadInflectionToken.new(locale, token, kind)
    end
  else
    orig_token = token
    token = value[1..-1]

    if InflectorCfg::Reserved::Tokens.invalid?(token, :DB)
      raise I18n::BadInflectionToken.new(locale, token, kind)
    end

    token = token.to_sym
    if kind_subtree[token].nil?
      raise BadInflectionAlias.new(locale, orig_token, kind, token)
    else
      shorten_inflection_alias(token, kind, locale, inflections_tree, count)
    end
  end

end

#store_translations(locale, data, options = {}) ⇒ Hash

Note:

If inflections are changed it will regenerate proper internal structures.

Stores translations in memory.

Returns:

  • (Hash)

    the stored translations

Raises:


108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/i18n-inflector/backend.rb', line 108

def store_translations(locale, data, options = {})
  r = super
  inflector_try_init
  if data.respond_to?(:has_key?)
    subdata = (data[:i18n] || data['i18n'])
    unless subdata.nil?
      subdata = (subdata[:inflections] || subdata['inflections'])
      unless subdata.nil?
        db, db_strict = load_inflection_tokens(locale, r[:i18n][:inflections])
        @inflector.add_database(db, db_strict)
      end
    end
  end
  r
end

#translate(locale, key, options = {}) ⇒ String

Note:

The given options along with a translated string and the given locale are passed to I18n::Backend::Simple#translate and then the result is processed by Inflector::API#interpolate

Translates given key taking care of inflections.

Parameters:

  • locale (Symbol)

    locale

  • key (Symbol, String)

    translation key

  • options (Hash) (defaults to: {})

    a set of options to pass to the translation routines.

Returns:

  • (String)

    the translated string with interpolated patterns

See Also:


58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/i18n-inflector/backend.rb', line 58

def translate(locale, key, options = {})
  inflector_try_init

  # take care about cache-awareness
  cached = options.has_key?(:inflector_cache_aware) ?
           options[:inflector_cache_aware] : @inflector.options.cache_aware

  if cached
    interpolate_options = options
    @inflector.options.prepare_options!(options)
  else
    interpolate_options = options.dup
    @inflector.options.clean_for_translate!(options)
  end

  # translate string using original translate
  translated_string = super

  # generate a pattern from key-based inflection object
  if (translated_string.is_a?(Hash) && key.to_s[0..0] == InflectorCfg::Markers::STRICT_KIND)
    translated_string = @inflector.key_to_pattern(translated_string)
  end

  # interpolate string
  begin

    @inflector.options.prepare_options!(interpolate_options) unless cached
    @inflector.interpolate(translated_string, locale, interpolate_options)

  # complete the exception by adding translation key
  rescue I18n::InflectionException => e

    e.key = key
    raise

  end

end