i18n 0.1.0

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

Potentially problematic release.


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

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,192 @@
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
+ @@default_locale = 'en-US'
14
+ @@exception_handler = :default_exception_handler
15
+
16
+ class << self
17
+ # Returns the current backend. Defaults to +Backend::Simple+.
18
+ def backend
19
+ @@backend ||= Backend::Simple.new
20
+ end
21
+
22
+ # Sets the current backend. Used to set a custom backend.
23
+ def backend=(backend)
24
+ @@backend = backend
25
+ end
26
+
27
+ # Returns the current default locale. Defaults to 'en-US'
28
+ def default_locale
29
+ @@default_locale
30
+ end
31
+
32
+ # Sets the current default locale. Used to set a custom default locale.
33
+ def default_locale=(locale)
34
+ @@default_locale = locale
35
+ end
36
+
37
+ # Returns the current locale. Defaults to I18n.default_locale.
38
+ def locale
39
+ Thread.current[:locale] ||= default_locale
40
+ end
41
+
42
+ # Sets the current locale pseudo-globally, i.e. in the Thread.current hash.
43
+ def locale=(locale)
44
+ Thread.current[:locale] = locale
45
+ end
46
+
47
+ # Sets the exception handler.
48
+ def exception_handler=(exception_handler)
49
+ @@exception_handler = exception_handler
50
+ end
51
+
52
+ # Allow client libraries to pass a block that populates the translation
53
+ # storage. Decoupled for backends like a db backend that persist their
54
+ # translations, so the backend can decide whether/when to yield or not.
55
+ def populate(&block)
56
+ backend.populate(&block)
57
+ end
58
+
59
+ # Allows client libraries to pass arguments that specify a source for
60
+ # translation data to be loaded by the backend. The backend defines
61
+ # acceptable sources.
62
+ # E.g. the provided SimpleBackend accepts a list of paths to translation
63
+ # files which are either named *.rb and contain plain Ruby Hashes or are
64
+ # named *.yml and contain YAML data.)
65
+ def load_translations(*args)
66
+ backend.load_translations(*args)
67
+ end
68
+
69
+ # Stores translations for the given locale in the backend.
70
+ def store_translations(locale, data)
71
+ backend.store_translations locale, data
72
+ end
73
+
74
+ # Translates, pluralizes and interpolates a given key using a given locale,
75
+ # scope, and default, as well as interpolation values.
76
+ #
77
+ # *LOOKUP*
78
+ #
79
+ # Translation data is organized as a nested hash using the upper-level keys
80
+ # as namespaces. <em>E.g.</em>, ActionView ships with the translation:
81
+ # <tt>:date => {:formats => {:short => "%b %d"}}</tt>.
82
+ #
83
+ # Translations can be looked up at any level of this hash using the key argument
84
+ # and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
85
+ # returns the whole translations hash <tt>{:formats => {:short => "%b %d"}}</tt>.
86
+ #
87
+ # Key can be either a single key or a dot-separated key (both Strings and Symbols
88
+ # work). <em>E.g.</em>, the short format can be looked up using both:
89
+ # I18n.t 'date.formats.short'
90
+ # I18n.t :'date.formats.short'
91
+ #
92
+ # Scope can be either a single key, a dot-separated key or an array of keys
93
+ # or dot-separated keys. Keys and scopes can be combined freely. So these
94
+ # examples will all look up the same short date format:
95
+ # I18n.t 'date.formats.short'
96
+ # I18n.t 'formats.short', :scope => 'date'
97
+ # I18n.t 'short', :scope => 'date.formats'
98
+ # I18n.t 'short', :scope => %w(date formats)
99
+ #
100
+ # *INTERPOLATION*
101
+ #
102
+ # Translations can contain interpolation variables which will be replaced by
103
+ # values passed to #translate as part of the options hash, with the keys matching
104
+ # the interpolation variable names.
105
+ #
106
+ # <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
107
+ # value for the key +bar+ will be interpolated into the translation:
108
+ # I18n.t :foo, :bar => 'baz' # => 'foo baz'
109
+ #
110
+ # *PLURALIZATION*
111
+ #
112
+ # Translation data can contain pluralized translations. Pluralized translations
113
+ # are arrays of singluar/plural versions of translations like <tt>['Foo', 'Foos']</tt>.
114
+ #
115
+ # Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
116
+ # pluralization rules. Other algorithms can be supported by custom backends.
117
+ #
118
+ # This returns the singular version of a pluralized translation:
119
+ # I18n.t :foo, :count => 1 # => 'Foo'
120
+ #
121
+ # These both return the plural version of a pluralized translation:
122
+ # I18n.t :foo, :count => 0 # => 'Foos'
123
+ # I18n.t :foo, :count => 2 # => 'Foos'
124
+ #
125
+ # The <tt>:count</tt> option can be used both for pluralization and interpolation.
126
+ # <em>E.g.</em>, with the translation
127
+ # <tt>:foo => ['{{count}} foo', '{{count}} foos']</tt>, count will
128
+ # be interpolated to the pluralized translation:
129
+ # I18n.t :foo, :count => 1 # => '1 foo'
130
+ #
131
+ # *DEFAULTS*
132
+ #
133
+ # This returns the translation for <tt>:foo</tt> or <tt>default</tt> if no translation was found:
134
+ # I18n.t :foo, :default => 'default'
135
+ #
136
+ # This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
137
+ # translation for <tt>:foo</tt> was found:
138
+ # I18n.t :foo, :default => :bar
139
+ #
140
+ # Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
141
+ # or <tt>default</tt> if no translations for <tt>:foo</tt> and <tt>:bar</tt> were found.
142
+ # I18n.t :foo, :default => [:bar, 'default']
143
+ #
144
+ # <b>BULK LOOKUP</b>
145
+ #
146
+ # This returns an array with the translations for <tt>:foo</tt> and <tt>:bar</tt>.
147
+ # I18n.t [:foo, :bar]
148
+ #
149
+ # Can be used with dot-separated nested keys:
150
+ # I18n.t [:'baz.foo', :'baz.bar']
151
+ #
152
+ # Which is the same as using a scope option:
153
+ # I18n.t [:foo, :bar], :scope => :baz
154
+ def translate(key, options = {})
155
+ locale = options.delete(:locale) || I18n.locale
156
+ backend.translate locale, key, options
157
+ rescue I18n::ArgumentError => e
158
+ raise e if options[:raise]
159
+ send @@exception_handler, e, locale, key, options
160
+ end
161
+ alias :t :translate
162
+
163
+ # Localizes certain objects, such as dates and numbers to local formatting.
164
+ def localize(object, options = {})
165
+ locale = options[:locale] || I18n.locale
166
+ format = options[:format] || :default
167
+ backend.localize(locale, object, format)
168
+ end
169
+ alias :l :localize
170
+
171
+ protected
172
+ # Handles exceptions raised in the backend. All exceptions except for
173
+ # MissingTranslationData exceptions are re-raised. When a MissingTranslationData
174
+ # was caught and the option :raise is not set the handler returns an error
175
+ # message string containing the key/scope.
176
+ def default_exception_handler(exception, locale, key, options)
177
+ return exception.message if MissingTranslationData === exception
178
+ raise exception
179
+ end
180
+
181
+ # Merges the given locale, key and scope into a single array of keys.
182
+ # Splits keys that contain dots into multiple keys. Makes sure all
183
+ # keys are Symbols.
184
+ def normalize_translation_keys(locale, key, scope)
185
+ keys = [locale] + Array(scope) + [key]
186
+ keys = keys.map{|k| k.to_s.split(/\./) }
187
+ keys.flatten.map{|k| k.to_sym}
188
+ end
189
+ end
190
+ end
191
+
192
+
@@ -0,0 +1,193 @@
1
+ require 'strscan'
2
+
3
+ module I18n
4
+ module Backend
5
+ class Simple
6
+ # Allow client libraries to pass a block that populates the translation
7
+ # storage. Decoupled for backends like a db backend that persist their
8
+ # translations, so the backend can decide whether/when to yield or not.
9
+ def populate(&block)
10
+ yield
11
+ end
12
+
13
+ # Accepts a list of paths to translation files. Loads translations from
14
+ # plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
15
+ # for details.
16
+ def load_translations(*filenames)
17
+ filenames.each {|filename| load_file filename }
18
+ end
19
+
20
+ # Stores translations for the given locale in memory.
21
+ # This uses a deep merge for the translations hash, so existing
22
+ # translations will be overwritten by new ones only at the deepest
23
+ # level of the hash.
24
+ def store_translations(locale, data)
25
+ merge_translations(locale, data)
26
+ end
27
+
28
+ def translate(locale, key, options = {})
29
+ raise InvalidLocale.new(locale) if locale.nil?
30
+ return key.map{|k| translate locale, k, options } if key.is_a? Array
31
+
32
+ reserved = :scope, :default
33
+ count, scope, default = options.values_at(:count, *reserved)
34
+ options.delete(:default)
35
+ values = options.reject{|name, value| reserved.include? name }
36
+
37
+ entry = lookup(locale, key, scope) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options))
38
+ entry = pluralize locale, entry, count
39
+ entry = interpolate locale, entry, values
40
+ entry
41
+ end
42
+
43
+ # Acts the same as +strftime+, but returns a localized version of the
44
+ # formatted date string. Takes a key from the date/time formats
45
+ # translations as a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
46
+ def localize(locale, object, format = :default)
47
+ raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
48
+
49
+ type = object.respond_to?(:sec) ? 'time' : 'date'
50
+ formats = translate(locale, :"#{type}.formats")
51
+ format = formats[format.to_sym] if formats && formats[format.to_sym]
52
+ # TODO raise exception unless format found?
53
+ format = format.to_s.dup
54
+
55
+ format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
56
+ format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
57
+ format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
58
+ format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
59
+ format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
60
+ object.strftime(format)
61
+ end
62
+
63
+ protected
64
+
65
+ def translations
66
+ @translations ||= {}
67
+ end
68
+
69
+ # Looks up a translation from the translations hash. Returns nil if
70
+ # eiher key is nil, or locale, scope or key do not exist as a key in the
71
+ # nested translations hash. Splits keys or scopes containing dots
72
+ # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
73
+ # <tt>%w(currency format)</tt>.
74
+ def lookup(locale, key, scope = [])
75
+ return unless key
76
+ keys = I18n.send :normalize_translation_keys, locale, key, scope
77
+ keys.inject(translations){|result, k| result[k.to_sym] or return nil }
78
+ end
79
+
80
+ # Evaluates a default translation.
81
+ # If the given default is a String it is used literally. If it is a Symbol
82
+ # it will be translated with the given options. If it is an Array the first
83
+ # translation yielded will be returned.
84
+ #
85
+ # <em>I.e.</em>, <tt>default(locale, [:foo, 'default'])</tt> will return +default+ if
86
+ # <tt>translate(locale, :foo)</tt> does not yield a result.
87
+ def default(locale, default, options = {})
88
+ case default
89
+ when String then default
90
+ when Symbol then translate locale, default, options
91
+ when Array then default.each do |obj|
92
+ result = default(locale, obj, options.dup) and return result
93
+ end and nil
94
+ end
95
+ rescue MissingTranslationData
96
+ nil
97
+ end
98
+
99
+ # Picks a translation from an array according to English pluralization
100
+ # rules. It will pick the first translation if count is not equal to 1
101
+ # and the second translation if it is equal to 1. Other backends can
102
+ # implement more flexible or complex pluralization rules.
103
+ def pluralize(locale, entry, count)
104
+ return entry unless entry.is_a?(Hash) and count
105
+ # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash)
106
+ key = :zero if count == 0 && entry.has_key?(:zero)
107
+ key ||= count == 1 ? :one : :other
108
+ raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
109
+ entry[key]
110
+ end
111
+
112
+ # Interpolates values into a given string.
113
+ #
114
+ # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
115
+ # # => "file test.txt opened by {{user}}"
116
+ #
117
+ # Note that you have to double escape the <tt>\\</tt> when you want to escape
118
+ # the <tt>{{...}}</tt> key in a string (once for the string and once for the
119
+ # interpolation).
120
+ def interpolate(locale, string, values = {})
121
+ return string if !string.is_a?(String)
122
+
123
+ string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}')
124
+ if string.respond_to?(:force_encoding)
125
+ original_encoding = string.encoding
126
+ string.force_encoding(Encoding::BINARY)
127
+ end
128
+ s = StringScanner.new(string)
129
+
130
+ while s.skip_until(/\{\{/)
131
+ s.string[s.pos - 3, 1] = '' and next if s.pre_match[-1, 1] == '\\'
132
+ start_pos = s.pos - 2
133
+ key = s.scan_until(/\}\}/)[0..-3]
134
+ end_pos = s.pos - 1
135
+
136
+ raise ReservedInterpolationKey.new(key, string) if %w(scope default).include?(key)
137
+ raise MissingInterpolationArgument.new(key, string) unless values.has_key? key.to_sym
138
+
139
+ s.string[start_pos..end_pos] = values[key.to_sym].to_s
140
+ s.unscan
141
+ end
142
+
143
+ result = s.string
144
+ result.force_encoding(original_encoding) if original_encoding
145
+ result
146
+ end
147
+
148
+ # Loads a single translations file by delegating to #load_rb or
149
+ # #load_yml depending on the file extension and directly merges the
150
+ # data to the existing translations. Raises I18n::UnknownFileType
151
+ # for all other file extensions.
152
+ def load_file(filename)
153
+ type = File.extname(filename).tr('.', '').downcase
154
+ raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}"
155
+ data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash
156
+ data.each{|locale, d| merge_translations locale, d }
157
+ end
158
+
159
+ # Loads a plain Ruby translations file. eval'ing the file must yield
160
+ # a Hash containing translation data with locales as toplevel keys.
161
+ def load_rb(filename)
162
+ eval IO.read(filename), binding, filename
163
+ end
164
+
165
+ # Loads a YAML translations file. The data must have locales as
166
+ # toplevel keys.
167
+ def load_yml(filename)
168
+ YAML::load IO.read(filename)
169
+ end
170
+
171
+ # Deep merges the given translations hash with the existing translations
172
+ # for the given locale
173
+ def merge_translations(locale, data)
174
+ locale = locale.to_sym
175
+ translations[locale] ||= {}
176
+ data = deep_symbolize_keys data
177
+
178
+ # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
179
+ merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
180
+ translations[locale].merge! data, &merger
181
+ end
182
+
183
+ # Return a new hash with all keys and nested keys converted to symbols.
184
+ def deep_symbolize_keys(hash)
185
+ hash.inject({}){|result, (key, value)|
186
+ value = deep_symbolize_keys(value) if value.is_a? Hash
187
+ result[(key.to_sym rescue key) || key] = value
188
+ result
189
+ }
190
+ end
191
+ end
192
+ end
193
+ 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.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.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.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.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,141 @@
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.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_delegates_store_translations_to_backend
75
+ I18n.backend.expects(:store_translations).with 'de-DE', {:foo => :bar}
76
+ I18n.store_translations 'de-DE', {:foo => :bar}
77
+ end
78
+
79
+ def test_delegates_populate_to_backend
80
+ I18n.backend.expects(:populate) # can't specify a block here as an expected argument
81
+ I18n.populate{ }
82
+ end
83
+
84
+ def test_populate_yields_the_block
85
+ tmp = nil
86
+ I18n.populate do tmp = 'yielded' end
87
+ assert_equal 'yielded', tmp
88
+ end
89
+
90
+ def test_translate_given_no_locale_uses_i18n_locale
91
+ I18n.backend.expects(:translate).with 'en-US', :foo, {}
92
+ I18n.translate :foo
93
+ end
94
+
95
+ def test_translate_on_nested_symbol_keys_works
96
+ assert_equal ".", I18n.t(:'currency.format.separator')
97
+ end
98
+
99
+ def test_translate_with_nested_string_keys_works
100
+ assert_equal ".", I18n.t('currency.format.separator')
101
+ end
102
+
103
+ def test_translate_with_array_as_scope_works
104
+ assert_equal ".", I18n.t(:separator, :scope => ['currency.format'])
105
+ end
106
+
107
+ def test_translate_with_array_containing_dot_separated_strings_as_scope_works
108
+ assert_equal ".", I18n.t(:separator, :scope => ['currency.format'])
109
+ end
110
+
111
+ def test_translate_with_key_array_and_dot_separated_scope_works
112
+ assert_equal [".", ","], I18n.t(%w(separator delimiter), :scope => 'currency.format')
113
+ end
114
+
115
+ def test_translate_with_dot_separated_key_array_and_scope_works
116
+ assert_equal [".", ","], I18n.t(%w(format.separator format.delimiter), :scope => 'currency')
117
+ end
118
+
119
+ def test_translate_with_options_using_scope_works
120
+ I18n.backend.expects(:translate).with('de-DE', :precision, :scope => :"currency.format")
121
+ I18n.with_options :locale => 'de-DE', :scope => :'currency.format' do |locale|
122
+ locale.t :precision
123
+ end
124
+ end
125
+
126
+ # def test_translate_given_no_args_raises_missing_translation_data
127
+ # assert_equal "translation missing: en-US, no key", I18n.t
128
+ # end
129
+
130
+ def test_translate_given_a_bogus_key_raises_missing_translation_data
131
+ assert_equal "translation missing: en-US, bogus", I18n.t(:bogus)
132
+ end
133
+
134
+ def test_localize_nil_raises_argument_error
135
+ assert_raises(I18n::ArgumentError) { I18n.l nil }
136
+ end
137
+
138
+ def test_localize_object_raises_argument_error
139
+ assert_raises(I18n::ArgumentError) { I18n.l Object.new }
140
+ end
141
+ 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: i18n
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
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: 2008-06-13 00:00:00 +02:00
16
+ default_executable:
17
+ dependencies: []
18
+
19
+ description: Add Internationalization to your Ruby application.
20
+ email: rails-patch-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-patch-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 for Ruby
65
+ test_files: []
66
+