russian 0.0.6 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +3 -3
- data/Rakefile +1 -1
- data/TODO +1 -0
- data/lib/russian.rb +1 -1
- data/lib/russian/locale/actionview.yml +0 -1
- data/lib/russian/locale/activerecord.yml +1 -1
- data/lib/russian/locale/activesupport.yml +1 -0
- data/lib/vendor/i18n/README.textile +2 -0
- data/lib/vendor/i18n/i18n.gemspec +21 -18
- data/lib/vendor/i18n/lib/i18n.rb +53 -44
- data/lib/vendor/i18n/lib/i18n/backend/simple.rb +70 -52
- data/lib/vendor/i18n/lib/i18n/exceptions.rb +3 -3
- data/lib/vendor/i18n/test/all.rb +1 -1
- data/lib/vendor/i18n/test/i18n_exceptions_test.rb +14 -14
- data/lib/vendor/i18n/test/i18n_test.rb +23 -23
- data/lib/vendor/i18n/test/simple_backend_test.rb +121 -92
- data/spec/locale_spec.rb +0 -1
- metadata +3 -3
data/README.textile
CHANGED
@@ -16,7 +16,7 @@ Russian -- это библиотека для полноценной подде
|
|
16
16
|
|
17
17
|
Цель проекта -- построить полноценную среду для русской локализации Ruby и Rails проектов, при этом используя минимально возможное количество хаков, сохраняя при этом поддержку локализации приложения на другие языки, а также форсировать включение в основную ветку I18n и Rails всех функций локализации, необходимых для работы с русским языком.
|
18
18
|
|
19
|
-
Russian использует библиотеку I18n (включена в поставку), несколько хаков поверх нее (собственный бекэнд с поддержкой
|
19
|
+
Russian использует библиотеку I18n (включена в поставку), несколько хаков поверх нее (собственный бекэнд с поддержкой специфичного для русского форматирования даты и времени, поддержкой плюрализации), несколько хаков поверх Rails (хаки хелперов даты-времени, хак для сообщений валидации) и файлы переводов, а также набор хелперов, упрощающий работу с русским языком (простая плюрализация, простой strftime и др.).
|
20
20
|
|
21
21
|
Russian стремится быть минимально деструктивной для окружения и быть полностью совместимой с другими языками (таким образом, когда приложение использует Russian и собственный бекэнд Russian, оно остается полностью совместимым с Rails i18n).
|
22
22
|
|
@@ -92,7 +92,7 @@ h1. Использование
|
|
92
92
|
* _NB:_ локаль русского языка (@ru-RU@) становится локалью по умолчанию
|
93
93
|
* загружаются все файлы переводов, в том числе переводы для Rails.
|
94
94
|
|
95
|
-
После этого можно использовать все стандартные функции библиотеки I18n, пользоваться измененным
|
95
|
+
После этого можно использовать все стандартные функции библиотеки I18n, пользоваться измененным функционалом для лучшей поддержки русского языка, или использовать хелперы модуля Russian для еще более простой работы с русским языком.
|
96
96
|
|
97
97
|
h2. Отличия от стандартной библиотеки I18n
|
98
98
|
|
@@ -125,7 +125,7 @@ Russian.locale
|
|
125
125
|
Russian::LOCALE
|
126
126
|
</code></pre>
|
127
127
|
|
128
|
-
-- возвращает локаль русского языка (
|
128
|
+
-- возвращает локаль русского языка (@:'ru-RU'@).
|
129
129
|
|
130
130
|
<pre><code>
|
131
131
|
Russian::i18n_backend_class
|
data/Rakefile
CHANGED
data/TODO
CHANGED
data/lib/russian.rb
CHANGED
@@ -43,7 +43,7 @@ ru-RU:
|
|
43
43
|
greater_than: "может иметь значение большее {{count}}"
|
44
44
|
greater_than_or_equal_to: "может иметь значение большее или равное {{count}}"
|
45
45
|
equal_to: "может иметь лишь значение, равное {{count}}"
|
46
|
-
less_than: "может иметь значение
|
46
|
+
less_than: "может иметь значение меньшее чем {{count}}"
|
47
47
|
less_than_or_equal_to: "может иметь значение меньшее или равное {{count}}"
|
48
48
|
odd: "может иметь лишь четное значение"
|
49
49
|
even: "может иметь лишь нечетное значение"
|
@@ -1,24 +1,27 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "i18n"
|
3
|
-
s.version = "0.0
|
4
|
-
s.date = "2008-
|
5
|
-
s.summary = "Internationalization for Ruby"
|
6
|
-
s.email = "rails-
|
7
|
-
s.homepage = "http://
|
8
|
-
s.description = "Add Internationalization to your Ruby application."
|
3
|
+
s.version = "0.1.0"
|
4
|
+
s.date = "2008-10-26"
|
5
|
+
s.summary = "Internationalization support for Ruby"
|
6
|
+
s.email = "rails-i18n@googlegroups.com"
|
7
|
+
s.homepage = "http://rails-i18n.org"
|
8
|
+
s.description = "Add Internationalization support to your Ruby application."
|
9
9
|
s.has_rdoc = false
|
10
|
-
s.authors = ['Sven Fuchs', 'Matt Aimonetti', 'Stephan Soller', 'Saimon Moore']
|
10
|
+
s.authors = ['Sven Fuchs', 'Joshua Harvey', 'Matt Aimonetti', 'Stephan Soller', 'Saimon Moore']
|
11
11
|
s.files = [
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
12
|
+
'i18n.gemspec',
|
13
|
+
'lib/i18n/backend/simple.rb',
|
14
|
+
'lib/i18n/exceptions.rb',
|
15
|
+
'lib/i18n.rb',
|
16
|
+
'MIT-LICENSE',
|
17
|
+
'README.textile'
|
18
|
+
]
|
19
|
+
s.test_files = [
|
20
|
+
'test/all.rb',
|
21
|
+
'test/i18n_exceptions_test.rb',
|
22
|
+
'test/i18n_test.rb',
|
23
|
+
'test/locale/en-US.rb',
|
24
|
+
'test/locale/en-US.yml',
|
25
|
+
'test/simple_backend_test.rb'
|
23
26
|
]
|
24
27
|
end
|
data/lib/vendor/i18n/lib/i18n.rb
CHANGED
@@ -2,39 +2,39 @@
|
|
2
2
|
# Sven Fuchs (http://www.artweb-design.de),
|
3
3
|
# Joshua Harvey (http://www.workingwithrails.com/person/759-joshua-harvey),
|
4
4
|
# Saimon Moore (http://saimonmoore.net),
|
5
|
-
# Stephan Soller (http://www.arkanis-development.de/)
|
5
|
+
# Stephan Soller (http://www.arkanis-development.de/)
|
6
6
|
# Copyright:: Copyright (c) 2008 The Ruby i18n Team
|
7
7
|
# License:: MIT
|
8
8
|
require 'i18n/backend/simple'
|
9
9
|
require 'i18n/exceptions'
|
10
10
|
|
11
|
-
module I18n
|
11
|
+
module I18n
|
12
12
|
@@backend = nil
|
13
|
-
@@load_path =
|
13
|
+
@@load_path = nil
|
14
14
|
@@default_locale = :'en-US'
|
15
15
|
@@exception_handler = :default_exception_handler
|
16
|
-
|
16
|
+
|
17
17
|
class << self
|
18
18
|
# Returns the current backend. Defaults to +Backend::Simple+.
|
19
19
|
def backend
|
20
20
|
@@backend ||= Backend::Simple.new
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
# Sets the current backend. Used to set a custom backend.
|
24
|
-
def backend=(backend)
|
24
|
+
def backend=(backend)
|
25
25
|
@@backend = backend
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
# Returns the current default locale. Defaults to 'en-US'
|
29
29
|
def default_locale
|
30
|
-
@@default_locale
|
30
|
+
@@default_locale
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
# Sets the current default locale. Used to set a custom default locale.
|
34
|
-
def default_locale=(locale)
|
35
|
-
@@default_locale = locale
|
34
|
+
def default_locale=(locale)
|
35
|
+
@@default_locale = locale
|
36
36
|
end
|
37
|
-
|
37
|
+
|
38
38
|
# Returns the current locale. Defaults to I18n.default_locale.
|
39
39
|
def locale
|
40
40
|
Thread.current[:locale] ||= default_locale
|
@@ -44,46 +44,55 @@ module I18n
|
|
44
44
|
def locale=(locale)
|
45
45
|
Thread.current[:locale] = locale
|
46
46
|
end
|
47
|
-
|
47
|
+
|
48
48
|
# Sets the exception handler.
|
49
49
|
def exception_handler=(exception_handler)
|
50
50
|
@@exception_handler = exception_handler
|
51
51
|
end
|
52
|
-
|
53
|
-
# Allow clients to register paths providing translation data sources. The
|
52
|
+
|
53
|
+
# Allow clients to register paths providing translation data sources. The
|
54
54
|
# backend defines acceptable sources.
|
55
55
|
#
|
56
56
|
# E.g. the provided SimpleBackend accepts a list of paths to translation
|
57
57
|
# files which are either named *.rb and contain plain Ruby Hashes or are
|
58
|
-
# named *.yml and contain YAML data. So for the SimpleBackend clients may
|
58
|
+
# named *.yml and contain YAML data. So for the SimpleBackend clients may
|
59
59
|
# register translation files like this:
|
60
60
|
# I18n.load_path << 'path/to/locale/en-US.yml'
|
61
61
|
def load_path
|
62
|
-
@@load_path
|
62
|
+
@@load_path ||= []
|
63
63
|
end
|
64
64
|
|
65
|
+
# Sets the load path instance. Custom implementations are expected to
|
66
|
+
# behave like a Ruby Array.
|
65
67
|
def load_path=(load_path)
|
66
68
|
@@load_path = load_path
|
67
69
|
end
|
68
|
-
|
69
|
-
#
|
70
|
+
|
71
|
+
# Tells the backend to reload translations. Used in situations like the
|
72
|
+
# Rails development environment. Backends can implement whatever strategy
|
73
|
+
# is useful.
|
74
|
+
def reload!
|
75
|
+
backend.reload!
|
76
|
+
end
|
77
|
+
|
78
|
+
# Translates, pluralizes and interpolates a given key using a given locale,
|
70
79
|
# scope, and default, as well as interpolation values.
|
71
80
|
#
|
72
81
|
# *LOOKUP*
|
73
82
|
#
|
74
|
-
# Translation data is organized as a nested hash using the upper-level keys
|
75
|
-
# as namespaces. <em>E.g.</em>, ActionView ships with the translation:
|
83
|
+
# Translation data is organized as a nested hash using the upper-level keys
|
84
|
+
# as namespaces. <em>E.g.</em>, ActionView ships with the translation:
|
76
85
|
# <tt>:date => {:formats => {:short => "%b %d"}}</tt>.
|
77
|
-
#
|
78
|
-
# Translations can be looked up at any level of this hash using the key argument
|
79
|
-
# and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
|
86
|
+
#
|
87
|
+
# Translations can be looked up at any level of this hash using the key argument
|
88
|
+
# and the scope option. <em>E.g.</em>, in this example <tt>I18n.t :date</tt>
|
80
89
|
# returns the whole translations hash <tt>{:formats => {:short => "%b %d"}}</tt>.
|
81
|
-
#
|
82
|
-
# Key can be either a single key or a dot-separated key (both Strings and Symbols
|
90
|
+
#
|
91
|
+
# Key can be either a single key or a dot-separated key (both Strings and Symbols
|
83
92
|
# work). <em>E.g.</em>, the short format can be looked up using both:
|
84
93
|
# I18n.t 'date.formats.short'
|
85
94
|
# I18n.t :'date.formats.short'
|
86
|
-
#
|
95
|
+
#
|
87
96
|
# Scope can be either a single key, a dot-separated key or an array of keys
|
88
97
|
# or dot-separated keys. Keys and scopes can be combined freely. So these
|
89
98
|
# examples will all look up the same short date format:
|
@@ -96,9 +105,9 @@ module I18n
|
|
96
105
|
#
|
97
106
|
# Translations can contain interpolation variables which will be replaced by
|
98
107
|
# values passed to #translate as part of the options hash, with the keys matching
|
99
|
-
# the interpolation variable names.
|
108
|
+
# the interpolation variable names.
|
100
109
|
#
|
101
|
-
# <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
|
110
|
+
# <em>E.g.</em>, with a translation <tt>:foo => "foo {{bar}}"</tt> the option
|
102
111
|
# value for the key +bar+ will be interpolated into the translation:
|
103
112
|
# I18n.t :foo, :bar => 'baz' # => 'foo baz'
|
104
113
|
#
|
@@ -107,7 +116,7 @@ module I18n
|
|
107
116
|
# Translation data can contain pluralized translations. Pluralized translations
|
108
117
|
# are arrays of singluar/plural versions of translations like <tt>['Foo', 'Foos']</tt>.
|
109
118
|
#
|
110
|
-
# Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
|
119
|
+
# Note that <tt>I18n::Backend::Simple</tt> only supports an algorithm for English
|
111
120
|
# pluralization rules. Other algorithms can be supported by custom backends.
|
112
121
|
#
|
113
122
|
# This returns the singular version of a pluralized translation:
|
@@ -116,9 +125,9 @@ module I18n
|
|
116
125
|
# These both return the plural version of a pluralized translation:
|
117
126
|
# I18n.t :foo, :count => 0 # => 'Foos'
|
118
127
|
# I18n.t :foo, :count => 2 # => 'Foos'
|
119
|
-
#
|
120
|
-
# The <tt>:count</tt> option can be used both for pluralization and interpolation.
|
121
|
-
# <em>E.g.</em>, with the translation
|
128
|
+
#
|
129
|
+
# The <tt>:count</tt> option can be used both for pluralization and interpolation.
|
130
|
+
# <em>E.g.</em>, with the translation
|
122
131
|
# <tt>:foo => ['{{count}} foo', '{{count}} foos']</tt>, count will
|
123
132
|
# be interpolated to the pluralized translation:
|
124
133
|
# I18n.t :foo, :count => 1 # => '1 foo'
|
@@ -128,11 +137,11 @@ module I18n
|
|
128
137
|
# This returns the translation for <tt>:foo</tt> or <tt>default</tt> if no translation was found:
|
129
138
|
# I18n.t :foo, :default => 'default'
|
130
139
|
#
|
131
|
-
# This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
|
140
|
+
# This returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt> if no
|
132
141
|
# translation for <tt>:foo</tt> was found:
|
133
142
|
# I18n.t :foo, :default => :bar
|
134
143
|
#
|
135
|
-
# Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
|
144
|
+
# Returns the translation for <tt>:foo</tt> or the translation for <tt>:bar</tt>
|
136
145
|
# or <tt>default</tt> if no translations for <tt>:foo</tt> and <tt>:bar</tt> were found.
|
137
146
|
# I18n.t :foo, :default => [:bar, 'default']
|
138
147
|
#
|
@@ -148,13 +157,13 @@ module I18n
|
|
148
157
|
# I18n.t [:foo, :bar], :scope => :baz
|
149
158
|
def translate(key, options = {})
|
150
159
|
locale = options.delete(:locale) || I18n.locale
|
151
|
-
backend.translate
|
160
|
+
backend.translate(locale, key, options)
|
152
161
|
rescue I18n::ArgumentError => e
|
153
162
|
raise e if options[:raise]
|
154
|
-
send
|
155
|
-
end
|
163
|
+
send(@@exception_handler, e, locale, key, options)
|
164
|
+
end
|
156
165
|
alias :t :translate
|
157
|
-
|
166
|
+
|
158
167
|
# Localizes certain objects, such as dates and numbers to local formatting.
|
159
168
|
def localize(object, options = {})
|
160
169
|
locale = options[:locale] || I18n.locale
|
@@ -162,7 +171,7 @@ module I18n
|
|
162
171
|
backend.localize(locale, object, format)
|
163
172
|
end
|
164
173
|
alias :l :localize
|
165
|
-
|
174
|
+
|
166
175
|
protected
|
167
176
|
# Handles exceptions raised in the backend. All exceptions except for
|
168
177
|
# MissingTranslationData exceptions are re-raised. When a MissingTranslationData
|
@@ -172,14 +181,14 @@ module I18n
|
|
172
181
|
return exception.message if MissingTranslationData === exception
|
173
182
|
raise exception
|
174
183
|
end
|
175
|
-
|
184
|
+
|
176
185
|
# Merges the given locale, key and scope into a single array of keys.
|
177
186
|
# Splits keys that contain dots into multiple keys. Makes sure all
|
178
187
|
# keys are Symbols.
|
179
188
|
def normalize_translation_keys(locale, key, scope)
|
180
189
|
keys = [locale] + Array(scope) + [key]
|
181
|
-
keys = keys.map{|k| k.to_s.split(/\./) }
|
182
|
-
keys.flatten.map{|k| k.to_sym}
|
190
|
+
keys = keys.map { |k| k.to_s.split(/\./) }
|
191
|
+
keys.flatten.map { |k| k.to_sym }
|
183
192
|
end
|
184
193
|
end
|
185
|
-
end
|
194
|
+
end
|
@@ -6,42 +6,48 @@ module I18n
|
|
6
6
|
INTERPOLATION_RESERVED_KEYS = %w(scope default)
|
7
7
|
MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
|
8
8
|
|
9
|
-
# Accepts a list of paths to translation files. Loads translations from
|
9
|
+
# Accepts a list of paths to translation files. Loads translations from
|
10
10
|
# plain Ruby (*.rb) or YAML files (*.yml). See #load_rb and #load_yml
|
11
11
|
# for details.
|
12
12
|
def load_translations(*filenames)
|
13
|
-
filenames.each {|filename| load_file
|
13
|
+
filenames.each { |filename| load_file(filename) }
|
14
14
|
end
|
15
|
-
|
16
|
-
# Stores translations for the given locale in memory.
|
15
|
+
|
16
|
+
# Stores translations for the given locale in memory.
|
17
17
|
# This uses a deep merge for the translations hash, so existing
|
18
18
|
# translations will be overwritten by new ones only at the deepest
|
19
19
|
# level of the hash.
|
20
20
|
def store_translations(locale, data)
|
21
21
|
merge_translations(locale, data)
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
def translate(locale, key, options = {})
|
25
25
|
raise InvalidLocale.new(locale) if locale.nil?
|
26
|
-
return key.map{|k| translate
|
26
|
+
return key.map { |k| translate(locale, k, options) } if key.is_a? Array
|
27
27
|
|
28
28
|
reserved = :scope, :default
|
29
29
|
count, scope, default = options.values_at(:count, *reserved)
|
30
30
|
options.delete(:default)
|
31
|
-
values = options.reject{|name, value| reserved.include?
|
31
|
+
values = options.reject { |name, value| reserved.include?(name) }
|
32
32
|
|
33
|
-
entry = lookup(locale, key, scope)
|
34
|
-
|
35
|
-
|
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)
|
36
42
|
entry
|
37
43
|
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>).
|
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>).
|
42
48
|
def localize(locale, object, format = :default)
|
43
49
|
raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
|
44
|
-
|
50
|
+
|
45
51
|
type = object.respond_to?(:sec) ? 'time' : 'date'
|
46
52
|
# TODO only translate these if format is a String?
|
47
53
|
formats = translate(locale, :"#{type}.formats")
|
@@ -51,56 +57,70 @@ module I18n
|
|
51
57
|
|
52
58
|
# TODO only translate these if the format string is actually present
|
53
59
|
# 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])
|
60
|
+
format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
|
55
61
|
format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
|
56
62
|
format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
|
57
63
|
format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
|
58
64
|
format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
|
59
65
|
object.strftime(format)
|
60
66
|
end
|
61
|
-
|
67
|
+
|
68
|
+
def initialized?
|
69
|
+
@initialized ||= false
|
70
|
+
end
|
71
|
+
|
72
|
+
def reload!
|
73
|
+
@initialized = false
|
74
|
+
@translations = nil
|
75
|
+
end
|
76
|
+
|
62
77
|
protected
|
63
|
-
|
64
78
|
def init_translations
|
65
79
|
load_translations(*I18n.load_path)
|
66
80
|
@initialized = true
|
67
81
|
end
|
68
|
-
|
82
|
+
|
69
83
|
def translations
|
70
84
|
@translations ||= {}
|
71
85
|
end
|
72
|
-
|
73
|
-
# Looks up a translation from the translations hash. Returns nil if
|
86
|
+
|
87
|
+
# Looks up a translation from the translations hash. Returns nil if
|
74
88
|
# eiher key is nil, or locale, scope or key do not exist as a key in the
|
75
89
|
# nested translations hash. Splits keys or scopes containing dots
|
76
90
|
# into multiple keys, i.e. <tt>currency.format</tt> is regarded the same as
|
77
91
|
# <tt>%w(currency format)</tt>.
|
78
92
|
def lookup(locale, key, scope = [])
|
79
93
|
return unless key
|
80
|
-
init_translations unless
|
81
|
-
keys = I18n.send
|
82
|
-
keys.inject(translations)
|
94
|
+
init_translations unless initialized?
|
95
|
+
keys = I18n.send(:normalize_translation_keys, locale, key, scope)
|
96
|
+
keys.inject(translations) do |result, k|
|
97
|
+
if (x = result[k.to_sym]).nil?
|
98
|
+
return nil
|
99
|
+
else
|
100
|
+
x
|
101
|
+
end
|
102
|
+
end
|
83
103
|
end
|
84
|
-
|
85
|
-
# Evaluates a default translation.
|
104
|
+
|
105
|
+
# Evaluates a default translation.
|
86
106
|
# If the given default is a String it is used literally. If it is a Symbol
|
87
107
|
# it will be translated with the given options. If it is an Array the first
|
88
108
|
# translation yielded will be returned.
|
89
|
-
#
|
90
|
-
# <em>I.e.</em>, <tt>default(locale, [:foo, 'default'])</tt> will return +default+ if
|
109
|
+
#
|
110
|
+
# <em>I.e.</em>, <tt>default(locale, [:foo, 'default'])</tt> will return +default+ if
|
91
111
|
# <tt>translate(locale, :foo)</tt> does not yield a result.
|
92
112
|
def default(locale, default, options = {})
|
93
113
|
case default
|
94
114
|
when String then default
|
95
115
|
when Symbol then translate locale, default, options
|
96
|
-
when Array then default.each do |obj|
|
116
|
+
when Array then default.each do |obj|
|
97
117
|
result = default(locale, obj, options.dup) and return result
|
98
118
|
end and nil
|
99
119
|
end
|
100
120
|
rescue MissingTranslationData
|
101
121
|
nil
|
102
122
|
end
|
103
|
-
|
123
|
+
|
104
124
|
# Picks a translation from an array according to English pluralization
|
105
125
|
# rules. It will pick the first translation if count is not equal to 1
|
106
126
|
# and the second translation if it is equal to 1. Other backends can
|
@@ -113,20 +133,18 @@ module I18n
|
|
113
133
|
raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
|
114
134
|
entry[key]
|
115
135
|
end
|
116
|
-
|
136
|
+
|
117
137
|
# Interpolates values into a given string.
|
118
|
-
#
|
119
|
-
# interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
|
138
|
+
#
|
139
|
+
# interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
|
120
140
|
# # => "file test.txt opened by {{user}}"
|
121
|
-
#
|
141
|
+
#
|
122
142
|
# Note that you have to double escape the <tt>\\</tt> when you want to escape
|
123
143
|
# the <tt>{{...}}</tt> key in a string (once for the string and once for the
|
124
144
|
# interpolation).
|
125
145
|
def interpolate(locale, string, values = {})
|
126
146
|
return string unless string.is_a?(String)
|
127
147
|
|
128
|
-
string = string.gsub(/%d/, '{{count}}').gsub(/%s/, '{{value}}')
|
129
|
-
|
130
148
|
if string.respond_to?(:force_encoding)
|
131
149
|
original_encoding = string.encoding
|
132
150
|
string.force_encoding(Encoding::BINARY)
|
@@ -149,45 +167,45 @@ module I18n
|
|
149
167
|
result.force_encoding(original_encoding) if original_encoding
|
150
168
|
result
|
151
169
|
end
|
152
|
-
|
153
|
-
# Loads a single translations file by delegating to #load_rb or
|
170
|
+
|
171
|
+
# Loads a single translations file by delegating to #load_rb or
|
154
172
|
# #load_yml depending on the file extension and directly merges the
|
155
173
|
# data to the existing translations. Raises I18n::UnknownFileType
|
156
174
|
# for all other file extensions.
|
157
175
|
def load_file(filename)
|
158
176
|
type = File.extname(filename).tr('.', '').downcase
|
159
|
-
raise UnknownFileType.new(type, filename) unless respond_to?
|
177
|
+
raise UnknownFileType.new(type, filename) unless respond_to?(:"load_#{type}")
|
160
178
|
data = send :"load_#{type}", filename # TODO raise a meaningful exception if this does not yield a Hash
|
161
|
-
data.each{|locale, d| merge_translations
|
179
|
+
data.each { |locale, d| merge_translations(locale, d) }
|
162
180
|
end
|
163
|
-
|
181
|
+
|
164
182
|
# Loads a plain Ruby translations file. eval'ing the file must yield
|
165
183
|
# a Hash containing translation data with locales as toplevel keys.
|
166
184
|
def load_rb(filename)
|
167
|
-
eval
|
185
|
+
eval(IO.read(filename), binding, filename)
|
168
186
|
end
|
169
|
-
|
170
|
-
# Loads a YAML translations file. The data must have locales as
|
187
|
+
|
188
|
+
# Loads a YAML translations file. The data must have locales as
|
171
189
|
# toplevel keys.
|
172
190
|
def load_yml(filename)
|
173
|
-
YAML::load
|
191
|
+
YAML::load(IO.read(filename))
|
174
192
|
end
|
175
|
-
|
193
|
+
|
176
194
|
# Deep merges the given translations hash with the existing translations
|
177
195
|
# for the given locale
|
178
196
|
def merge_translations(locale, data)
|
179
197
|
locale = locale.to_sym
|
180
198
|
translations[locale] ||= {}
|
181
|
-
data = deep_symbolize_keys
|
199
|
+
data = deep_symbolize_keys(data)
|
182
200
|
|
183
201
|
# deep_merge by Stefan Rusterholz, see http://www.ruby-forum.com/topic/142809
|
184
|
-
merger = proc{|key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
185
|
-
translations[locale].merge!
|
202
|
+
merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : v2 }
|
203
|
+
translations[locale].merge!(data, &merger)
|
186
204
|
end
|
187
|
-
|
205
|
+
|
188
206
|
# Return a new hash with all keys and nested keys converted to symbols.
|
189
207
|
def deep_symbolize_keys(hash)
|
190
|
-
hash.inject({}){|result, (key, value)|
|
208
|
+
hash.inject({}) { |result, (key, value)|
|
191
209
|
value = deep_symbolize_keys(value) if value.is_a? Hash
|
192
210
|
result[(key.to_sym rescue key) || key] = value
|
193
211
|
result
|
@@ -195,4 +213,4 @@ module I18n
|
|
195
213
|
end
|
196
214
|
end
|
197
215
|
end
|
198
|
-
end
|
216
|
+
end
|