svenfuchs-i18n 0.0.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 The Ruby I18n team
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,20 @@
1
+ h1. Ruby I18n gem
2
+
3
+ I18n and localization solution for Ruby.
4
+
5
+ For information please refer to http://rails-i18n.org
6
+
7
+ h2. Authors
8
+
9
+ * "Matt Aimonetti":http://railsontherun.com
10
+ * "Sven Fuchs":http://www.artweb-design.de
11
+ * "Joshua Harvey":http://www.workingwithrails.com/person/759-joshua-harvey
12
+ * "Saimon Moore":http://saimonmoore.net
13
+ * "Stephan Soller":http://www.arkanis-development.de
14
+
15
+ h2. License
16
+
17
+ MIT License. See the included MIT-LICENCE file.
18
+
19
+
20
+
data/i18n.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "i18n"
3
+ s.version = "0.1.0"
4
+ s.date = "2008-10-26"
5
+ s.summary = "Internationalization support for Ruby"
6
+ s.email = "rails-i18n@googlegroups.com"
7
+ s.homepage = "http://rails-i18n.org"
8
+ s.description = "Add Internationalization support to your Ruby application."
9
+ s.has_rdoc = false
10
+ s.authors = ['Sven Fuchs', 'Joshua Harvey', 'Matt Aimonetti', 'Stephan Soller', 'Saimon Moore']
11
+ s.files = [
12
+ 'i18n.gemspec',
13
+ 'lib/i18n/backend/simple.rb',
14
+ 'lib/i18n/exceptions.rb',
15
+ 'lib/i18n.rb',
16
+ 'MIT-LICENSE',
17
+ 'README.textile'
18
+ ]
19
+ s.test_files = [
20
+ 'test/all.rb',
21
+ 'test/i18n_exceptions_test.rb',
22
+ 'test/i18n_test.rb',
23
+ 'test/locale/en-US.rb',
24
+ 'test/locale/en-US.yml',
25
+ 'test/simple_backend_test.rb'
26
+ ]
27
+ end
@@ -0,0 +1,216 @@
1
+ require 'yaml'
2
+
3
+ module I18n
4
+ module Backend
5
+ class Simple
6
+ INTERPOLATION_RESERVED_KEYS = %w(scope default)
7
+ MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
8
+
9
+ # Accepts a list of paths to translation files. Loads translations from
10
+ # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
11
+ # for details.
12
+ def load_translations(*filenames)
13
+ filenames.each { |filename| load_file(filename) }
14
+ end
15
+
16
+ # Stores translations for the given locale in memory.
17
+ # This uses a deep merge for the translations hash, so existing
18
+ # translations will be overwritten by new ones only at the deepest
19
+ # level of the hash.
20
+ def store_translations(locale, data)
21
+ merge_translations(locale, data)
22
+ end
23
+
24
+ def translate(locale, key, options = {})
25
+ raise InvalidLocale.new(locale) if locale.nil?
26
+ return key.map { |k| translate(locale, k, options) } if key.is_a? Array
27
+
28
+ reserved = :scope, :default
29
+ count, scope, default = options.values_at(:count, *reserved)
30
+ options.delete(:default)
31
+ values = options.reject { |name, value| reserved.include?(name) }
32
+
33
+ entry = lookup(locale, key, scope)
34
+ if entry.nil?
35
+ entry = default(locale, default, options)
36
+ if entry.nil?
37
+ raise(I18n::MissingTranslationData.new(locale, key, options))
38
+ end
39
+ end
40
+ entry = pluralize(locale, entry, count)
41
+ entry = interpolate(locale, entry, values)
42
+ entry
43
+ end
44
+
45
+ # Acts the same as +strftime+, but returns a localized version of the
46
+ # formatted date string. Takes a key from the date/time formats
47
+ # translations as a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
48
+ def localize(locale, object, format = :default)
49
+ raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
50
+
51
+ type = object.respond_to?(:sec) ? 'time' : 'date'
52
+ # TODO only translate these if format is a String?
53
+ formats = translate(locale, :"#{type}.formats")
54
+ format = formats[format.to_sym] if formats && formats[format.to_sym]
55
+ # TODO raise exception unless format found?
56
+ format = format.to_s.dup
57
+
58
+ # TODO only translate these if the format string is actually present
59
+ # TODO check which format strings are present, then bulk translate then, then replace them
60
+ format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
61
+ format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
62
+ format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
63
+ format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
64
+ format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
65
+ object.strftime(format)
66
+ end
67
+
68
+ def initialized?
69
+ @initialized ||= false
70
+ end
71
+
72
+ def reload!
73
+ @initialized = false
74
+ @translations = nil
75
+ end
76
+
77
+ protected
78
+ def init_translations
79
+ load_translations(*I18n.load_path)
80
+ @initialized = true
81
+ end
82
+
83
+ def translations
84
+ @translations ||= {}
85
+ end
86
+
87
+ # Looks up a translation from the translations hash. Returns nil if
88
+ # eiher key is nil, or locale, scope or key do not exist as a key in the
89
+ # nested translations hash. Splits keys or scopes containing dots
90
+ # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
91
+ # <tt>%w(currency format)</tt>.
92
+ def lookup(locale, key, scope = [])
93
+ return unless key
94
+ init_translations unless initialized?
95
+ keys = I18n.send(:normalize_translation_keys, locale, key, scope)
96
+ keys.inject(translations) do |result, k|
97
+ if (x = result[k.to_sym]).nil?
98
+ return nil
99
+ else
100
+ x
101
+ end
102
+ end
103
+ end
104
+
105
+ # Evaluates a default translation.
106
+ # If the given default is a String it is used literally. If it is a Symbol
107
+ # it will be translated with the given options. If it is an Array the first
108
+ # translation yielded will be returned.
109
+ #
110
+ # <em>I.e.</em>, <tt>default(locale, [:foo, 'default'])</tt> will return +default+ if
111
+ # <tt>translate(locale, :foo)</tt> does not yield a result.
112
+ def default(locale, default, options = {})
113
+ case default
114
+ when String then default
115
+ when Symbol then translate locale, default, options
116
+ when Array then default.each do |obj|
117
+ result = default(locale, obj, options.dup) and return result
118
+ end and nil
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)
129
+ return entry unless entry.is_a?(Hash) and count
130
+ # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash)
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
+ #
139
+ # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
140
+ # # => "file test.txt opened by {{user}}"
141
+ #
142
+ # Note that you have to double escape the <tt>\\</tt> when you want to escape
143
+ # the <tt>{{...}}</tt> key in a string (once for the string and once for the
144
+ # interpolation).
145
+ def interpolate(locale, string, values = {})
146
+ return string unless string.is_a?(String)
147
+
148
+ if string.respond_to?(:force_encoding)
149
+ original_encoding = string.encoding
150
+ string.force_encoding(Encoding::BINARY)
151
+ end
152
+
153
+ result = string.gsub(MATCH) do
154
+ escaped, pattern, key = $1, $2, $2.to_sym
155
+
156
+ if escaped
157
+ pattern
158
+ elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
159
+ raise ReservedInterpolationKey.new(pattern, string)
160
+ elsif !values.include?(key)
161
+ raise MissingInterpolationArgument.new(pattern, string)
162
+ else
163
+ values[key].to_s
164
+ end
165
+ end
166
+
167
+ result.force_encoding(original_encoding) if original_encoding
168
+ result
169
+ end
170
+
171
+ # Loads a single translations file by delegating to #load_rb or
172
+ # #load_yml depending on the file extension and directly merges the
173
+ # data to the existing translations. Raises I18n::UnknownFileType
174
+ # for all other file extensions.
175
+ def load_file(filename)
176
+ type = File.extname(filename).tr('.', '').downcase
177
+ raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}")
178
+ data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash
179
+ data.each { |locale, d| merge_translations(locale, d) }
180
+ end
181
+
182
+ # Loads a plain Ruby translations file. eval'ing the file must yield
183
+ # a Hash containing translation data with locales as toplevel keys.
184
+ def load_rb(filename)
185
+ eval(IO.read(filename), binding, filename)
186
+ end
187
+
188
+ # Loads a YAML translations file. The data must have locales as
189
+ # toplevel keys.
190
+ def load_yml(filename)
191
+ YAML::load(IO.read(filename))
192
+ end
193
+
194
+ # Deep merges the given translations hash with the existing translations
195
+ # for the given locale
196
+ def merge_translations(locale, data)
197
+ locale = locale.to_sym
198
+ translations[locale] ||= {}
199
+ data = deep_symbolize_keys(data)
200
+
201
+ # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
202
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
203
+ translations[locale].merge!(data, &merger)
204
+ end
205
+
206
+ # Return a new hash with all keys and nested keys converted to symbols.
207
+ def deep_symbolize_keys(hash)
208
+ hash.inject({}) { |result, (key, value)|
209
+ value = deep_symbolize_keys(value) if value.is_a? Hash
210
+ result[(key.to_sym rescue key) || key] = value
211
+ result
212
+ }
213
+ end
214
+ end
215
+ end
216
+ end
@@ -0,0 +1,53 @@
1
+ module I18n
2
+ class ArgumentError < ::ArgumentError; end
3
+
4
+ class InvalidLocale < ArgumentError
5
+ attr_reader :locale
6
+ def initialize(locale)
7
+ @locale = locale
8
+ super "#{locale.inspect} is not a valid locale"
9
+ end
10
+ end
11
+
12
+ class MissingTranslationData < ArgumentError
13
+ attr_reader :locale, :key, :options
14
+ def initialize(locale, key, options)
15
+ @key, @locale, @options = key, locale, options
16
+ keys = I18n.send(:normalize_translation_keys, locale, key, options[:scope])
17
+ keys << 'no key' if keys.size < 2
18
+ super "translation missing: #{keys.join(', ')}"
19
+ end
20
+ end
21
+
22
+ class InvalidPluralizationData < ArgumentError
23
+ attr_reader :entry, :count
24
+ def initialize(entry, count)
25
+ @entry, @count = entry, count
26
+ super "translation data #{entry.inspect} can not be used with :count => #{count}"
27
+ end
28
+ end
29
+
30
+ class MissingInterpolationArgument < ArgumentError
31
+ attr_reader :key, :string
32
+ def initialize(key, string)
33
+ @key, @string = key, string
34
+ super "interpolation argument #{key} missing in #{string.inspect}"
35
+ end
36
+ end
37
+
38
+ class ReservedInterpolationKey < ArgumentError
39
+ attr_reader :key, :string
40
+ def initialize(key, string)
41
+ @key, @string = key, string
42
+ super "reserved key #{key.inspect} used in #{string.inspect}"
43
+ end
44
+ end
45
+
46
+ class UnknownFileType < ArgumentError
47
+ attr_reader :type, :filename
48
+ def initialize(type, filename)
49
+ @type, @filename = type, filename
50
+ super "can not load translations from #{filename}, the file type #{type} is not known"
51
+ end
52
+ end
53
+ end
data/lib/i18n.rb CHANGED
@@ -2,39 +2,39 @@
2
2
  # Sven Fuchs (http://www.artweb-design.de),
