i18n 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of i18n might be problematic. Click here for more details.

@@ -12,7 +12,7 @@ module I18n
12
12
  RESERVED_KEYS = [:scope, :default, :separator, :resolve, :object, :fallback, :format, :cascade, :throw, :raise, :rescue_format]
13
13
  RESERVED_KEYS_PATTERN = /%\{(#{RESERVED_KEYS.join("|")})\}/
14
14
 
15
- extend Module.new {
15
+ extend(Module.new {
16
16
  # Gets I18n configuration object.
17
17
  def config
18
18
  Thread.current[:i18n_config] ||= I18n::Config.new
@@ -141,7 +141,7 @@ module I18n
141
141
  # always return the same translations/values per unique combination of argument
142
142
  # values.
143
143
  def translate(*args)
144
- options = args.last.is_a?(Hash) ? args.pop : {}
144
+ options = args.last.is_a?(Hash) ? args.pop.dup : {}
145
145
  key = args.shift
146
146
  backend = config.backend
147
147
  locale = options.delete(:locale) || config.locale
@@ -219,7 +219,7 @@ module I18n
219
219
  # I18n.transliterate("Jürgen", :locale => :en) # => "Jurgen"
220
220
  # I18n.transliterate("Jürgen", :locale => :de) # => "Juergen"
221
221
  def transliterate(*args)
222
- options = args.pop if args.last.is_a?(Hash)
222
+ options = args.pop.dup if args.last.is_a?(Hash)
223
223
  key = args.shift
224
224
  locale = options && options.delete(:locale) || config.locale
225
225
  handling = options && (options.delete(:throw) && :throw || options.delete(:raise) && :raise)
@@ -230,7 +230,8 @@ module I18n
230
230
  end
231
231
 
232
232
  # Localizes certain objects, such as dates and numbers to local formatting.
233
- def localize(object, options = {})
233
+ def localize(object, options = nil)
234
+ options = options ? options.dup : {}
234
235
  locale = options.delete(:locale) || config.locale
235
236
  format = options.delete(:format) || :default
236
237
  config.backend.localize(locale, object, format, options)
@@ -328,5 +329,5 @@ module I18n
328
329
  "(an instance of which is set to I18n.exception_handler by default)."
329
330
  exception.is_a?(MissingTranslation) ? exception.message : raise(exception)
330
331
  end
331
- }
332
+ })
332
333
  end
@@ -122,10 +122,14 @@ module I18n
122
122
  result unless result.is_a?(MissingTranslation)
123
123
  end
124
124
 
125
- # Picks a translation from an array according to English pluralization
126
- # rules. It will pick the first translation if count is not equal to 1
127
- # and the second translation if it is equal to 1. Other backends can
128
- # implement more flexible or complex pluralization rules.
125
+ # Picks a translation from a pluralized mnemonic subkey according to English
126
+ # pluralization rules :
127
+ # - It will pick the :one subkey if count is equal to 1.
128
+ # - It will pick the :other subkey otherwise.
129
+ # - It will pick the :zero subkey in the special case where count is
130
+ # equal to 0 and there is a :zero subkey present. This behaviour is
131
+ # not stand with regards to the CLDR pluralization rules.
132
+ # Other backends can implement more flexible or complex pluralization rules.
129
133
  def pluralize(locale, entry, count)
130
134
  return entry unless entry.is_a?(Hash) && count
131
135
 
@@ -155,7 +159,9 @@ module I18n
155
159
  type = File.extname(filename).tr('.', '').downcase
156
160
  raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}", true)
157
161
  data = send(:"load_#{type}", filename)
158
- raise InvalidLocaleData.new(filename) unless data.is_a?(Hash)
162
+ unless data.is_a?(Hash)
163
+ raise InvalidLocaleData.new(filename, 'expects it to return a hash, but does not')
164
+ end
159
165
  data.each { |locale, d| store_translations(locale, d || {}) }
160
166
  end
161
167
 
@@ -170,10 +176,8 @@ module I18n
170
176
  def load_yml(filename)
171
177
  begin
172
178
  YAML.load_file(filename)
173
- rescue TypeError
174
- nil
175
- rescue SyntaxError
176
- nil
179
+ rescue TypeError, ScriptError, StandardError => e
180
+ raise InvalidLocaleData.new(filename, e.inspect)
177
181
  end
178
182
  end
179
183
  end
@@ -45,8 +45,7 @@ module I18n
45
45
  options = default_options if backend == backends.last
46
46
  translation = backend.translate(locale, key, options)
47
47
  if namespace_lookup?(translation, options)
48
- namespace ||= {}
49
- namespace.merge!(translation)
48
+ namespace = translation.merge(namespace || {})
50
49
  elsif !translation.nil?
51
50
  return translation
52
51
  end
@@ -77,7 +77,7 @@ module I18n
77
77
  end
78
78
 
79
79
  def missing_key(key)
80
- "raise(MissingInterpolationArgument.new(#{key}, self))"
80
+ "raise(MissingInterpolationArgument.new(#{key}, {}, self))"
81
81
  end
82
82
 
83
83
  def reserved_key(key)
@@ -73,7 +73,7 @@ module I18n
73
73
  raise "Key-value stores cannot handle procs"
74
74
  end
75
75
 
76
- @store[key] = ActiveSupport::JSON.encode([value]) unless value.is_a?(Symbol)
76
+ @store[key] = ActiveSupport::JSON.encode(value) unless value.is_a?(Symbol)
77
77
  end
78
78
  end
79
79
 
@@ -90,7 +90,7 @@ module I18n
90
90
  def lookup(locale, key, scope = [], options = {})
91
91
  key = normalize_flat_keys(locale, key, scope, options[:separator])
92
92
  value = @store["#{locale}.#{key}"]
93
- value = ActiveSupport::JSON.decode(value)[0] if value
93
+ value = ActiveSupport::JSON.decode(value) if value
94
94
  value.is_a?(Hash) ? value.deep_symbolize_keys : value
95
95
  end
96
96
  end
@@ -67,11 +67,11 @@ module I18n
67
67
  "ů"=>"u", "Ű"=>"U", "ű"=>"u", "Ų"=>"U", "ų"=>"u", "Ŵ"=>"W", "ŵ"=>"w",
68
68
  "Ŷ"=>"Y", "ŷ"=>"y", "Ÿ"=>"Y", "Ź"=>"Z", "ź"=>"z", "Ż"=>"Z", "ż"=>"z",
69
69
  "Ž"=>"Z", "ž"=>"z"
70
- }
70
+ }.freeze
71
71
 
