josevalim-i18n 0.1.2

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,18 @@
1
+ h1. Ruby I18n gem
2
+
3
+ I18n and localization solution for Ruby.
4
+
5
+ h2. Authors
6
+
7
+ * "Matt Aimonetti":http://railsontherun.com
8
+ * "Sven Fuchs":http://www.artweb-design.de
9
+ * "Joshua Harvey":http://www.workingwithrails.com/person/759-joshua-harvey
10
+ * "Saimon Moore":http://saimonmoore.net
11
+ * "Stephan Soller":http://www.arkanis-development.de
12
+
13
+ h2. License
14
+
15
+ MIT License. See the included MIT-LICENCE file.
16
+
17
+
18
+
data/lib/i18n.rb ADDED
@@ -0,0 +1,187 @@
1
+ # Authors:: Matt Aimonetti (http://railsontherun.com/),
2
+ # Sven Fuchs (http://www.artweb-design.de),
3
+ # Joshua Harvey (http://www.workingwithrails.com/person/759-joshua-harvey),
4
+ # Saimon Moore (http://saimonmoore.net),
5
+ # Stephan Soller (http://www.arkanis-development.de/)
6
+ # Copyright:: Copyright (c) 2008 The Ruby i18n Team
7
+ # License:: MIT
8
+ require 'i18n/backend/simple'
9
+ require 'i18n/exceptions'
10
+
11
+ module I18n
12
+ @@backend = nil
13
+ @@load_path = nil
14
+ @@default_locale = :'en-US'
15
+ @@exception_handler = :default_exception_handler
16
+
17
+ class << self
18
+ # Returns the current backend. Defaults to +Backend::Simple+.
19
+ def backend
20
+ @@backend ||= Backend::Simple.new
21
+ end
22
+
23
+ # Sets the current backend. Used to set a custom backend.
24
+ def backend=(backend)
25
+ @@backend = backend
26
+ end
27
+
28
+ # Returns the current default locale. Defaults to 'en-US'
29
+ def default_locale
30
+ @@default_locale
31
+ end
32
+
33
+ # Sets the current default locale. Used to set a custom default locale.
34
+ def default_locale=(locale)
35
+ @@default_locale = locale
36
+ end
37
+
38
+ # Returns the current locale. Defaults to I18n.default_locale.
39
+ def locale
40
+ Thread.current[:locale] ||= default_locale
41
+ end
42
+
43
+ # Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
44
+ def locale=(locale)
45
+ Thread.current[:locale] = locale
46
+ end
47
+
48
+ # Sets the exception handler.
49
+ def exception_handler=(exception_handler)
50
+ @@exception_handler = exception_handler
51
+ end
52
+
53
+ # Allow clients to register paths providing translation data sources. The
54
+ # backend defines acceptable sources.
55
+ #
56
+ # E.g. the provided SimpleBackend accepts a list of paths to translation
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
59
+ # register translation files like this:
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
+ # Translates, pluralizes and interpolates a given key using a given locale,
72
+ # scope, and default, as well as interpolation values.
73
+ #
74
+ # *LOOKUP*
75
+ #
76
+ # Translation data is organized as a nested hash using the upper-level keys
77
+ # as namespaces. <em>E.g.</em>, ActionView ships with the translation:
78
+ # <tt>:date => {:formats => {:short => "%b %d"}}</tt>.
79
+ #
80
+ # Translations can be looked up at any level of this hash using the key argument
81
+ # and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
82
+ # returns the whole translations hash <tt>{:formats => {:short => "%b %d"}}</tt>.
83
+ #
84
+ # Key can be either a single key or a dot-separated key (both Strings and Symbols
85
+ # work). <em>E.g.</em>, the short format can be looked up using both:
86
+ # I18n.t 'date.formats.short'
87
+ # I18n.t :'date.formats.short'
88
+ #
89
+ # Scope can be either a single key, a dot-separated key or an array of keys
90
+ # or dot-separated keys. Keys and scopes can be combined freely. So these
91
+ # examples will all look up the same short date format:
92
+ # I18n.t 'date.formats.short'
93
+ # I18n.t 'formats.short', :scope => 'date'
94
+ # I18n.t 'short', :scope => 'date.formats'
95
+ # I18n.t 'short', :scope => %w(date formats)
96
+ #
97
+ # *INTERPOLATION*
98
+ #
99
+ # Translations can contain interpolation variables which will be replaced by
100
+ # values passed to #translate as part of the options hash, with the keys matching
101
+ # the interpolation variable names.
102
+ #
103
+ # <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
104
+ # value for the key +bar+ will be interpolated into the translation:
105
+ # I18n.t :foo, :bar => 'baz' # => 'foo baz'
106
+ #
107
+ # *PLURALIZATION*
108
+ #
109
+ # Translation data can contain pluralized translations. Pluralized translations
110
+ # are arrays of singluar/plural versions of translations like <tt>['Foo', 'Foos']</tt>.
111
+ #
112
+ # Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
113
+ # pluralization rules. Other algorithms can be supported by custom backends.
114
+ #
115
+ # This returns the singular version of a pluralized translation:
116
+ # I18n.t :foo, :count => 1 # => 'Foo'
117
+ #
118
+ # These both return the plural version of a pluralized translation:
119
+ # I18n.t :foo, :count => 0 # => 'Foos'
120
+ # I18n.t :foo, :count => 2 # => 'Foos'
121
+ #
122
+ # The <tt>:count</tt> option can be used both for pluralization and interpolation.
123
+ # <em>E.g.</em>, with the translation
124
+ # <tt>:foo => ['{{count}} foo', '{{count}} foos']</tt>, count will
125
+ # be interpolated to the pluralized translation:
126
+ # I18n.t :foo, :count => 1 # => '1 foo'
127
+ #
128
+ # *DEFAULTS*
129
+ #
130
+ # This returns the translation for <tt>:foo</tt> or <tt>default</tt> if no translation was found:
131
+ # I18n.t :foo, :default => 'default'
132
+ #
133
+ # This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
134
+ # translation for <tt>:foo</tt> was found:
135
+ # I18n.t :foo, :default => :bar
136
+ #
137
+ # Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
138
+ # or <tt>default</tt> if no translations for <tt>:foo</tt> and <tt>:bar</tt> were found.
139
+ # I18n.t :foo, :default => [:bar, 'default']
140
+ #
141
+ # <b>BULK LOOKUP</b>
142
+ #
143
+ # This returns an array with the translations for <tt>:foo</tt> and <tt>:bar</tt>.
144
+ # I18n.t [:foo, :bar]
145
+ #
146
+ # Can be used with dot-separated nested keys:
147
+ # I18n.t [:'baz.foo', :'baz.bar']
148
+ #
149
+ # Which is the same as using a scope option:
150
+ # I18n.t [:foo, :bar], :scope => :baz
151
+ def translate(key, options = {})
152
+ locale = options.delete(:locale) || I18n.locale
153
+ backend.translate locale, key, options
154
+ rescue I18n::ArgumentError => e
155
+ raise e if options[:raise]
156
+ send @@exception_handler, e, locale, key, options
157
+ end
158
+ alias :t :translate
159
+
160
+ # Localizes certain objects, such as dates and numbers to local formatting.
161
+ def localize(object, options = {})
162
+ locale = options[:locale] || I18n.locale
163
+ format = options[:format] || :default
164
+ backend.localize(locale, object, format)
165
+ end
166
+ alias :l :localize
167
+
168
+ protected
169
+ # Handles exceptions raised in the backend. All exceptions except for
170
+ # MissingTranslationData exceptions are re-raised. When a MissingTranslationData
171
+ # was caught and the option :raise is not set the handler returns an error
172
+ # message string containing the key/scope.
173
+ def default_exception_handler(exception, locale, key, options)
174
+ return exception.message if MissingTranslationData === exception
175
+ raise exception
176
+ end
177
+
178
+ # Merges the given locale, key and scope into a single array of keys.
179
+ # Splits keys that contain dots into multiple keys. Makes sure all
180
+ # keys are Symbols.
181
+ def normalize_translation_keys(locale, key, scope)
182
+ keys = [locale] + Array(scope) + [key]
183
+ keys = keys.map{|k| k.to_s.split(/\./) }
184
+ keys.flatten.map{|k| k.to_sym}
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,212 @@
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
+ protected
73
+
74
+ def init_translations
75
+ load_translations(*I18n.load_path)
76
+ @initialized = true
77
+ end
78
+
79
+ def translations
80
+ @translations ||= {}
81
+ end
82
+
83
+ # Looks up a translation from the translations hash. Returns nil if
84
+ # eiher key is nil, or locale, scope or key do not exist as a key in the
85
+ # nested translations hash. Splits keys or scopes containing dots
86
+ # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
87
+ # <tt>%w(currency format)</tt>.
88
+ def lookup(locale, key, scope = [])
89
+ return unless key
90
+ init_translations unless initialized?
91
+ keys = I18n.send :normalize_translation_keys, locale, key, scope
92
+ keys.inject(translations) do |result, k|
93
+ if (x = result[k.to_sym]).nil?
94
+ return nil
95
+ else
96
+ x
97
+ end
98
+ end
99
+ end
100
+
101
+ # Evaluates a default translation.
102
+ # If the given default is a String it is used literally. If it is a Symbol
103
+ # it will be translated with the given options. If it is an Array the first
104
+ # translation yielded will be returned.
105
+ #
106
+ # <em>I.e.</em>, <tt>default(locale, [:foo, 'default'])</tt> will return +default+ if
107
+ # <tt>translate(locale, :foo)</tt> does not yield a result.
108
+ def default(locale, default, options = {})
109
+ case default
110
+ when String then default
111
+ when Symbol then translate locale, default, options
112
+ when Array then default.each do |obj|
113
+ result = default(locale, obj, options.dup) and return result
114
+ end and nil
115
+ end
116
+ rescue MissingTranslationData
117
+ nil
118
+ end
119
+
120
+ # Picks a translation from an array according to English pluralization
121
+ # rules. It will pick the first translation if count is not equal to 1
122
+ # and the second translation if it is equal to 1. Other backends can
123
+ # implement more flexible or complex pluralization rules.
124
+ def pluralize(locale, entry, count)
125
+ return entry unless entry.is_a?(Hash) and count
126
+ # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash)
127
+ key = :zero if count == 0 && entry.has_key?(:zero)
128
+ key ||= count == 1 ? :one : :other
129
+ raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
130
+ entry[key]
131
+ end
132
+
133
+ # Interpolates values into a given string.
134
+ #
135
+ # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
136
+ # # => "file test.txt opened by {{user}}"
137
+ #
138
+ # Note that you have to double escape the <tt>\\</tt> when you want to escape
139
+ # the <tt>{{...}}</tt> key in a string (once for the string and once for the
140
+ # interpolation).
141
+ def interpolate(locale, string, values = {})
142
+ return string unless string.is_a?(String)
143
+
144
+ if string.respond_to?(:force_encoding)
145
+ original_encoding = string.encoding
146
+ string.force_encoding(Encoding::BINARY)
147
+ end
148
+
149
+ result = string.gsub(MATCH) do
150
+ escaped, pattern, key = $1, $2, $2.to_sym
151
+
152
+ if escaped
153
+ pattern
154
+ elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
155
+ raise ReservedInterpolationKey.new(pattern, string)
156
+ elsif !values.include?(key)
157
+ raise MissingInterpolationArgument.new(pattern, string)
158
+ else
159
+ values[key].to_s
160
+ end
161
+ end
162
+
163
+ result.force_encoding(original_encoding) if original_encoding
164
+ result
165
+ end
166
+
167
+ # Loads a single translations file by delegating to #load_rb or
168
+ # #load_yml depending on the file extension and directly merges the
169
+ # data to the existing translations. Raises I18n::UnknownFileType
170
+ # for all other file extensions.
171
+ def load_file(filename)
172
+ type = File.extname(filename).tr('.', '').downcase
173
+ raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}"
174
+ data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash
175
+ data.each{|locale, d| merge_translations locale, d }
176
+ end
177
+
178
+ # Loads a plain Ruby translations file. eval'ing the file must yield
179
+ # a Hash containing translation data with locales as toplevel keys.
180
+ def load_rb(filename)
181
+ eval IO.read(filename), binding, filename
182
+ end
183
+
184
+ # Loads a YAML translations file. The data must have locales as
185
+ # toplevel keys.
186
+ def load_yml(filename)
187
+ YAML::load IO.read(filename)
188
+ end
189
+
190
+ # Deep merges the given translations hash with the existing translations
191
+ # for the given locale
192
+ def merge_translations(locale, data)
193
+ locale = locale.to_sym
194
+ translations[locale] ||= {}
195
+ data = deep_symbolize_keys data
196
+
197
+ # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
198
+ merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
199
+ translations[locale].merge! data, &merger
200
+ end
201
+
202
+ # Return a new hash with all keys and nested keys converted to symbols.
203
+ def deep_symbolize_keys(hash)
204
+ hash.inject({}){|result, (key, value)|
205
+ value = deep_symbolize_keys(value) if value.is_a? Hash
206
+ result[(key.to_sym rescue key) || key] = value
207
+ result
208
+ }
209
+ end
210
+ end
211
+ end
212
+ 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/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,473 @@
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
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: josevalim-i18n
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Sven Fuchs
8
+ - Matt Aimonetti
9
+ - Stephan Soller
10
+ - Saimon Moore
11
+ autorequire:
12
+ bindir: bin
13
+ cert_chain: []
14
+
15
+ date: 2009-02-18 00:00:00 -08:00
16
+ default_executable:
17
+ dependencies: []
18
+
19
+ description: Add Internationalization to your Ruby application.
20
+ email: rails-i18n@googlegroups.com
21
+ executables: []
22
+
23
+ extensions: []
24
+
25
+ extra_rdoc_files: []
26
+
27
+ files:
28
+ - lib/i18n/backend/simple.rb
29
+ - lib/i18n/exceptions.rb
30
+ - lib/i18n.rb
31
+ - MIT-LICENSE
32
+ - README.textile
33
+ - test/all.rb
34
+ - test/i18n_exceptions_test.rb
35
+ - test/i18n_test.rb
36
+ - test/locale/en-US.rb
37
+ - test/locale/en-US.yml
38
+ - test/simple_backend_test.rb
39
+ has_rdoc: false
40
+ homepage: http://groups.google.com/group/rails-i18n
41
+ post_install_message:
42
+ rdoc_options: []
43
+
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: "0"
51
+ version:
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ version:
58
+ requirements: []
59
+
60
+ rubyforge_project:
61
+ rubygems_version: 1.2.0
62
+ signing_key:
63
+ specification_version: 2
64
+ summary: Internationalization (i18n) for Ruby
65
+ test_files: []
66
+