3
3
  # Joshua Harvey (http://www.workingwithrails.com/person/759-joshua-harvey),
4
4
  # Saimon Moore (http://saimonmoore.net),
5
- # Stephan Soller (http://www.arkanis-development.de/)
5
+ # Stephan Soller (http://www.arkanis-development.de/)
6
6
  # Copyright:: Copyright (c) 2008 The Ruby i18n Team
7
7
  # License:: MIT
8
8
  require 'i18n/backend/simple'
9
9
  require 'i18n/exceptions'
10
10
 
11
- module I18n
11
+ module I18n
12
12
  @@backend = nil
13
- @@load_paths = []
13
+ @@load_path = nil
14
14
  @@default_locale = :'en-US'
15
15
  @@exception_handler = :default_exception_handler
16
-
16
+
17
17
  class << self
18
18
  # Returns the current backend. Defaults to +Backend::Simple+.
19
19
  def backend
20
20
  @@backend ||= Backend::Simple.new
21
21
  end
22
-
22
+
23
23
  # Sets the current backend. Used to set a custom backend.
24
- def backend=(backend)
24
+ def backend=(backend)
25
25
  @@backend = backend
26
26
  end
27
-
27
+
28
28
  # Returns the current default locale. Defaults to 'en-US'
29
29
  def default_locale
30
- @@default_locale
30
+ @@default_locale
31
31
  end
32
-
32
+
33
33
  # Sets the current default locale. Used to set a custom default locale.
34
- def default_locale=(locale)
35
- @@default_locale = locale
34
+ def default_locale=(locale)
35
+ @@default_locale = locale
36
36
  end
37
-
37
+
38
38
  # Returns the current locale. Defaults to I18n.default_locale.
39
39
  def locale
40
40
  Thread.current[:locale] ||= default_locale
@@ -44,42 +44,55 @@ module I18n
44
44
  def locale=(locale)
45
45
  Thread.current[:locale] = locale
46
46
  end
47
-
47
+
48
48
  # Sets the exception handler.
49
49
  def exception_handler=(exception_handler)
50
50
  @@exception_handler = exception_handler
51
51
  end
52
-
53
- # Allow clients to register paths providing translation data sources. The
52
+
53
+ # Allow clients to register paths providing translation data sources. The
54
54
  # backend defines acceptable sources.
55
55
  #
56
56
  # E.g. the provided SimpleBackend accepts a list of paths to translation
57
57
  # files which are either named *.rb and contain plain Ruby Hashes or are
58
- # named *.yml and contain YAML data. So for the SimpleBackend clients may
58
+ # named *.yml and contain YAML data. So for the SimpleBackend clients may
59
59
  # register translation files like this:
60
- # I18n.load_paths << 'path/to/locale/en-US.yml'
61
- def load_paths
62
- @@load_paths
60
+ # I18n.load_path << 'path/to/locale/en-US.yml'
61
+ def load_path
62
+ @@load_path ||= []
63
+ end
64
+
65
+ # Sets the load path instance. Custom implementations are expected to
66
+ # behave like a Ruby Array.
67
+ def load_path=(load_path)
68
+ @@load_path = load_path
69
+ end
70
+
71
+ # Tells the backend to reload translations. Used in situations like the
72
+ # Rails development environment. Backends can implement whatever strategy
73
+ # is useful.
74
+ def reload!
75
+ backend.reload!
63
76
  end
64
-
65
- # Translates, pluralizes and interpolates a given key using a given locale,
77
+
78
+ # Translates, pluralizes and interpolates a given key using a given locale,
66
79
  # scope, and default, as well as interpolation values.
67
80
  #
68
81
  # *LOOKUP*
69
82
  #
70
- # Translation data is organized as a nested hash using the upper-level keys
71
- # as namespaces. <em>E.g.</em>, ActionView ships with the translation:
83
+ # Translation data is organized as a nested hash using the upper-level keys
84
+ # as namespaces. <em>E.g.</em>, ActionView ships with the translation:
72
85
  # <tt>:date => {:formats => {:short => "%b %d"}}</tt>.
73
- #
74
- # Translations can be looked up at any level of this hash using the key argument
75
- # and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
86
+ #
87
+ # Translations can be looked up at any level of this hash using the key argument
88
+ # and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
76
89
  # returns the whole translations hash <tt>{:formats => {:short => "%b %d"}}</tt>.
77
- #
78
- # Key can be either a single key or a dot-separated key (both Strings and Symbols
90
+ #
91
+ # Key can be either a single key or a dot-separated key (both Strings and Symbols
79
92
  # work). <em>E.g.</em>, the short format can be looked up using both:
80
93
  # I18n.t 'date.formats.short'
81
94
  # I18n.t :'date.formats.short'
82
- #
95
+ #
83
96
  # Scope can be either a single key, a dot-separated key or an array of keys
84
97
  # or dot-separated keys. Keys and scopes can be combined freely. So these
85
98
  # examples will all look up the same short date format:
@@ -92,9 +105,9 @@ module I18n
92
105
  #
93
106
  # Translations can contain interpolation variables which will be replaced by
94
107
  # values passed to #translate as part of the options hash, with the keys matching
95
- # the interpolation variable names.
108
+ # the interpolation variable names.
96
109
  #
97
- # <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
110
+ # <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
98
111
  # value for the key +bar+ will be interpolated into the translation:
99
112
  # I18n.t :foo, :bar => 'baz' # => 'foo baz'
100
113
  #
@@ -103,7 +116,7 @@ module I18n
103
116
  # Translation data can contain pluralized translations. Pluralized translations
104
117
  # are arrays of singluar/plural versions of translations like <tt>['Foo', 'Foos']</tt>.
105
118
  #
106
- # Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
119
+ # Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
107
120
  # pluralization rules. Other algorithms can be supported by custom backends.
108
121
  #
109
122
  # This returns the singular version of a pluralized translation:
@@ -112,9 +125,9 @@ module I18n
112
125
  # These both return the plural version of a pluralized translation:
113
126
  # I18n.t :foo, :count => 0 # => 'Foos'
114
127
  # I18n.t :foo, :count => 2 # => 'Foos'
115
- #
116
- # The <tt>:count</tt> option can be used both for pluralization and interpolation.
117
- # <em>E.g.</em>, with the translation
128
+ #
129
+ # The <tt>:count</tt> option can be used both for pluralization and interpolation.
130
+ # <em>E.g.</em>, with the translation
118
131
  # <tt>:foo => ['{{count}} foo', '{{count}} foos']</tt>, count will
119
132
  # be interpolated to the pluralized translation:
120
133
  # I18n.t :foo, :count => 1 # => '1 foo'
@@ -124,11 +137,11 @@ module I18n
124
137
  # This returns the translation for <tt>:foo</tt> or <tt>default</tt> if no translation was found:
125
138
  # I18n.t :foo, :default => 'default'
126
139
  #
127
- # This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
140
+ # This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
128
141
  # translation for <tt>:foo</tt> was found:
129
142
  # I18n.t :foo, :default => :bar
130
143
  #
131
- # Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
144
+ # Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
132
145
  # or <tt>default</tt> if no translations for <tt>:foo</tt> and <tt>:bar</tt> were found.
133
146
  # I18n.t :foo, :default => [:bar, 'default']
134
147
  #
@@ -144,13 +157,13 @@ module I18n
144
157
  # I18n.t [:foo, :bar], :scope => :baz
145
158
  def translate(key, options = {})
146
159
  locale = options.delete(:locale) || I18n.locale
147
- backend.translate locale, key, options
160
+ backend.translate(locale, key, options)
148
161
  rescue I18n::ArgumentError => e
149
162
  raise e if options[:raise]
150
- send @@exception_handler, e, locale, key, options
151
- end
163
+ send(@@exception_handler, e, locale, key, options)
164
+ end
152
165
  alias :t :translate
153
-
166
+
154
167
  # Localizes certain objects, such as dates and numbers to local formatting.
155
168
  def localize(object, options = {})
156
169
  locale = options[:locale] || I18n.locale
@@ -158,7 +171,7 @@ module I18n
158
171
  backend.localize(locale, object, format)
159
172
  end
160
173
  alias :l :localize
161
-
174
+
162
175
  protected
163
176
  # Handles exceptions raised in the backend. All exceptions except for
164
177
  # MissingTranslationData exceptions are re-raised. When a MissingTranslationData
@@ -168,14 +181,14 @@ module I18n
168
181
  return exception.message if MissingTranslationData === exception
169
182
  raise exception
170
183
  end
171
-
184
+
172
185
  # Merges the given locale, key and scope into a single array of keys.
173
186
  # Splits keys that contain dots into multiple keys. Makes sure all
174
187
  # keys are Symbols.
175
188
  def normalize_translation_keys(locale, key, scope)
176
189
  keys = [locale] + Array(scope) + [key]
177
- keys = keys.map{|k| k.to_s.split(/\./) }
178
- keys.flatten.map{|k| k.to_sym}
190
+ keys = keys.map { |k| k.to_s.split(/\./) }
191
+ keys.flatten.map { |k| k.to_sym }
179
192
  end
180
193
  end