72
72
  def initialize(rule = nil)
73
73
  @rule = rule
74
- add DEFAULT_APPROXIMATIONS
74
+ add DEFAULT_APPROXIMATIONS.dup
75
75
  add rule if rule
76
76
  end
77
77
 
@@ -83,16 +83,19 @@ module I18n
83
83
 
84
84
  private
85
85
 
86
- def approximations
87
- @approximations ||= {}
88
- end
86
+ def approximations
87
+ @approximations ||= {}
88
+ end
89
89
 
90
- # Add transliteration rules to the approximations hash.
91
- def add(hash)
92
- hash.keys.each {|key| hash[key.to_s] = hash.delete(key).to_s}
93
- approximations.merge! hash
90
+ # Add transliteration rules to the approximations hash.
91
+ def add(hash)
92
+ hash.keys.each do |key|
93
+ utf8_key = key.to_s.dup.force_encoding('UTF-8')
94
+ hash[utf8_key] = hash.delete(key).to_s
94
95
  end
96
+ approximations.merge! hash
97
+ end
95
98
  end
96
99
  end
97
100
  end
98
- end
101
+ end
@@ -0,0 +1,10 @@
1
+ # Makes String#force_encoding working with ruby 1.8.7
2
+ unless defined?(Encoding)
3
+ require 'iconv'
4
+
5
+ class String
6
+ def force_encoding(encoding)
7
+ ::Iconv.conv('UTF-8//IGNORE', encoding.upcase, self)
8
+ end
9
+ end
10
+ end
@@ -29,9 +29,9 @@ module I18n
29
29
 
30
30
  class InvalidLocaleData < ArgumentError
31
31
  attr_reader :filename
32
- def initialize(filename)
33
- @filename = filename
34
- super "can not load translations from #{filename}, expected it to return a hash, but does not"
32
+ def initialize(filename, exception_message)
33
+ @filename, @exception_message = filename, exception_message
34
+ super "can not load translations from #{filename}: #{exception_message}"
35
35
  end
36
36
  end
37
37
 
@@ -81,10 +81,10 @@ module I18n
81
81
  end
82
82
 
83
83
  class MissingInterpolationArgument < ArgumentError
