Class: Multilocale::Dictionary

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/multilocale/dictionary.rb

Overview

One language's phrases as a flat key => value map, plus the conversion the Ruby i18n gem needs.

Multilocale stores keys flat. The i18n gem resolves t("cart.title") by splitting on dots and walking nested hashes, so a flat YAML key "cart.title": Cart is NOT found at runtime — it has to be nested on the way out and flattened again on the way in. That translation is this class.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(language, entries = {}) ⇒ Dictionary

Returns a new instance of Dictionary.



16
17
18
19
# File 'lib/multilocale/dictionary.rb', line 16

def initialize(language, entries = {})
  @language = language
  @entries = entries.sort_by { |key, _| key.to_s }.to_h
end

Instance Attribute Details

#entriesObject (readonly)

Returns the value of attribute entries.



14
15
16
# File 'lib/multilocale/dictionary.rb', line 14

def entries
  @entries
end

#languageObject (readonly)

Returns the value of attribute language.



14
15
16
# File 'lib/multilocale/dictionary.rb', line 14

def language
  @language
end

Class Method Details

.flatten(tree, prefix = nil) ⇒ Object

The inverse of #nested: what a locale file read from disk has to go through before it can be pushed back as phrase rows.



82
83
84
85
86
87
88
89
90
91
92
# File 'lib/multilocale/dictionary.rb', line 82

def self.flatten(tree, prefix = nil)
  tree.each_with_object({}) do |(key, value), flat|
    path = [prefix, key].compact.join(".")

    if value.is_a?(Hash)
      flat.merge!(flatten(value, path))
    else
      flat[path] = value
    end
  end
end

.from_phrases(phrases) ⇒ Object

{ "en" => Dictionary, "es" => Dictionary, … } from a flat list of rows.



22
23
24
25
26
# File 'lib/multilocale/dictionary.rb', line 22

def self.from_phrases(phrases)
  phrases.each_with_object({}) { |phrase, grouped|
    (grouped[phrase.language] ||= {})[phrase.key] = phrase.value
  }.map { |language, entries| [language, new(language, entries)] }.to_h
end

Instance Method Details

#[](key) ⇒ Object



28
29
30
# File 'lib/multilocale/dictionary.rb', line 28

def [](key)
  entries[key.to_s]
end

#each(&block) ⇒ Object



32
33
34
# File 'lib/multilocale/dictionary.rb', line 32

def each(&block)
  entries.each(&block)
end

#empty?Boolean

Returns:

  • (Boolean)


40
41
42
# File 'lib/multilocale/dictionary.rb', line 40

def empty?
  entries.empty?
end

#keysObject



44
45
46
# File 'lib/multilocale/dictionary.rb', line 44

def keys
  entries.keys
end

#nestedObject

Dotted keys become nested hashes, which is what i18n (and Rails) read. cart.title and cart cannot both be keys — one would have to be both a string and a hash — so that collision is reported rather than silently dropping one of them.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'lib/multilocale/dictionary.rb', line 56

def nested
  entries.each_with_object({}) do |(key, value), tree|
    path = key.to_s.split(".")
    leaf = path.pop
    node = tree

    path.each_with_index do |segment, index|
      node[segment] ||= {}
      unless node[segment].is_a?(Hash)
        raise Error, "Key collision in #{language}: #{path[0..index].join('.')} is both a value and a namespace " \
                     "(#{key})"
      end

      node = node[segment]
    end

    if node[leaf].is_a?(Hash)
      raise Error, "Key collision in #{language}: #{key} is both a value and a namespace"
    end

    node[leaf] = value
  end
end

#sizeObject



36
37
38
# File 'lib/multilocale/dictionary.rb', line 36

def size
  entries.size
end

#to_hObject



48
49
50
# File 'lib/multilocale/dictionary.rb', line 48

def to_h
  entries
end