yaroslav-russian 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/lib/russian.rb ADDED
@@ -0,0 +1,91 @@
1
+ $KCODE='u'
2
+
3
+ $:.push File.join(File.dirname(__FILE__), 'russian')
4
+ $:.push File.join(File.dirname(__FILE__), 'vendor', 'i18n', 'lib')
5
+
6
+ require 'i18n' unless defined?(I18n)
7
+
8
+ require 'backend/advanced'
9
+ require 'action_view_ext/helpers/date_helper'
10
+ require 'active_record_ext/custom_error_message'
11
+
12
+ module Russian
13
+ module VERSION
14
+ MAJOR = 0
15
+ MINOR = 0
16
+ TINY = 1
17
+
18
+ STRING = [MAJOR, MINOR, TINY].join('.')
19
+ end
20
+
21
+ # Russian locale
22
+ LOCALE = :'ru-RU'
23
+
24
+ class << self
25
+ # Russian locale
26
+ def locale
27
+ LOCALE
28
+ end
29
+
30
+ # Returns custom backend class for usage with Russian library
31
+ #
32
+ # See I18n::Backend
33
+ def i18n_backend_class
34
+ I18n::Backend::Advanced
35
+ end
36
+
37
+ # Init Russian i18n: set custom backend, set default locale to Russian locale, load all translations
38
+ # shipped with library.
39
+ def init_i18n
40
+ I18n.backend = Russian.i18n_backend_class.new
41
+ I18n.default_locale = LOCALE
42
+ locale_files.each { |file| I18n.backend.load_translations(file) }
43
+ end
44
+
45
+ # See I18n::translate
46
+ def translate(key, options = {})
47
+ I18n.translate(key, options.merge({ :locale => LOCALE }))
48
+ end
49
+ alias :t :translate
50
+
51
+ # See I18n::localize
52
+ def localize(object, options = {})
53
+ I18n.localize(object, options.merge({ :locale => LOCALE }))
54
+ end
55
+ alias :l :localize
56
+
57
+ # strftime() proxy with Russian localization
58
+ def strftime(object, format = :default)
59
+ localize(object, { :format => format })
60
+ end
61
+
62
+ # Simple pluralization proxy
63
+ #
64
+ # Usage:
65
+ # Russian.pluralize(1, "вещь", "вещи", "вещей")
66
+ def pluralize(n, *variants)
67
+ variants_hash = pluralization_variants_to_hash(*variants)
68
+ I18n.backend.send(:pluralize, LOCALE, variants_hash, n)
69
+ end
70
+
71
+ protected
72
+ # Returns all locale files shipped with library
73
+ def locale_files
74
+ Dir[File.join(File.dirname(__FILE__), "russian", "locale", "**/*")]
75
+ end
76
+
77
+ # Converts an array of pluralization variants (3 entries) to a Hash that can be used
78
+ # with I18n pluralization.
79
+ def pluralization_variants_to_hash(*variants)
80
+ raise ArgumentError, "Must have at least 3 variants for pluralization" if variants.size < 3
81
+ {
82
+ :one => variants[0],
83
+ :few => variants[1],
84
+ :many => variants[2],
85
+ :other => variants[1]
86
+ }
87
+ end
88
+ end
89
+ end
90
+
91
+ Russian.init_i18n
@@ -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.
@@ -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
+
@@ -0,0 +1,24 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "i18n"
3
+ s.version = "0.0.1"
4
+ s.date = "2008-06-13"
5
+ s.summary = "Internationalization for Ruby"
6
+ s.email = "rails-patch-i18n@googlegroups.com"
7
+ s.homepage = "http://groups.google.com/group/rails-patch-i18n"
8
+ s.description = "Add Internationalization to your Ruby application."
9
+ s.has_rdoc = false
10
+ s.authors = ['Sven Fuchs', 'Matt Aimonetti', 'Stephan Soller', 'Saimon Moore']
11
+ s.files = [
12
+ "lib/i18n/backend/minimal.rb",
13
+ "lib/i18n/core_ext.rb",
14
+ "lib/i18n/localization.rb",
15
+ "lib/i18n/translation.rb",
16
+ "lib/i18n.rb",
17
+ "LICENSE",
18
+ "README",
19
+ "spec/core_ext_spec.rb",
20
+ "spec/i18n_spec.rb",
21
+ "spec/spec.opts",
22
+ "spec/spec_helper.rb"
23
+ ]
24
+ end
@@ -0,0 +1,192 @@
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) || default(locale, default, options) || raise(I18n::MissingTranslationData.new(locale, key, options))
34
+ entry = pluralize locale, entry, count
35
+ entry = interpolate locale, entry, values
36
+ entry
37
+ end
38
+
39
+ # Acts the same as +strftime+, but returns a localized version of the
40
+ # formatted date string. Takes a key from the date/time formats
41
+ # translations as a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
42
+ def localize(locale, object, format = :default)
43
+ raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
44
+
45
+ type = object.respond_to?(:sec) ? 'time' : 'date'
46
+ # TODO only translate these if format is a String?
47
+ formats = translate(locale, :"#{type}.formats")
48
+ format = formats[format.to_sym] if formats && formats[format.to_sym]
49
+ # TODO raise exception unless format found?
50
+ format = format.to_s.dup
51
+
52
+ # TODO only translate these if the format string is actually present
53
+ # TODO check which format strings are present, then bulk translate then, then replace them
54
+ format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
55
+ format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
56
+ format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
57
+ format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
58
+ format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
59
+ object.strftime(format)
60
+ end
61
+
62
+ protected
63
+
64
+ def translations
65
+ @translations ||= {}
66
+ end
67
+
68
+ # Looks up a translation from the translations hash. Returns nil if
69
+ # eiher key is nil, or locale, scope or key do not exist as a key in the
70
+ # nested translations hash. Splits keys or scopes containing dots
71
+ # into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
72
+ # <tt>%w(currency format)</tt>.
73
+ def lookup(locale, key, scope = [])
74
+ return unless key
75
+ keys = I18n.send :normalize_translation_keys, locale, key, scope
76
+ keys.inject(translations){|result, k| result[k.to_sym] or return nil }
77
+ end
78
+
79
+ # Evaluates a default translation.
80
+ # If the given default is a String it is used literally. If it is a Symbol
81
+ # it will be translated with the given options. If it is an Array the first
82
+ # translation yielded will be returned.
83
+ #
84
+ # <em>I.e.</em>, <tt>default(locale, [:foo, 'default'])</tt> will return +default+ if
85
+ # <tt>translate(locale, :foo)</tt> does not yield a result.
86
+ def default(locale, default, options = {})
87
+ case default
88
+ when String then default
89
+ when Symbol then translate locale, default, options
90
+ when Array then default.each do |obj|
91
+ result = default(locale, obj, options.dup) and return result
92
+ end and nil
93
+ end
94
+ rescue MissingTranslationData
95
+ nil
96
+ end
97
+
98
+ # Picks a translation from an array according to English pluralization
99
+ # rules. It will pick the first translation if count is not equal to 1
100
+ # and the second translation if it is equal to 1. Other backends can
101
+ # implement more flexible or complex pluralization rules.
102
+ def pluralize(locale, entry, count)
103
+ return entry unless entry.is_a?(Hash) and count
104
+ # raise InvalidPluralizationData.new(entry, count) unless entry.is_a?(Hash)
105
+ key = :zero if count == 0 && entry.has_key?(:zero)
106
+ key ||= count == 1 ? :one : :other
107
+ raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
108
+ entry[key]
109
+ end
110
+
111
+ # Interpolates values into a given string.
112
+ #
113
+ # interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
114
+ # # => "file test.txt opened by {{user}}"
115
+ #
116
+ # Note that you have to double escape the <tt>\\</tt> when you want to escape
117
+ # the <tt>{{...}}</tt> key in a string (once for the string and once for the
118
+ # interpolation).
119
+ def interpolate(locale, string, values = {})
120
+ return string unless string.is_a?(String)
121
+
122
+ string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}')
123
+
124
+ if string.respond_to?(:force_encoding)
125
+ original_encoding = string.encoding
126
+ string.force_encoding(Encoding::BINARY)
127
+ end
128
+
129
+ result = string.gsub(MATCH) do
130
+ escaped, pattern, key = $1, $2, $2.to_sym
131
+
132
+ if escaped
133
+ pattern
134
+ elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
135
+ raise ReservedInterpolationKey.new(pattern, string)
136
+ elsif !values.include?(key)
137
+ raise MissingInterpolationArgument.new(pattern, string)
138
+ else
139
+ values[key].to_s
140
+ end
141
+ end
142
+
143
+ result.force_encoding(original_encoding) if original_encoding
144
+ result
145
+ end
146
+
147
+ # Loads a single translations file by delegating to #load_rb or
148
+ # #load_yml depending on the file extension and directly merges the
149
+ # data to the existing translations. Raises I18n::UnknownFileType
150
+ # for all other file extensions.
151
+ def load_file(filename)
152
+ type = File.extname(filename).tr('.', '').downcase
153
+ raise UnknownFileType.new(type, filename) unless respond_to? :"load_#{type}"
154
+ data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash
155
+ data.each{|locale, d| merge_translations locale, d }
156
+ end
157
+
158
+ # Loads a plain Ruby translations file. eval'ing the file must yield
159
+ # a Hash containing translation data with locales as toplevel keys.
160
+ def load_rb(filename)
161
+ eval IO.read(filename), binding, filename
162
+ end
163
+
164
+ # Loads a YAML translations file. The data must have locales as
165
+ # toplevel keys.
166
+ def load_yml(filename)
167
+ YAML::load IO.read(filename)
168
+ end
169
+
170
+ # Deep merges the given translations hash with the existing translations
171
+ # for the given locale
172
+ def merge_translations(locale, data)
173
+ locale = locale.to_sym
174
+ translations[locale] ||= {}
175
+ data = deep_symbolize_keys data
176
+
177
+ # deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
178
+ merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
179
+ translations[locale].merge! data, &merger
180
+ end
181
+
182
+ # Return a new hash with all keys and nested keys converted to symbols.
183
+ def deep_symbolize_keys(hash)
184
+ hash.inject({}){|result, (key, value)|
185
+ value = deep_symbolize_keys(value) if value.is_a? Hash
186
+ result[(key.to_sym rescue key) || key] = value
187
+ result
188
+ }
189
+ end
190
+ end
191
+ end
192
+ 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
@@ -0,0 +1,180 @@
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
+ # Allows client libraries to pass arguments that specify a source for
53
+ # translation data to be loaded by the backend. The backend defines
54
+ # acceptable sources.
55
+ # E.g. the provided SimpleBackend accepts a list of paths to translation
56
+ # files which are either named *.rb and contain plain Ruby Hashes or are
57
+ # named *.yml and contain YAML data.)
58
+ def load_translations(*args)
59
+ backend.load_translations(*args)
60
+ end
61
+
62
+ # Translates, pluralizes and interpolates a given key using a given locale,
63
+ # scope, and default, as well as interpolation values.
64
+ #
65
+ # *LOOKUP*
66
+ #
67
+ # Translation data is organized as a nested hash using the upper-level keys
68
+ # as namespaces. <em>E.g.</em>, ActionView ships with the translation:
69
+ # <tt>:date => {:formats => {:short => "%b %d"}}</tt>.
70
+ #
71
+ # Translations can be looked up at any level of this hash using the key argument
72
+ # and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
73
+ # returns the whole translations hash <tt>{:formats => {:short => "%b %d"}}</tt>.
74
+ #
75
+ # Key can be either a single key or a dot-separated key (both Strings and Symbols
76
+ # work). <em>E.g.</em>, the short format can be looked up using both:
77
+ # I18n.t 'date.formats.short'
78
+ # I18n.t :'date.formats.short'
79
+ #
80
+ # Scope can be either a single key, a dot-separated key or an array of keys
81
+ # or dot-separated keys. Keys and scopes can be combined freely. So these
82
+ # examples will all look up the same short date format:
83
+ # I18n.t 'date.formats.short'
84
+ # I18n.t 'formats.short', :scope => 'date'
85
+ # I18n.t 'short', :scope => 'date.formats'
86
+ # I18n.t 'short', :scope => %w(date formats)
87
+ #
88
+ # *INTERPOLATION*
89
+ #
90
+ # Translations can contain interpolation variables which will be replaced by
91
+ # values passed to #translate as part of the options hash, with the keys matching
92
+ # the interpolation variable names.
93
+ #
94
+ # <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
95
+ # value for the key +bar+ will be interpolated into the translation:
96
+ # I18n.t :foo, :bar => 'baz' # => 'foo baz'
97
+ #
98
+ # *PLURALIZATION*
99
+ #
100
+ # Translation data can contain pluralized translations. Pluralized translations
101
+ # are arrays of singluar/plural versions of translations like <tt>['Foo', 'Foos']</tt>.
102
+ #
103
+ # Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
104
+ # pluralization rules. Other algorithms can be supported by custom backends.
105
+ #
106
+ # This returns the singular version of a pluralized translation:
107
+ # I18n.t :foo, :count => 1 # => 'Foo'
108
+ #
109
+ # These both return the plural version of a pluralized translation:
110
+ # I18n.t :foo, :count => 0 # => 'Foos'
111
+ # I18n.t :foo, :count => 2 # => 'Foos'
112
+ #
113
+ # The <tt>:count</tt> option can be used both for pluralization and interpolation.
114
+ # <em>E.g.</em>, with the translation
115
+ # <tt>:foo => ['{{count}} foo', '{{count}} foos']</tt>, count will
116
+ # be interpolated to the pluralized translation:
117
+ # I18n.t :foo, :count => 1 # => '1 foo'
118
+ #
119
+ # *DEFAULTS*
120
+ #
121
+ # This returns the translation for <tt>:foo</tt> or <tt>default</tt> if no translation was found:
122
+ # I18n.t :foo, :default => 'default'
123
+ #
124
+ # This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
125
+ # translation for <tt>:foo</tt> was found:
126
+ # I18n.t :foo, :default => :bar
127
+ #
128
+ # Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
129
+ # or <tt>default</tt> if no translations for <tt>:foo</tt> and <tt>:bar</tt> were found.
130
+ # I18n.t :foo, :default => [:bar, 'default']
131
+ #
132
+ # <b>BULK LOOKUP</b>
133
+ #
134
+ # This returns an array with the translations for <tt>:foo</tt> and <tt>:bar</tt>.
135
+ # I18n.t [:foo, :bar]
136
+ #
137
+ # Can be used with dot-separated nested keys:
138
+ # I18n.t [:'baz.foo', :'baz.bar']
139
+ #
140
+ # Which is the same as using a scope option:
141
+ # I18n.t [:foo, :bar], :scope => :baz
142
+ def translate(key, options = {})
143
+ locale = options.delete(:locale) || I18n.locale
144
+ backend.translate locale, key, options
145
+ rescue I18n::ArgumentError => e
146
+ raise e if options[:raise]
147
+ send @@exception_handler, e, locale, key, options
148
+ end
149
+ alias :t :translate
150
+
151
+ # Localizes certain objects, such as dates and numbers to local formatting.
152
+ def localize(object, options = {})
153
+ locale = options[:locale] || I18n.locale
154
+ format = options[:format] || :default
155
+ backend.localize(locale, object, format)
156
+ end
157
+ alias :l :localize
158
+
159
+ protected
160
+ # Handles exceptions raised in the backend. All exceptions except for
161
+ # MissingTranslationData exceptions are re-raised. When a MissingTranslationData
162
+ # was caught and the option :raise is not set the handler returns an error
163
+ # message string containing the key/scope.
164
+ def default_exception_handler(exception, locale, key, options)
165
+ return exception.message if MissingTranslationData === exception
166
+ raise exception
167
+ end
168
+
169
+ # Merges the given locale, key and scope into a single array of keys.
170
+ # Splits keys that contain dots into multiple keys. Makes sure all
171
+ # keys are Symbols.
172
+ def normalize_translation_keys(locale, key, scope)
173
+ keys = [locale] + Array(scope) + [key]
174
+ keys = keys.map{|k| k.to_s.split(/\./) }
175
+ keys.flatten.map{|k| k.to_sym}
176
+ end
177
+ end
178
+ end
179
+
180
+
@@ -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