84
- attr_reader :values, :string
85
- def initialize(values, string)
86
- @values, @string = values, string
87
- super "missing interpolation argument in #{string.inspect} (#{values.inspect} given)"
84
+ attr_reader :key, :values, :string
85
+ def initialize(key, values, string)
86
+ @key, @values, @string = key, values, string
87
+ super "missing interpolation argument #{key.inspect} in #{string.inspect} (#{values.inspect} given)"
88
88
  end
89
89
  end
90
90
 
@@ -21,7 +21,7 @@ module I18n
21
21
  '%'
22
22
  else
23
23
  key = ($1 || $2).to_sym
24
- value = values.key?(key) ? values[key] : raise(MissingInterpolationArgument.new(values, string))
24
+ value = values.key?(key) ? values[key] : raise(MissingInterpolationArgument.new(key, values, string))
25
25
  value = value.call(values) if value.respond_to?(:call)
26
26
  $3 ? sprintf("%#{$3}", value) : value
27
27
  end
@@ -44,6 +44,13 @@ module I18n
44
44
  assert_nothing_raised { I18n.l(@date, :format => '%x') }
45
45
  end
46
46
 
47
+ test "localize Date: does not modify the options hash" do
48
+ options = { :format => '%b', :locale => :de }
49
+ assert_equal 'Mar', I18n.l(@date, options)
50
+ assert_equal({ :format => '%b', :locale => :de }, options)
51
+ assert_nothing_raised { I18n.l(@date, options.freeze) }
52
+ end
53
+
47
54
  test "localize Date: given nil it raises I18n::ArgumentError" do
48
55
  assert_raise(I18n::ArgumentError) { I18n.l(nil) }
49
56
  end
@@ -27,13 +27,13 @@ module I18n
27
27
 
28
28
  test "localize Date: given a format that resolves to a Proc it calls the Proc with the object" do
29
29
  setup_time_proc_translations
30
- date = ::Date.new(2008, 3, 1, 6)
30
+ date = ::Date.new(2008, 3, 1)
31
31
  assert_equal '[Sat, 01 Mar 2008, {}]', I18n.l(date, :format => :proc, :locale => :ru)
32
32
  end
33
33
 
34
34
  test "localize Date: given a format that resolves to a Proc it calls the Proc with the object and extra options" do
35
35
  setup_time_proc_translations
36
- date = ::Date.new(2008, 3, 1, 6)
36
+ date = ::Date.new(2008, 3, 1)
37
37
  assert_equal '[Sat, 01 Mar 2008, {:foo=>"foo"}]', I18n.l(date, :format => :proc, :foo => 'foo', :locale => :ru)
38
38
  end
39
39
 
@@ -41,6 +41,13 @@ module I18n
41
41
  assert_nothing_raised { I18n.t(:foo, :locale => :xx) }
42
42
  end
43
43
 
44
+ test "lookup: does not modify the options hash" do
45
+ options = {}
46
+ assert_equal "a", I18n.t(:string, options)
47
+ assert_equal({}, options)
48
+ assert_nothing_raised { I18n.t(:string, options.freeze) }
49
+ end
50
+
44
51
  test "lookup: given an array of keys it translates all of them" do
45
52
  assert_equal %w(bar baz), I18n.t([:bar, :baz], :scope => [:foo])
46
53
  end
@@ -1,3 +1,3 @@
1
1
  module I18n
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.2"
3
3
  end
@@ -3,10 +3,10 @@ require 'test_helper'
3
3
  class I18nBackendChainTest < Test::Unit::TestCase
4
4
  def setup
5
5
  @first = backend(:en => {
6
- :foo => 'Foo', :formats => { :short => 'short' }, :plural_1 => { :one => '%{count}' }
6
+ :foo => 'Foo', :formats => { :short => 'short' }, :plural_1 => { :one => '%{count}' }, :dates => {:a => "A"}
7
7
  })
8
8
  @second = backend(:en => {
9
- :bar => 'Bar', :formats => { :long => 'long' }, :plural_2 => { :one => 'one' }
9
+ :bar => 'Bar', :formats => { :long => 'long' }, :plural_2 => { :one => 'one' }, :dates => {:a => "B", :b => "B"}
10
10
  })
11
11
  @chain = I18n.backend = I18n::Backend::Chain.new(@first, @second)
12
12
  end
