josevalim-i18n 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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
+