181
- end
194
+ end
data/test/all.rb ADDED
@@ -0,0 +1,5 @@
1
+ dir = File.dirname(__FILE__)
2
+ require dir + '/i18n_test.rb'
3
+ require dir + '/simple_backend_test.rb'
4
+ require dir + '/i18n_exceptions_test.rb'
5
+ # *require* dir + '/custom_backend_test.rb'
@@ -0,0 +1,100 @@
1
+ $:.unshift "lib"
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'mocha'
6
+ require 'i18n'
7
+ require 'active_support'
8
+
9
+ class I18nExceptionsTest < Test::Unit::TestCase
10
+ def test_invalid_locale_stores_locale
11
+ force_invalid_locale
12
+ rescue I18n::ArgumentError => e
13
+ assert_nil e.locale
14
+ end
15
+
16
+ def test_invalid_locale_message
17
+ force_invalid_locale
18
+ rescue I18n::ArgumentError => e
19
+ assert_equal 'nil is not a valid locale', e.message
20
+ end
21
+
22
+ def test_missing_translation_data_stores_locale_key_and_options
23
+ force_missing_translation_data
24
+ rescue I18n::ArgumentError => e
25
+ options = {:scope => :bar}
26
+ assert_equal 'de-DE', e.locale
27
+ assert_equal :foo, e.key
28
+ assert_equal options, e.options
29
+ end
30
+
31
+ def test_missing_translation_data_message
32
+ force_missing_translation_data
33
+ rescue I18n::ArgumentError => e
34
+ assert_equal 'translation missing: de-DE, bar, foo', e.message
35
+ end
36
+
37
+ def test_invalid_pluralization_data_stores_entry_and_count
38
+ force_invalid_pluralization_data
39
+ rescue I18n::ArgumentError => e
40
+ assert_equal [:bar], e.entry
41
+ assert_equal 1, e.count
42
+ end
43
+
44
+ def test_invalid_pluralization_data_message
45
+ force_invalid_pluralization_data
46
+ rescue I18n::ArgumentError => e
47
+ assert_equal 'translation data [:bar] can not be used with :count => 1', e.message
48
+ end
49
+
50
+ def test_missing_interpolation_argument_stores_key_and_string
51
+ force_missing_interpolation_argument
52
+ rescue I18n::ArgumentError => e
53
+ assert_equal 'bar', e.key
54
+ assert_equal "{{bar}}", e.string
55
+ end
56
+
57
+ def test_missing_interpolation_argument_message
58
+ force_missing_interpolation_argument
59
+ rescue I18n::ArgumentError => e
60
+ assert_equal 'interpolation argument bar missing in "{{bar}}"', e.message
61
+ end
62
+
63
+ def test_reserved_interpolation_key_stores_key_and_string
64
+ force_reserved_interpolation_key
65
+ rescue I18n::ArgumentError => e
66
+ assert_equal 'scope', e.key
67
+ assert_equal "{{scope}}", e.string
68
+ end
69
+
70
+ def test_reserved_interpolation_key_message
71
+ force_reserved_interpolation_key
72
+ rescue I18n::ArgumentError => e
73
+ assert_equal 'reserved key "scope" used in "{{scope}}"', e.message
74
+ end
75
+
76
+ private
77
+ def force_invalid_locale
78
+ I18n.backend.translate nil, :foo
79
+ end
80
+
81
+ def force_missing_translation_data
82
+ I18n.backend.store_translations 'de-DE', :bar => nil
83
+ I18n.backend.translate 'de-DE', :foo, :scope => :bar
84
+ end
85
+
86
+ def force_invalid_pluralization_data
87
+ I18n.backend.store_translations 'de-DE', :foo => [:bar]
88
+ I18n.backend.translate 'de-DE', :foo, :count => 1
89
+ end
90
+
91
+ def force_missing_interpolation_argument
92
+ I18n.backend.store_translations 'de-DE', :foo => "{{bar}}"
93
+ I18n.backend.translate 'de-DE', :foo, :baz => 'baz'
94
+ end
95
+
96
+ def force_reserved_interpolation_key
97
+ I18n.backend.store_translations 'de-DE', :foo => "{{scope}}"
98
+ I18n.backend.translate 'de-DE', :foo, :baz => 'baz'
99
+ end
100
+ end
data/test/i18n_test.rb ADDED
@@ -0,0 +1,125 @@
1
+ $:.unshift "lib"
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'mocha'
6
+ require 'i18n'
7
+ require 'active_support'
8
+
9
+ class I18nTest < Test::Unit::TestCase
10
+ def setup
11
+ I18n.backend.store_translations :'en-US', {
12
+ :currency => {
13
+ :format => {
14
+ :separator => '.',
15
+ :delimiter => ',',
16
+ }
17
+ }
18
+ }
19
+ end
20
+
21
+ def test_uses_simple_backend_set_by_default
22
+ assert I18n.backend.is_a?(I18n::Backend::Simple)
23
+ end
24
+
25
+ def test_can_set_backend
26
+ assert_nothing_raised{ I18n.backend = self }
27
+ assert_equal self, I18n.backend
28
+ I18n.backend = I18n::Backend::Simple.new
29
+ end
30
+
31
+ def test_uses_en_us_as_default_locale_by_default
32
+ assert_equal 'en-US', I18n.default_locale
33
+ end
34
+
35
+ def test_can_set_default_locale
36
+ assert_nothing_raised{ I18n.default_locale = 'de-DE' }
37
+ assert_equal 'de-DE', I18n.default_locale
38
+ I18n.default_locale = 'en-US'
39
+ end
40
+
41
+ def test_uses_default_locale_as_locale_by_default
42
+ assert_equal I18n.default_locale, I18n.locale
43
+ end
44
+
45
+ def test_can_set_locale_to_thread_current
46
+ assert_nothing_raised{ I18n.locale = 'de-DE' }
47
+ assert_equal 'de-DE', I18n.locale
48
+ assert_equal 'de-DE', Thread.current[:locale]
49
+ I18n.locale = 'en-US'
50
+ end
51
+
52
+ def test_can_set_exception_handler
53
+ assert_nothing_raised{ I18n.exception_handler = :custom_exception_handler }
54
+ I18n.exception_handler = :default_exception_handler # revert it
55
+ end
56
+
57
+ def test_uses_custom_exception_handler
58
+ I18n.exception_handler = :custom_exception_handler
59
+ I18n.expects(:custom_exception_handler)
60
+ I18n.translate :bogus
61
+ I18n.exception_handler = :default_exception_handler # revert it
62
+ end
63
+
64
+ def test_delegates_translate_to_backend
65
+ I18n.backend.expects(:translate).with 'de-DE', :foo, {}
66
+ I18n.translate :foo, :locale => 'de-DE'
67
+ end
68
+
69
+ def test_delegates_localize_to_backend
70
+ I18n.backend.expects(:localize).with 'de-DE', :whatever, :default
71
+ I18n.localize :whatever, :locale => 'de-DE'
72
+ end
73
+
74
+ def test_translate_given_no_locale_uses_i18n_locale
75
+ I18n.backend.expects(:translate).with 'en-US', :foo, {}
76
+ I18n.translate :foo
77
+ end
78
+
79
+ def test_translate_on_nested_symbol_keys_works
80
+ assert_equal ".", I18n.t(:'currency.format.separator')
81
+ end
82
+
83
+ def test_translate_with_nested_string_keys_works
84
+ assert_equal ".", I18n.t('currency.format.separator')
85
+ end
86
+
87
+ def test_translate_with_array_as_scope_works
88
+ assert_equal ".", I18n.t(:separator, :scope => ['currency.format'])
89
+ end
90
+
91
+ def test_translate_with_array_containing_dot_separated_strings_as_scope_works
92
+ assert_equal ".", I18n.t(:separator, :scope => ['currency.format'])
93
+ end
94
+
95
+ def test_translate_with_key_array_and_dot_separated_scope_works
96
+ assert_equal [".", ","], I18n.t(%w(separator delimiter), :scope => 'currency.format')
97
+ end
98
+
99
+ def test_translate_with_dot_separated_key_array_and_scope_works
100
+ assert_equal [".", ","], I18n.t(%w(format.separator format.delimiter), :scope => 'currency')
101
+ end
102
+
103
+ def test_translate_with_options_using_scope_works
104
+ I18n.backend.expects(:translate).with('de-DE', :precision, :scope => :"currency.format")
105
+ I18n.with_options :locale => 'de-DE', :scope => :'currency.format' do |locale|
106
+ locale.t :precision
107
+ end
108
+ end
109
+
110
+ # def test_translate_given_no_args_raises_missing_translation_data
111
+ # assert_equal "translation missing: en-US, no key", I18n.t
112
+ # end
113
+
114
+ def test_translate_given_a_bogus_key_raises_missing_translation_data
115
+ assert_equal "translation missing: en-US, bogus", I18n.t(:bogus)
116
+ end
117
+
118
+ def test_localize_nil_raises_argument_error
119
+ assert_raises(I18n::ArgumentError) { I18n.l nil }
120
+ end
121
+
122
+ def test_localize_object_raises_argument_error
123
+ assert_raises(I18n::ArgumentError) { I18n.l Object.new }
124
+ end
125
+ end
@@ -0,0 +1 @@
1
+ {:'en-US-Ruby' => {:foo => {:bar => "baz"}}}
@@ -0,0 +1,3 @@
1
+ en-US-Yaml:
2
+ foo:
3
+ bar: baz
@@ -0,0 +1,502 @@
1
+ # encoding: utf-8
2
+ $:.unshift "lib"
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'mocha'
7
+ require 'i18n'
8
+ require 'time'
9
+ require 'yaml'
10
+
11
+ module I18nSimpleBackendTestSetup
12
+ def setup_backend
13
+ # backend_reset_translations!
14
+ @backend = I18n::Backend::Simple.new
15
+ @backend.store_translations 'en-US', :foo => {:bar => 'bar', :baz => 'baz'}
16
+ @locale_dir = File.dirname(__FILE__) + '/locale'
17
+ end
18
+ alias :setup :setup_backend
19
+
20
+ # def backend_reset_translations!
21
+ # I18n::Backend::Simple::ClassMethods.send :class_variable_set, :@@translations, {}
22
+ # end
23
+
24
+ def backend_get_translations
25
+ # I18n::Backend::Simple::ClassMethods.send :class_variable_get, :@@translations
26
+ @backend.instance_variable_get :@translations
27
+ end
28
+
29
+ def add_datetime_translations
30
+ @backend.store_translations :'de-DE', {
31
+ :date => {
32
+ :formats => {
33
+ :default => "%d.%m.%Y",
34
+ :short => "%d. %b",
35
+ :long => "%d. %B %Y",
36
+ },
37
+ :day_names => %w(Sonntag Montag Dienstag Mittwoch Donnerstag Freitag Samstag),
38
+ :abbr_day_names => %w(So Mo Di Mi Do Fr Sa),
39
+ :month_names => %w(Januar Februar März April Mai Juni Juli August September Oktober November Dezember).unshift(nil),
40
+ :abbr_month_names => %w(Jan Feb Mar Apr Mai Jun Jul Aug Sep Okt Nov Dez).unshift(nil),
41
+ :order => [:day, :month, :year]
42
+ },
43
+ :time => {
44
+ :formats => {
45
+ :default => "%a, %d. %b %Y %H:%M:%S %z",
46
+ :short => "%d. %b %H:%M",
47
+ :long => "%d. %B %Y %H:%M",
48
+ },
49
+ :am => 'am',
50
+ :pm => 'pm'
51
+ },
52
+ :datetime => {
53
+ :distance_in_words => {
54
+ :half_a_minute => 'half a minute',
55
+ :less_than_x_seconds => {
56
+ :one => 'less than 1 second',
57
+ :other => 'less than {{count}} seconds'
58
+ },
59
+ :x_seconds => {
60
+ :one => '1 second',
61
+ :other => '{{count}} seconds'
62
+ },
63
+ :less_than_x_minutes => {
64
+ :one => 'less than a minute',
65
+ :other => 'less than {{count}} minutes'
66
+ },
67
+ :x_minutes => {
68
+ :one => '1 minute',
69
+ :other => '{{count}} minutes'
70
+ },
71
+ :about_x_hours => {
72
+ :one => 'about 1 hour',
73
+ :other => 'about {{count}} hours'
74
+ },
75
+ :x_days => {
76
+ :one => '1 day',
77
+ :other => '{{count}} days'
78
+ },
79
+ :about_x_months => {
80
+ :one => 'about 1 month',
81
+ :other => 'about {{count}} months'
82
+ },
83
+ :x_months => {
84
+ :one => '1 month',
85
+ :other => '{{count}} months'
86
+ },
87
+ :about_x_years => {
88
+ :one => 'about 1 year',
89
+ :other => 'about {{count}} year'
90
+ },
91
+ :over_x_years => {
92
+ :one => 'over 1 year',
93
+ :other => 'over {{count}} years'
94
+ }
95
+ }
96
+ }
97
+ }
98
+ end
99
+ end
100
+
101
+ class I18nSimpleBackendTranslationsTest < Test::Unit::TestCase
102
+ include I18nSimpleBackendTestSetup
103
+
104
+ def test_store_translations_adds_translations # no, really :-)
105
+ @backend.store_translations :'en-US', :foo => 'bar'
106
+ assert_equal Hash[:'en-US', {:foo => 'bar'}], backend_get_translations
107
+ end
108
+
109
+ def test_store_translations_deep_merges_translations
110
+ @backend.store_translations :'en-US', :foo => {:bar => 'bar'}
111
+ @backend.store_translations :'en-US', :foo => {:baz => 'baz'}
112
+ assert_equal Hash[:'en-US', {:foo => {:bar => 'bar', :baz => 'baz'}}], backend_get_translations
113
+ end
114
+
115
+ def test_store_translations_forces_locale_to_sym
116
+ @backend.store_translations 'en-US', :foo => 'bar'
117
+ assert_equal Hash[:'en-US', {:foo => 'bar'}], backend_get_translations
118
+ end
119
+
120
+ def test_store_translations_converts_keys_to_symbols
121
+ # backend_reset_translations!
122
+ @backend.store_translations 'en-US', 'foo' => {'bar' => 'bar', 'baz' => 'baz'}
123
+ assert_equal Hash[:'en-US', {:foo => {:bar => 'bar', :baz => 'baz'}}], backend_get_translations
124
+ end
125
+ end
126
+
127
+ class I18nSimpleBackendTranslateTest < Test::Unit::TestCase
128
+ include I18nSimpleBackendTestSetup
129
+
130
+ def test_translate_calls_lookup_with_locale_given
131
+ @backend.expects(:lookup).with('de-DE', :bar, [:foo]).returns 'bar'
132
+ @backend.translate 'de-DE', :bar, :scope => [:foo]
133
+ end
134
+
135
+ def test_given_no_keys_it_returns_the_default
136
+ assert_equal 'default', @backend.translate('en-US', nil, :default => 'default')
137
+ end
138
+
139
+ def test_translate_given_a_symbol_as_a_default_translates_the_symbol
140
+ assert_equal 'bar', @backend.translate('en-US', nil, :scope => [:foo], :default => :bar)
141
+ end
142
+
143
+ def test_translate_given_an_array_as_default_uses_the_first_match
144
+ assert_equal 'bar', @backend.translate('en-US', :does_not_exist, :scope => [:foo], :default => [:does_not_exist_2, :bar])
145
+ end
146
+
147
+ def test_translate_given_an_array_of_inexistent_keys_it_raises_missing_translation_data
148
+ assert_raises I18n::MissingTranslationData do
149
+ @backend.translate('en-US', :does_not_exist, :scope => [:foo], :default => [:does_not_exist_2, :does_not_exist_3])
150
+ end
151
+ end
152
+
153
+ def test_translate_an_array_of_keys_translates_all_of_them
154
+ assert_equal %w(bar baz), @backend.translate('en-US', [:bar, :baz], :scope => [:foo])
155
+ end
156
+
157
+ def test_translate_calls_pluralize
158
+ @backend.expects(:pluralize).with 'en-US', 'bar', 1
159
+ @backend.translate 'en-US', :bar, :scope => [:foo], :count => 1
160
+ end
161
+
162
+ def test_translate_calls_interpolate
163
+ @backend.expects(:interpolate).with 'en-US', 'bar', {}
164
+ @backend.translate 'en-US', :bar, :scope => [:foo]
165
+ end
166
+
167
+ def test_translate_calls_interpolate_including_count_as_a_value
168
+ @backend.expects(:interpolate).with 'en-US', 'bar', {:count => 1}
169
+ @backend.translate 'en-US', :bar, :scope => [:foo], :count => 1
170
+ end
171
+
172
+ def test_translate_given_nil_as_a_locale_raises_an_argument_error
173
+ assert_raises(I18n::InvalidLocale){ @backend.translate nil, :bar }
174
+ end
175
+
176
+ def test_translate_with_a_bogus_key_and_no_default_raises_missing_translation_data
177
+ assert_raises(I18n::MissingTranslationData){ @backend.translate 'de-DE', :bogus }
178
+ end
179
+ end
180
+
181
+ class I18nSimpleBackendLookupTest < Test::Unit::TestCase
182
+ include I18nSimpleBackendTestSetup
183
+
184
+ # useful because this way we can use the backend with no key for interpolation/pluralization
185
+ def test_lookup_given_nil_as_a_key_returns_nil
186
+ assert_nil @backend.send(:lookup, 'en-US', nil)
187
+ end
188
+
189
+ def test_lookup_given_nested_keys_looks_up_a_nested_hash_value
190
+ assert_equal 'bar', @backend.send(:lookup, 'en-US', :bar, [:foo])
191
+ end
192
+ end
193
+
194
+ class I18nSimpleBackendPluralizeTest < Test::Unit::TestCase
195
+ include I18nSimpleBackendTestSetup
196
+
197
+ def test_pluralize_given_nil_returns_the_given_entry
198
+ entry = {:one => 'bar', :other => 'bars'}
199
+ assert_equal entry, @backend.send(:pluralize, nil, entry, nil)
200
+ end
201
+
202
+ def test_pluralize_given_0_returns_zero_string_if_zero_key_given
203
+ assert_equal 'zero', @backend.send(:pluralize, nil, {:zero => 'zero', :one => 'bar', :other => 'bars'}, 0)
204
+ end
205
+
206
+ def test_pluralize_given_0_returns_plural_string_if_no_zero_key_given
207
+ assert_equal 'bars', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 0)
208
+ end
209
+
210
+ def test_pluralize_given_1_returns_singular_string
211
+ assert_equal 'bar', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 1)
212
+ end
213
+
214
+ def test_pluralize_given_2_returns_plural_string
215
+ assert_equal 'bars', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 2)
216
+ end
217
+
218
+ def test_pluralize_given_3_returns_plural_string
219
+ assert_equal 'bars', @backend.send(:pluralize, nil, {:one => 'bar', :other => 'bars'}, 3)
220
+ end
221
+
222
+ def test_interpolate_given_incomplete_pluralization_data_raises_invalid_pluralization_data
223
+ assert_raises(I18n::InvalidPluralizationData){ @backend.send(:pluralize, nil, {:one => 'bar'}, 2) }
224
+ end
225
+
226
+ # def test_interpolate_given_a_string_raises_invalid_pluralization_data
227
+ # assert_raises(I18n::InvalidPluralizationData){ @backend.send(:pluralize, nil, 'bar', 2) }
228
+ # end
229
+ #
230
+ # def test_interpolate_given_an_array_raises_invalid_pluralization_data
231
+ # assert_raises(I18n::InvalidPluralizationData){ @backend.send(:pluralize, nil, ['bar'], 2) }
232
+ # end
233
+ end
234
+
235
+ class I18nSimpleBackendInterpolateTest < Test::Unit::TestCase
236
+ include I18nSimpleBackendTestSetup
237
+
238
+ def test_interpolate_given_a_value_hash_interpolates_the_values_to_the_string
239
+ assert_equal 'Hi David!', @backend.send(:interpolate, nil, 'Hi {{name}}!', :name => 'David')
240
+ end
241
+
242
+ def test_interpolate_given_a_value_hash_interpolates_into_unicode_string
243
+ assert_equal 'Häi David!', @backend.send(:interpolate, nil, 'Häi {{name}}!', :name => 'David')
244
+ end
245
+
246
+ def test_interpolate_given_nil_as_a_string_returns_nil
247
+ assert_nil @backend.send(:interpolate, nil, nil, :name => 'David')
248
+ end
249
+
250
+ def test_interpolate_given_an_non_string_as_a_string_returns_nil
251
+ assert_equal [], @backend.send(:interpolate, nil, [], :name => 'David')
252
+ end
253
+
254
+ def test_interpolate_given_a_values_hash_with_nil_values_interpolates_the_string
255
+ assert_equal 'Hi !', @backend.send(:interpolate, nil, 'Hi {{name}}!', {:name => nil})
256
+ end
257
+
258
+ def test_interpolate_given_an_empty_values_hash_raises_missing_interpolation_argument
259
+ assert_raises(I18n::MissingInterpolationArgument) { @backend.send(:interpolate, nil, 'Hi {{name}}!', {}) }
260
+ end
261
+
262
+ def test_interpolate_given_a_string_containing_a_reserved_key_raises_reserved_interpolation_key
263
+ assert_raises(I18n::ReservedInterpolationKey) { @backend.send(:interpolate, nil, '{{default}}', {:default => nil}) }
264
+ end
265
+ end
266
+
267
+ class I18nSimpleBackendLocalizeDateTest < Test::Unit::TestCase
268
+ include I18nSimpleBackendTestSetup
269
+
270
+ def setup
271
+ @backend = I18n::Backend::Simple.new
272
+ add_datetime_translations
273
+ @date = Date.new 2008, 1, 1
274
+ end
275
+
276
+ def test_translate_given_the_short_format_it_uses_it
277
+ assert_equal '01. Jan', @backend.localize('de-DE', @date, :short)
278
+ end
279
+
280
+ def test_translate_given_the_long_format_it_uses_it
281
+ assert_equal '01. Januar 2008', @backend.localize('de-DE', @date, :long)
282
+ end
283
+
284
+ def test_translate_given_the_default_format_it_uses_it
285
+ assert_equal '01.01.2008', @backend.localize('de-DE', @date, :default)
286
+ end
287
+
288
+ def test_translate_given_a_day_name_format_it_returns_a_day_name
289
+ assert_equal 'Dienstag', @backend.localize('de-DE', @date, '%A')
290
+ end
291
+
292
+ def test_translate_given_an_abbr_day_name_format_it_returns_an_abbrevated_day_name
293
+ assert_equal 'Di', @backend.localize('de-DE', @date, '%a')
294
+ end
295
+
296
+ def test_translate_given_a_month_name_format_it_returns_a_month_name
297
+ assert_equal 'Januar', @backend.localize('de-DE', @date, '%B')
298
+ end
299
+
300
+ def test_translate_given_an_abbr_month_name_format_it_returns_an_abbrevated_month_name
301
+ assert_equal 'Jan', @backend.localize('de-DE', @date, '%b')
302
+ end
303
+
304
+ def test_translate_given_no_format_it_does_not_fail
305
+ assert_nothing_raised{ @backend.localize 'de-DE', @date }
306
+ end
307
+
308
+ def test_translate_given_an_unknown_format_it_does_not_fail
309
+ assert_nothing_raised{ @backend.localize 'de-DE', @date, '%x' }
310
+ end
311
+
312
+ def test_localize_nil_raises_argument_error
313
+ assert_raises(I18n::ArgumentError) { @backend.localize 'de-DE', nil }
314
+ end
315
+
316
+ def test_localize_object_raises_argument_error
317
+ assert_raises(I18n::ArgumentError) { @backend.localize 'de-DE', Object.new }
318
+ end
319
+ end
320
+
321
+ class I18nSimpleBackendLocalizeDateTimeTest < Test::Unit::TestCase
322
+ include I18nSimpleBackendTestSetup
323
+
324
+ def setup
325
+ @backend = I18n::Backend::Simple.new
326
+ add_datetime_translations
327
+ @morning = DateTime.new 2008, 1, 1, 6
328
+ @evening = DateTime.new 2008, 1, 1, 18
329
+ end
330
+
331
+ def test_translate_given_the_short_format_it_uses_it
332
+ assert_equal '01. Jan 06:00', @backend.localize('de-DE', @morning, :short)
333
+ end
334
+
335
+ def test_translate_given_the_long_format_it_uses_it
336
+ assert_equal '01. Januar 2008 06:00', @backend.localize('de-DE', @morning, :long)
337
+ end
338
+
339
+ def test_translate_given_the_default_format_it_uses_it
340
+ assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de-DE', @morning, :default)
341
+ end
342
+
343
+ def test_translate_given_a_day_name_format_it_returns_the_correct_day_name
344
+ assert_equal 'Dienstag', @backend.localize('de-DE', @morning, '%A')
345
+ end
346
+
347
+ def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name
348
+ assert_equal 'Di', @backend.localize('de-DE', @morning, '%a')
349
+ end
350
+
351
+ def test_translate_given_a_month_name_format_it_returns_the_correct_month_name
352
+ assert_equal 'Januar', @backend.localize('de-DE', @morning, '%B')
353
+ end
354
+
355
+ def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name
356
+ assert_equal 'Jan', @backend.localize('de-DE', @morning, '%b')
357
+ end
358
+
359
+ def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator
360
+ assert_equal 'am', @backend.localize('de-DE', @morning, '%p')
361
+ assert_equal 'pm', @backend.localize('de-DE', @evening, '%p')
362
+ end
363
+
364
+ def test_translate_given_no_format_it_does_not_fail
365
+ assert_nothing_raised{ @backend.localize 'de-DE', @morning }
366
+ end
367
+
368
+ def test_translate_given_an_unknown_format_it_does_not_fail
369
+ assert_nothing_raised{ @backend.localize 'de-DE', @morning, '%x' }
370
+ end
371
+ end
372
+
373
+ class I18nSimpleBackendLocalizeTimeTest < Test::Unit::TestCase
374
+ include I18nSimpleBackendTestSetup
375
+
376
+ def setup
377
+ @old_timezone, ENV['TZ'] = ENV['TZ'], 'UTC'
378
+ @backend = I18n::Backend::Simple.new
379
+ add_datetime_translations
380
+ @morning = Time.parse '2008-01-01 6:00 UTC'
381
+ @evening = Time.parse '2008-01-01 18:00 UTC'
382
+ end
383
+
384
+ def teardown
385
+ @old_timezone ? ENV['TZ'] = @old_timezone : ENV.delete('TZ')
386
+ end
387
+
388
+ def test_translate_given_the_short_format_it_uses_it
389
+ assert_equal '01. Jan 06:00', @backend.localize('de-DE', @morning, :short)
390
+ end
391
+
392
+ def test_translate_given_the_long_format_it_uses_it
393
+ assert_equal '01. Januar 2008 06:00', @backend.localize('de-DE', @morning, :long)
394
+ end
395
+
396
+ # TODO Seems to break on Windows because ENV['TZ'] is ignored. What's a better way to do this?
397
+ # def test_translate_given_the_default_format_it_uses_it
398
+ # assert_equal 'Di, 01. Jan 2008 06:00:00 +0000', @backend.localize('de-DE', @morning, :default)
399
+ # end
400
+
401
+ def test_translate_given_a_day_name_format_it_returns_the_correct_day_name
402
+ assert_equal 'Dienstag', @backend.localize('de-DE', @morning, '%A')
403
+ end
404
+
405
+ def test_translate_given_an_abbr_day_name_format_it_returns_the_correct_abbrevated_day_name
406
+ assert_equal 'Di', @backend.localize('de-DE', @morning, '%a')
407
+ end
408
+
409
+ def test_translate_given_a_month_name_format_it_returns_the_correct_month_name
410
+ assert_equal 'Januar', @backend.localize('de-DE', @morning, '%B')
411
+ end
412
+
413
+ def test_translate_given_an_abbr_month_name_format_it_returns_the_correct_abbrevated_month_name
414
+ assert_equal 'Jan', @backend.localize('de-DE', @morning, '%b')
415
+ end
416
+
417
+ def test_translate_given_a_meridian_indicator_format_it_returns_the_correct_meridian_indicator
418
+ assert_equal 'am', @backend.localize('de-DE', @morning, '%p')
419
+ assert_equal 'pm', @backend.localize('de-DE', @evening, '%p')
420
+ end
421
+
422
+ def test_translate_given_no_format_it_does_not_fail
423
+ assert_nothing_raised{ @backend.localize 'de-DE', @morning }
424
+ end
425
+
426
+ def test_translate_given_an_unknown_format_it_does_not_fail
427
+ assert_nothing_raised{ @backend.localize 'de-DE', @morning, '%x' }
428
+ end
429
+ end
430
+
431
+ class I18nSimpleBackendHelperMethodsTest < Test::Unit::TestCase
432
+ def setup
433
+ @backend = I18n::Backend::Simple.new
434
+ end
435
+
436
+ def test_deep_symbolize_keys_works
437
+ result = @backend.send :deep_symbolize_keys, 'foo' => {'bar' => {'baz' => 'bar'}}
438
+ expected = {:foo => {:bar => {:baz => 'bar'}}}
439
+ assert_equal expected, result
440
+ end
441
+ end
442
+
443
+ class I18nSimpleBackendLoadTranslationsTest < Test::Unit::TestCase
444
+ include I18nSimpleBackendTestSetup
445
+
446
+ def test_load_translations_with_unknown_file_type_raises_exception
447
+ assert_raises(I18n::UnknownFileType) { @backend.load_translations "#{@locale_dir}/en-US.xml" }
448
+ end
449
+
450
+ def test_load_translations_with_ruby_file_type_does_not_raise_exception
451
+ assert_nothing_raised { @backend.load_translations "#{@locale_dir}/en-US.rb" }
452
+ end
453
+
454
+ def test_load_rb_loads_data_from_ruby_file
455
+ data = @backend.send :load_rb, "#{@locale_dir}/en-US.rb"
456
+ assert_equal({:'en-US-Ruby' => {:foo => {:bar => "baz"}}}, data)
457
+ end
458
+
459
+ def test_load_rb_loads_data_from_yaml_file
460
+ data = @backend.send :load_yml, "#{@locale_dir}/en-US.yml"
461
+ assert_equal({'en-US-Yaml' => {'foo' => {'bar' => 'baz'}}}, data)
462
+ end
463
+
464
+ def test_load_translations_loads_from_different_file_formats
465
+ @backend = I18n::Backend::Simple.new
466
+ @backend.load_translations "#{@locale_dir}/en-US.rb", "#{@locale_dir}/en-US.yml"
467
+ expected = {
468
+ :'en-US-Ruby' => {:foo => {:bar => "baz"}},
469
+ :'en-US-Yaml' => {:foo => {:bar => "baz"}}
470
+ }
471
+ assert_equal expected, backend_get_translations
472
+ end
473
+ end
474
+
475
+ class I18nSimpleBackendReloadTranslationsTest < Test::Unit::TestCase
476
+ include I18nSimpleBackendTestSetup
477
+
478
+ def setup
479
+ @backend = I18n::Backend::Simple.new
480
+ I18n.load_path = [File.dirname(__FILE__) + '/locale/en-US.yml']
481
+ assert_nil backend_get_translations
482
+ @backend.send :init_translations
483
+ end
484
+
485
+ def teardown
486
+ I18n.load_path = []
487
+ end
488
+
489
+ def test_setup
490
+ assert_not_nil backend_get_translations
491
+ end
492
+
493
+ def test_reload_translations_unloads_translations
494
+ @backend.reload!
495
+ assert_nil backend_get_translations
496
+ end
497
+
498
+ def test_reload_translations_uninitializes_translations
499
+ @backend.reload!
500
+ assert_equal @backend.initialized?, false
501
+ end
502
+ end
metadata CHANGED
@@ -1,10 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: svenfuchs-i18n
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sven Fuchs
8
+ - Joshua Harvey
8
9
  - Matt Aimonetti