@@ -42,6 +42,10 @@ class I18nBackendChainTest < Test::Unit::TestCase
42
42
  assert_equal({ :short => 'short', :long => 'long' }, I18n.t(:formats))
43
43
  end
44
44
 
45
+ test "namespace lookup collects results from all backends and does not overwrite" do
46
+ assert_equal({ :a => "A", :b => "B" }, I18n.t(:dates))
47
+ end
48
+
45
49
  test "namespace lookup with only the first backend returning a result" do
46
50
  assert_equal({ :one => '%{count}' }, I18n.t(:plural_1))
47
51
  end
@@ -1,5 +1,6 @@
1
- # :coding: utf-8
1
+ # encoding: utf-8
2
2
  require 'test_helper'
3
+ require 'i18n/core_ext/string/encoding'
3
4
 
4
5
  class I18nBackendTransliterator < Test::Unit::TestCase
5
6
  def setup
@@ -78,4 +79,8 @@ class I18nBackendTransliterator < Test::Unit::TestCase
78
79
  assert_not_equal "ue", transliterator.transliterate(char)
79
80
  end
80
81
 
82
+ test "DEFAULT_APPROXIMATIONS is frozen to prevent concurrency issues" do
83
+ assert I18n::Backend::Transliterator::HashTransliterator::DEFAULT_APPROXIMATIONS.frozen?
84
+ end
85
+
81
86
  end
@@ -54,14 +54,14 @@ class I18nExceptionsTest < Test::Unit::TestCase
54
54
  test "MissingInterpolationArgument stores key and string" do
55
55
  assert_raise(I18n::MissingInterpolationArgument) { force_missing_interpolation_argument }
56
56
  force_missing_interpolation_argument do |exception|
57
- # assert_equal :bar, exception.key
57
+ assert_equal :bar, exception.key
58
58
  assert_equal "%{bar}", exception.string
59
59
  end
60
60
  end
61
61
 
62
62
  test "MissingInterpolationArgument message contains the missing and given arguments" do
63
63
  force_missing_interpolation_argument do |exception|
64
- assert_equal 'missing interpolation argument in "%{bar}" ({:baz=>"baz"} given)', exception.message
64
+ assert_equal 'missing interpolation argument :bar in "%{bar}" ({:baz=>"baz"} given)', exception.message
65
65
  end
66
66
  end
67
67
 
@@ -19,6 +19,13 @@ class I18nLoadPathTest < Test::Unit::TestCase
19
19
  end
20
20
  end
21
21
 
22
+ test "loading an invalid yml file raises an InvalidLocaleData exception" do
23
+ assert_raise I18n::InvalidLocaleData do
24
+ I18n.load_path = [[locales_dir + '/invalid/syntax.yml']]
25
+ I18n.t(:'foo.bar', :default => "baz")
26
+ end
27
+ end
28
+
22
29
  test "adding arrays of filenames to the load path does not break locale loading" do
23
30
  I18n.load_path << Dir[locales_dir + '/*.{rb,yml}']
24
31
  assert_equal "baz", I18n.t(:'foo.bar')
@@ -0,0 +1,4 @@
1
+ en:
2
+ foo: foo
3
+ bar:
4
+ baz:
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
5
4
  prerelease:
5
+ version: 0.6.2
6
6
  platform: ruby
7
7
  authors:
8
8
  - Sven Fuchs
@@ -13,72 +13,72 @@ authors:
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
- date: 2012-08-31 00:00:00.000000000 Z
16
+ date: 2013-02-25 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
- name: activesupport
20
- requirement: !ruby/object:Gem::Requirement
21
- none: false
19
+ version_requirements: !ruby/object:Gem::Requirement
22
20
  requirements:
23
- - - ~>
21
+ - - ! '>='
24
22
  - !ruby/object:Gem::Version
25
23
  version: 3.0.0
24
+ none: false
25
+ name: activesupport
26
26
  type: :development
27
27
  prerelease: false
28
- version_requirements: !ruby/object:Gem::Requirement
29
- none: false
28
+ requirement: !ruby/object:Gem::Requirement
30
29
  requirements:
31
- - - ~>
30
+ - - ! '>='
32
31
  - !ruby/object:Gem::Version
33
32
  version: 3.0.0
34
- - !ruby/object:Gem::Dependency
35
- name: sqlite3
36
- requirement: !ruby/object:Gem::Requirement
37
33
  none: false
34
+ - !ruby/object:Gem::Dependency
35
+ version_requirements: !ruby/object:Gem::Requirement
38
36
  requirements:
