c23f7c13194ef77cb3393873503272f6a997fa36
[packages/precise/mcollective.git] / lib / mcollective / vendor / i18n / lib / i18n / backend / flatten.rb
1 module I18n
2   module Backend
3     # This module contains several helpers to assist flattening translations.
4     # You may want to flatten translations for:
5     #
6     #   1) speed up lookups, as in the Memoize backend;
7     #   2) In case you want to store translations in a data store, as in ActiveRecord backend;
8     #
9     # You can check both backends above for some examples.
10     # This module also keeps all links in a hash so they can be properly resolved when flattened.
11     module Flatten
12       SEPARATOR_ESCAPE_CHAR = "\001"
13       FLATTEN_SEPARATOR = "."
14
15       # normalize_keys the flatten way. This method is significantly faster
16       # and creates way less objects than the one at I18n.normalize_keys.
17       # It also handles escaping the translation keys.
18       def self.normalize_flat_keys(locale, key, scope, separator)
19         keys = [scope, key].flatten.compact
20         separator ||= I18n.default_separator
21
22         if separator != FLATTEN_SEPARATOR
23           keys.map! do |k|
24             k.to_s.tr("#{FLATTEN_SEPARATOR}#{separator}",
25               "#{SEPARATOR_ESCAPE_CHAR}#{FLATTEN_SEPARATOR}")
26           end
27         end
28
29         keys.join(".")
30       end
31
32       # Receives a string and escape the default separator.
33       def self.escape_default_separator(key) #:nodoc:
34         key.to_s.tr(FLATTEN_SEPARATOR, SEPARATOR_ESCAPE_CHAR)
35       end
36
37       # Shortcut to I18n::Backend::Flatten.normalize_flat_keys
38       # and then resolve_links.
39       def normalize_flat_keys(locale, key, scope, separator)
40         key = I18n::Backend::Flatten.normalize_flat_keys(locale, key, scope, separator)
41         resolve_link(locale, key)
42       end
43
44       # Store flattened links.
45       def links
46         @links ||= Hash.new { |h,k| h[k] = {} }
47       end
48
49       # Flatten keys for nested Hashes by chaining up keys:
50       #
51       #   >> { "a" => { "b" => { "c" => "d", "e" => "f" }, "g" => "h" }, "i" => "j"}.wind
52       #   => { "a.b.c" => "d", "a.b.e" => "f", "a.g" => "h", "i" => "j" }
53       #
54       def flatten_keys(hash, escape, prev_key=nil, &block)
55         hash.each_pair do |key, value|
56           key = escape_default_separator(key) if escape
57           curr_key = [prev_key, key].compact.join(FLATTEN_SEPARATOR).to_sym
58           yield curr_key, value
59           flatten_keys(value, escape, curr_key, &block) if value.is_a?(Hash)
60         end
61       end
62
63       # Receives a hash of translations (where the key is a locale and
64       # the value is another hash) and return a hash with all
65       # translations flattened.
66       #
67       # Nested hashes are included in the flattened hash just if subtree
68       # is true and Symbols are automatically stored as links.
69       def flatten_translations(locale, data, escape, subtree)
70         hash = {}
71         flatten_keys(data, escape) do |key, value|
72           if value.is_a?(Hash)
73             hash[key] = value if subtree
74           else
75             store_link(locale, key, value) if value.is_a?(Symbol)
76             hash[key] = value
77           end
78         end
79         hash
80       end
81
82       protected
83
84         def store_link(locale, key, link)
85           links[locale.to_sym][key.to_s] = link.to_s
86         end
87
88         def resolve_link(locale, key)
89           key, locale = key.to_s, locale.to_sym
90           links = self.links[locale]
91
92           if links.key?(key)
93             links[key]
94           elsif link = find_link(locale, key)
95             store_link(locale, key, key.gsub(*link))
96           else
97             key
98           end
99         end
100
101         def find_link(locale, key) #:nodoc:
102           links[locale].each do |from, to|
103             return [from, to] if key[0, from.length] == from
104           end && nil
105         end
106
107         def escape_default_separator(key) #:nodoc:
108           I18n::Backend::Flatten.escape_default_separator(key)
109         end
110
111     end
112   end
113 end