9
10
  - Stephan Soller
10
11
  - Saimon Moore
@@ -12,12 +13,12 @@ autorequire:
12
13
  bindir: bin
13
14
  cert_chain: []
14
15
 
15
- date: 2008-06-13 00:00:00 -07:00
16
+ date: 2008-10-26 00:00:00 -07:00
16
17
  default_executable:
17
18
  dependencies: []
18
19
 
19
- description: Add Internationalization to your Ruby application.
20
- email: rails-patch-i18n@googlegroups.com
20
+ description: Add Internationalization support to your Ruby application.
21
+ email: rails-i18n@googlegroups.com
21
22
  executables: []
22
23
 
23
24
  extensions: []
@@ -25,19 +26,14 @@ extensions: []
25
26
  extra_rdoc_files: []
26
27
 
27
28
  files:
28
- - lib/i18n/backend/minimal.rb
29
- - lib/i18n/core_ext.rb
30
- - lib/i18n/localization.rb
31
- - lib/i18n/translation.rb
29
+ - i18n.gemspec
30
+ - lib/i18n/backend/simple.rb
31
+ - lib/i18n/exceptions.rb
32
32
  - lib/i18n.rb
33
- - LICENSE
34
- - README
35
- - spec/core_ext_spec.rb
36
- - spec/i18n_spec.rb
37
- - spec/spec.opts
38
- - spec/spec/helper.rb
33
+ - MIT-LICENSE
34
+ - README.textile
39
35
  has_rdoc: false
40
- homepage: http://groups.google.com/group/rails-patch-i18n
36
+ homepage: http://rails-i18n.org
41
37
  post_install_message:
42
38
  rdoc_options: []
43
39
 
@@ -61,6 +57,11 @@ rubyforge_project:
61
57
  rubygems_version: 1.2.0
62
58
  signing_key:
63
59
  specification_version: 2
64
- summary: Internationalization for Ruby
65
- test_files: []
66
-
60
+ summary: Internationalization support for Ruby
61
+ test_files:
62
+ - test/all.rb
63
+ - test/i18n_exceptions_test.rb
64
+ - test/i18n_test.rb
65
+ - test/locale/en-US.rb
66
+ - test/locale/en-US.yml
67
+ - test/simple_backend_test.rb