39
37
  - - ! '>='
40
38
  - !ruby/object:Gem::Version
41
39
  version: '0'
40
+ none: false
41
+ name: sqlite3
42
42
  type: :development
43
43
  prerelease: false
44
- version_requirements: !ruby/object:Gem::Requirement
45
- none: false
44
+ requirement: !ruby/object:Gem::Requirement
46
45
  requirements:
47
46
  - - ! '>='
48
47
  - !ruby/object:Gem::Version
49
48
  version: '0'
50
- - !ruby/object:Gem::Dependency
51
- name: mocha
52
- requirement: !ruby/object:Gem::Requirement
53
49
  none: false
50
+ - !ruby/object:Gem::Dependency
51
+ version_requirements: !ruby/object:Gem::Requirement
54
52
  requirements:
55
53
  - - ! '>='
56
54
  - !ruby/object:Gem::Version
57
55
  version: '0'
56
+ none: false
57
+ name: mocha
58
58
  type: :development
59
59
  prerelease: false
60
- version_requirements: !ruby/object:Gem::Requirement
61
- none: false
60
+ requirement: !ruby/object:Gem::Requirement
62
61
  requirements:
63
62
  - - ! '>='
64
63
  - !ruby/object:Gem::Version
65
64
  version: '0'
66
- - !ruby/object:Gem::Dependency
67
- name: test_declarative
68
- requirement: !ruby/object:Gem::Requirement
69
65
  none: false
66
+ - !ruby/object:Gem::Dependency
67
+ version_requirements: !ruby/object:Gem::Requirement
70
68
  requirements:
71
69
  - - ! '>='
72
70
  - !ruby/object:Gem::Version
73
71
  version: '0'
72
+ none: false
73
+ name: test_declarative
74
74
  type: :development
75
75
  prerelease: false
76
- version_requirements: !ruby/object:Gem::Requirement
77
- none: false
76
+ requirement: !ruby/object:Gem::Requirement
78
77
  requirements:
79
78
  - - ! '>='
80
79
  - !ruby/object:Gem::Version
81
80
  version: '0'
81
+ none: false
82
82
  description: New wave Internationalization support for Ruby.
83
83
  email: rails-i18n@googlegroups.com
84
84
  executables: []
@@ -109,6 +109,7 @@ files:
109
109
  - lib/i18n/config.rb
110
110
  - lib/i18n/core_ext/hash.rb
111
111
  - lib/i18n/core_ext/kernel/surpress_warnings.rb
112
+ - lib/i18n/core_ext/string/encoding.rb
112
113
  - lib/i18n/core_ext/string/interpolate.rb
113
114
  - lib/i18n/exceptions.rb
114
115
  - lib/i18n/gettext/helpers.rb
@@ -174,29 +175,31 @@ files:
174
175
  - test/test_data/locales/en.rb
175
176
  - test/test_data/locales/en.yml
176
177
  - test/test_data/locales/invalid/empty.yml
178
+ - test/test_data/locales/invalid/syntax.yml
177
179
  - test/test_data/locales/plurals.rb
178
180
  - test/test_helper.rb
179
181
  - README.textile
180
182
  - MIT-LICENSE
181
183
  - CHANGELOG.textile
182
184
  homepage: http://github.com/svenfuchs/i18n
183
- licenses: []
185
+ licenses:
186
+ - MIT
184
187
  post_install_message:
185
188
  rdoc_options: []
186
189
  require_paths:
187
190
  - lib
188
191
  required_ruby_version: !ruby/object:Gem::Requirement
189
- none: false
190
192
  requirements:
191
193
  - - ! '>='
192
194
  - !ruby/object:Gem::Version
193
195
  version: '0'
194
- required_rubygems_version: !ruby/object:Gem::Requirement
195
196
  none: false
197
+ required_rubygems_version: !ruby/object:Gem::Requirement
196
198
  requirements:
197
199
  - - ! '>='
198
200
  - !ruby/object:Gem::Version
199
201
  version: 1.3.5
202
+ none: false
200
203
  requirements: []
201
204
  rubyforge_project: ! '[none]'
202
205
  rubygems_version: 1.8.23
@@ -204,4 +207,3 @@ signing_key:
204
207
  specification_version: 3
205
208
  summary: New wave Internationalization support for Ruby
206
209
  test_files: []
207
- has_rdoc: