Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 190 lines (165 sloc) 7.871 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'
3a582ed @carlosantoniodasilva Fix typo in filename: surpress => suppress
carlosantoniodasilva authored
3 require 'i18n/core_ext/kernel/suppress_warnings'
e270d72 @svenfuchs Surpress warnings in Base#interpolate when too many interpolation arg…
authored
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)
7ff8f9a @krekoten Make sure file names are always flattened
krekoten authored
14 filenames = I18n.load_path if filenames.empty?
15 filenames.flatten.each { |filename| load_file(filename) }
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
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
9d85541 @svenfuchs Switch from I18n::MissingTranslationData (which is an Exception) to I…
authored
37 throw(:exception, I18n::MissingTranslation.new(locale, key, options)) if entry.nil?
9d12bfa @josevalim Ensure metadata works with frozen values, closes #18.
josevalim authored
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
2e12adb @ndbroadbent Move exists? implementation to Backend::Base, and Backend::Chain. Add…
ndbroadbent authored
45 def exists?(locale, key)
46 lookup(locale, key) != nil
47 end
48
25f79f9 @svenfuchs refactor localize by extracting localize_format! and raise MissingTra…
authored
49 # Acts the same as +strftime+, but uses a localized version of the
50 # format string. Takes a key from the date/time formats translations as
51 # a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
52 def localize(locale, object, format = :default, options = {})
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
53 raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
54
55 if Symbol === format
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
56 key = format
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
57 type = object.respond_to?(:sec) ? 'time' : 'date'
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
58 options = options.merge(:raise => true, :object => object, :locale => locale)
59 format = I18n.t(:"#{type}.formats.#{key}", options)
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
60 end
61
2ca72dc @svenfuchs fix tests for 1.9.1 and 1.8.7
authored
62 # format = resolve(locale, object, format, options)
5e4e30c @miry Return meridian in correct case.
miry authored
63 format = format.to_s.gsub(/%[aAbBpP]/) do |match|
77ba8e2 @fcheung Speed up localize: only translate components that are actually in the…
fcheung authored
64 case match
65 when '%a' then I18n.t(:"date.abbr_day_names", :locale => locale, :format => format)[object.wday]
66 when '%A' then I18n.t(:"date.day_names", :locale => locale, :format => format)[object.wday]
67 when '%b' then I18n.t(:"date.abbr_month_names", :locale => locale, :format => format)[object.mon]
68 when '%B' then I18n.t(:"date.month_names", :locale => locale, :format => format)[object.mon]
5e4e30c @miry Return meridian in correct case.
miry authored
69 when '%p' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).upcase if object.respond_to? :hour
70 when '%P' then I18n.t(:"time.#{object.hour < 12 ? :am : :pm}", :locale => locale, :format => format).downcase if object.respond_to? :hour
77ba8e2 @fcheung Speed up localize: only translate components that are actually in the…
fcheung authored
71 end
72 end
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
73
74 object.strftime(format)
75 end
76
77 # Returns an array of locales for which translations are available
98bd63c @svenfuchs change available_translations to ignore a reserved meta translation k…
authored
78 # ignoring the reserved translation meta data key :i18n.
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
79 def available_locales
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
80 raise NotImplementedError
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
81 end
82
83 def reload!
84 end
85
86 protected
f7f7dc1 @josevalim Renamed Fast module to Memoize and changed the implementation a bit. …
josevalim authored
87
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
88 # 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
89 def lookup(locale, key, scope = [], options = {})
67cb16c @josevalim Base backend now provides a raw implementation, showing the minimum a…
josevalim authored
90 raise NotImplementedError
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
91 end
92
93 # Evaluates defaults.
94 # If given subject is an Array, it walks the array and returns the
95 # first translation that can be resolved. Otherwise it tries to resolve
96 # the translation directly.
97 def default(locale, object, subject, options = {})
98 options = options.dup.reject { |key, value| key == :default }
99 case subject
100 when Array
7807570 @josevalim Get rid of Ruby 1.9 warnings.
josevalim authored
101 subject.each do |item|
102 result = resolve(locale, object, item, options) and return result
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
103 end and nil
104 else
105 resolve(locale, object, subject, options)
106 end
107 end
108
109 # Resolves a translation.
110 # If the given subject is a Symbol, it will be translated with the
111 # given options. If it is a Proc then it will be evaluated. All other
112 # subjects will be returned directly.
20bf4fd @josevalim Fix the interpolation issue by adding :object to reserved keys. The i…
josevalim authored
113 def resolve(locale, object, subject, options = {})
7aacf1d @svenfuchs add a :resolve option so users can opt out of resolving lambdas and k…
authored
114 return subject if options[:resolve] == false
4028976 @svenfuchs enable I18n.t to use throw as an error handling strategy and use it i…
authored
115 result = catch(:exception) do
116 case subject
117 when Symbol
118 I18n.translate(subject, options.merge(:locale => locale, :throw => true))
119 when Proc
120 date_or_time = options.delete(:object) || object
121 resolve(locale, object, subject.call(date_or_time, options))
122 else
123 subject
124 end
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
125 end
9d85541 @svenfuchs Switch from I18n::MissingTranslationData (which is an Exception) to I…
authored
126 result unless result.is_a?(MissingTranslation)
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
127 end
128
2b93dc9 @tigrish Update documentation for the `pluralize` method
tigrish authored
129 # Picks a translation from a pluralized mnemonic subkey according to English
130 # pluralization rules :
131 # - It will pick the :one subkey if count is equal to 1.
132 # - It will pick the :other subkey otherwise.
133 # - It will pick the :zero subkey in the special case where count is
134 # equal to 0 and there is a :zero subkey present. This behaviour is
135 # not stand with regards to the CLDR pluralization rules.
136 # Other backends can implement more flexible or complex pluralization rules.
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
137 def pluralize(locale, entry, count)
a889482 @josevalim Won't raise errors if %{} is in the string but no interpolation value…
josevalim authored
138 return entry unless entry.is_a?(Hash) && count
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
139
140 key = :zero if count == 0 && entry.has_key?(:zero)
141 key ||= count == 1 ? :one : :other
142 raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
143 entry[key]
144 end
145
146 # Interpolates values into a given string.
147 #
8894ee5 @josevalim Deprecate {{}} as interpolation syntax.
josevalim authored
148 # interpolate "file %{file} opened by %%{user}", :file => 'test.txt', :user => 'Mr. X'
149 # # => "file test.txt opened by %{user}"
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
150 def interpolate(locale, string, values = {})
93dbfb6 @svenfuchs un-monkey-patch and refactor string interpolation
authored
151 if string.is_a?(::String) && !values.empty?
152 I18n.interpolate(string, values)
b30d11a @josevalim Remove all references to the deprecated syntax.
josevalim authored
153 else
93dbfb6 @svenfuchs un-monkey-patch and refactor string interpolation
authored
154 string
b30d11a @josevalim Remove all references to the deprecated syntax.
josevalim authored
155 end
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
156 end
d08fac7 @svenfuchs fix escape sequence for old interpolation variables. always raised a …
authored
157
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
158 # Loads a single translations file by delegating to #load_rb or
159 # #load_yml depending on the file extension and directly merges the
160 # data to the existing translations. Raises I18n::UnknownFileType
161 # for all other file extensions.
162 def load_file(filename)
163 type = File.extname(filename).tr('.', '').downcase
48f873c @tenderlove add true to respond_to? for 1.9.3 compatibility
tenderlove authored
164 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
165 data = send(:"load_#{type}", filename)
4de4ed4 @knapo Fix #180 - make exception message more helpful on YAML syntax error
knapo authored
166 unless data.is_a?(Hash)
167 raise InvalidLocaleData.new(filename, 'expects it to return a hash, but does not')
168 end
8805e01 @josevalim Ensure it works with empty locale files.
josevalim authored
169 data.each { |locale, d| store_translations(locale, d || {}) }
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
170 end
171
172 # Loads a plain Ruby translations file. eval'ing the file must yield
173 # a Hash containing translation data with locales as toplevel keys.
174 def load_rb(filename)
175 eval(IO.read(filename), binding, filename)
176 end
177
178 # Loads a YAML translations file. The data must have locales as
179 # toplevel keys.
180 def load_yml(filename)
44eba80 @tigrish - Empty YAML files still raise InvalidLocaleData under 1.9.3
tigrish authored
181 begin
182 YAML.load_file(filename)
ceb40d4 @knapo Proper catching invalid yml syntax across all ruby versions
knapo authored
183 rescue TypeError, ScriptError, StandardError => e
4de4ed4 @knapo Fix #180 - make exception message more helpful on YAML syntax error
knapo authored
184 raise InvalidLocaleData.new(filename, e.inspect)
44eba80 @tigrish - Empty YAML files still raise InvalidLocaleData under 1.9.3
tigrish authored
185 end
32ddc80 @svenfuchs move Simple backend implementation to a Base backend class and extend…
authored
186 end
187 end
188 end
f44faeb @svenfuchs make I18n::Backend::Base a module instead of a class. should make it …
authored
189 end
Something went wrong with that request. Please try again.