Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 175 lines (151 sloc) 7.127 kB
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
1 require 'yaml'
4f9592f @josevalim Remove Hash methods from I18n::Backend::Helpers and add them to core …
josevalim authored
2 require 'i18n/core_ext/hash'
e270d72 @svenfuchs Surpress warnings in Base#interpolate when too many interpolation arg…
authored
3 require 'i18n/core_ext/kernel/surpress_warnings'
4
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
5 module I18n
6 module Backend
f44faeb @svenfuchs make I18n::Backend::Base a module instead of a class. should make it …
authored
7 module Base
524d8e9 @josevalim Allow anyone to easily include the transliterate method.
josevalim authored
8 include I18n::Backend::Transliterator
678fb6a @svenfuchs * extract helper methods from Base backend class to a Helper module f…
authored
9
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
10 # Accepts a list of paths to translation files. Loads translations from
11 # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
12 # for details.
13 def load_translations(*filenames)
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
14 filenames = I18n.load_path.flatten if filenames.empty?
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
15 filenames.each { |filename| load_file(filename) }
16 end
17
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
18 # This method receives a locale, a data hash and options for storing translations.
19 # Should be implemented
9341d3f @svenfuchs make sure the ActiveRecord backend works with custom scope separators
authored
20 def store_translations(locale, data, options = {})
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
21 raise NotImplementedError
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
22 end
23
2af8ec5 @svenfuchs fix merge with thedarkone's fast backend refactoring, re-relaxing a f…
authored
24 def translate(locale, key, options = {})
9550939 @thedarkone Port optimized #translate from Fast backend.
thedarkone authored
25 raise InvalidLocale.new(locale) unless locale
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
26 entry = key && lookup(locale, key, options[:scope], options)
677ca6a @josevalim More code refactoring. Moved deep_merge to backend helpers and create…
josevalim authored
27
2af8ec5 @svenfuchs fix merge with thedarkone's fast backend refactoring, re-relaxing a f…
authored
28 if options.empty?
677ca6a @josevalim More code refactoring. Moved deep_merge to backend helpers and create…
josevalim authored
29 entry = resolve(locale, key, entry, options)
9550939 @thedarkone Port optimized #translate from Fast backend.
thedarkone authored
30 else
677ca6a @josevalim More code refactoring. Moved deep_merge to backend helpers and create…
josevalim authored
31 count, default = options.values_at(:count, :default)
b30d11a @josevalim Remove all references to the deprecated syntax.
josevalim authored
32 values = options.except(*RESERVED_KEYS)
9d12bfa @josevalim Ensure metadata works with frozen values, closes #18.
josevalim authored
33 entry = entry.nil? && default ?
34 default(locale, key, default, options) : resolve(locale, key, entry, options)
2af8ec5 @svenfuchs fix merge with thedarkone's fast backend refactoring, re-relaxing a f…
authored
35 end
36
9d12bfa @josevalim Ensure metadata works with frozen values, closes #18.
josevalim authored
37 raise(I18n::MissingTranslationData.new(locale, key, options)) if entry.nil?
38 entry = entry.dup if entry.is_a?(String)
39
40 entry = pluralize(locale, entry, count) if count
a889482 @josevalim Won't raise errors if %{} is in the string but no interpolation value…
josevalim authored
41 entry = interpolate(locale, entry, values) if values
9d12bfa @josevalim Ensure metadata works with frozen values, closes #18.
josevalim authored
42 entry
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
43 end
44
25f79f9 @svenfuchs refactor localize by extracting localize_format! and raise MissingTra…
authored
45 # Acts the same as +strftime+, but uses a localized version of the
46 # format string. Takes a key from the date/time formats translations as
47 # a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
48 def localize(locale, object, format = :default, options = {})
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
49 raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
50
51 if Symbol === format
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
52 key = format
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
53 type = object.respond_to?(:sec) ? 'time' : 'date'
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
54 options = options.merge(:raise => true, :object => object, :locale => locale)
55 format = I18n.t(:"#{type}.formats.#{key}", options)
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
56 end
57
2ca72dc @svenfuchs fix tests for 1.9.1 and 1.8.7
authored
58 # format = resolve(locale, object, format, options)
77ba8e2 @fcheung Speed up localize: only translate components that are actually in the…
fcheung authored
59 format = format.to_s.gsub(/%[aAbBp]/) do |match|
60 case match
61 when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday]
62 when '%A' then I18n.t(:"date.day_names", :locale => locale, :format => format)[object.wday]
63 when '%b' then I18n.t(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon]
64 when '%B' then I18n.t(:"date.month_names", :locale => locale, :format => format)[object.mon]
65 when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format) if object.respond_to? :hour
66 end
67 end
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
68
69 object.strftime(format)
70 end
71
72 # Returns an array of locales for which translations are available
98bd63c @svenfuchs change available_translations to ignore a reserved meta translation k…
authored
73 # ignoring the reserved translation meta data key :i18n.
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
74 def available_locales
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
75 raise NotImplementedError
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
76 end
77
78 def reload!
1006d7e @josevalim Do not show the deprecation message too frequently.
josevalim authored
79 @skip_syntax_deprecation = false
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
80 end
81
82 protected
f7f7dc1 @josevalim Renamed Fast module to Memoize and changed the implementation a bit. …
josevalim authored
83
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
84 # The method which actually looks up for the translation in the store.
9054984 @svenfuchs pass full options hash to #lookup. gives extending modules more control.
authored
85 def lookup(locale, key, scope = [], options = {})
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
86 raise NotImplementedError
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
87 end
88
89 # Evaluates defaults.
90 # If given subject is an Array, it walks the array and returns the
91 # first translation that can be resolved. Otherwise it tries to resolve
92 # the translation directly.
93 def default(locale, object, subject, options = {})
94 options = options.dup.reject { |key, value| key == :default }
95 case subject
96 when Array
7807570 @josevalim Get rid of Ruby 1.9 warnings.
josevalim authored
97 subject.each do |item|
98 result = resolve(locale, object, item, options) and return result
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
99 end and nil
100 else
101 resolve(locale, object, subject, options)
102 end
103 end
104
105 # Resolves a translation.
106 # If the given subject is a Symbol, it will be translated with the
107 # given options. If it is a Proc then it will be evaluated. All other
108 # subjects will be returned directly.
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
109 def resolve(locale, object, subject, options = {})
7aacf1d @svenfuchs add a :resolve option so users can opt out of resolving lambdas and k…
authored
110 return subject if options[:resolve] == false
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
111 case subject
112 when Symbol
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
113 I18n.translate(subject, options.merge(:locale => locale, :raise => true))
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
114 when Proc
4a8cd9f @lucasmncastro Fix localization when the Proc gets the object and extra options.
lucasmncastro authored
115 date_or_time = options.delete(:object) || object
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
116 resolve(locale, object, subject.call(date_or_time, options))
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
117 else
118 subject
119 end
120 rescue MissingTranslationData
121 nil
122 end
123
124 # Picks a translation from an array according to English pluralization
125 # rules. It will pick the first translation if count is not equal to 1
126 # and the second translation if it is equal to 1. Other backends can
127 # implement more flexible or complex pluralization rules.
128 def pluralize(locale, entry, count)
a889482 @josevalim Won't raise errors if %{} is in the string but no interpolation value…
josevalim authored
129 return entry unless entry.is_a?(Hash) && count
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
130
131 key = :zero if count == 0 && entry.has_key?(:zero)
132 key ||= count == 1 ? :one : :other
133 raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
134 entry[key]
135 end
136
137 # Interpolates values into a given string.
138 #
8894ee5 @josevalim Deprecate {{}} as interpolation syntax.
josevalim authored
139 # interpolate "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X'
140 # # => "file test.txt opened by %{user}"
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
141 def interpolate(locale, string, values = {})
93dbfb6 @svenfuchs un-monkey-patch and refactor string interpolation
authored
142 if string.is_a?(::String) && !values.empty?
143 I18n.interpolate(string, values)
b30d11a @josevalim Remove all references to the deprecated syntax.
josevalim authored
144 else
93dbfb6 @svenfuchs un-monkey-patch and refactor string interpolation
authored
145 string
b30d11a @josevalim Remove all references to the deprecated syntax.
josevalim authored
146 end
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
147 end
d08fac7 @svenfuchs fix escape sequence for old interpolation variables. always raised a …
authored
148
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
149 # Loads a single translations file by delegating to #load_rb or
150 # #load_yml depending on the file extension and directly merges the
151 # data to the existing translations. Raises I18n::UnknownFileType
152 # for all other file extensions.
153 def load_file(filename)
154 type = File.extname(filename).tr('.', '').downcase
48f873c @tenderlove add true to respond_to? for 1.9.3 compatibility
tenderlove authored
155 raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true)
408499c @josevalim Make tests pass on both 1.8.7 and 1.9.2. Raise an error if locale fil…
josevalim authored
156 data = send(:"load_#{type}", filename)
157 raise InvalidLocaleData.new(filename) unless data.is_a?(Hash)
8805e01 @josevalim Ensure it works with empty locale files.
josevalim authored
158 data.each { |locale, d| store_translations(locale, d || {}) }
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
159 end
160
161 # Loads a plain Ruby translations file. eval'ing the file must yield
162 # a Hash containing translation data with locales as toplevel keys.
163 def load_rb(filename)
164 eval(IO.read(filename), binding, filename)
165 end
166
167 # Loads a YAML translations file. The data must have locales as
168 # toplevel keys.
169 def load_yml(filename)
408499c @josevalim Make tests pass on both 1.8.7 and 1.9.2. Raise an error if locale fil…
josevalim authored
170 YAML.load_file(filename)
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
171 end
172 end
173 end
f44faeb @svenfuchs make I18n::Backend::Base a module instead of a class. should make it …
authored
174 end
Something went wrong with that request. Please try again.