r18n-core 3.1.1 → 5.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +398 -0
- data/README.md +63 -47
- data/base/cy.yml +34 -0
- data/lib/r18n-core.rb +37 -38
- data/lib/r18n-core/filter_list.rb +21 -13
- data/lib/r18n-core/filters.rb +43 -48
- data/lib/r18n-core/helpers.rb +2 -2
- data/lib/r18n-core/i18n.rb +70 -78
- data/lib/r18n-core/locale.rb +137 -107
- data/lib/r18n-core/locales/af.rb +36 -0
- data/lib/r18n-core/locales/az.rb +38 -0
- data/lib/r18n-core/locales/bg.rb +29 -0
- data/{locales → lib/r18n-core/locales}/ca.rb +9 -6
- data/{locales → lib/r18n-core/locales}/cs.rb +15 -11
- data/lib/r18n-core/locales/cy.rb +50 -0
- data/{locales → lib/r18n-core/locales}/da.rb +10 -7
- data/lib/r18n-core/locales/de.rb +33 -0
- data/{locales → lib/r18n-core/locales}/en-au.rb +2 -2
- data/{locales → lib/r18n-core/locales}/en-gb.rb +2 -2
- data/{locales → lib/r18n-core/locales}/en-us.rb +4 -3
- data/lib/r18n-core/locales/en.rb +51 -0
- data/{locales → lib/r18n-core/locales}/eo.rb +6 -4
- data/lib/r18n-core/locales/es-cl.rb +16 -0
- data/{locales → lib/r18n-core/locales}/es-us.rb +5 -4
- data/{locales → lib/r18n-core/locales}/es.rb +7 -3
- data/{locales → lib/r18n-core/locales}/fa.rb +2 -2
- data/lib/r18n-core/locales/fi.rb +39 -0
- data/lib/r18n-core/locales/fr.rb +39 -0
- data/{locales → lib/r18n-core/locales}/gl.rb +5 -3
- data/{locales → lib/r18n-core/locales}/hr.rb +13 -10
- data/{locales → lib/r18n-core/locales}/hu.rb +10 -7
- data/{locales → lib/r18n-core/locales}/id.rb +8 -4
- data/lib/r18n-core/locales/it.rb +37 -0
- data/{locales → lib/r18n-core/locales}/ja.rb +5 -4
- data/{locales → lib/r18n-core/locales}/kk.rb +12 -8
- data/{locales → lib/r18n-core/locales}/ko.rb +0 -0
- data/lib/r18n-core/locales/lv.rb +46 -0
- data/lib/r18n-core/locales/mn.rb +30 -0
- data/{locales → lib/r18n-core/locales}/nb.rb +6 -4
- data/lib/r18n-core/locales/nl.rb +31 -0
- data/{locales → lib/r18n-core/locales}/no.rb +0 -0
- data/lib/r18n-core/locales/pl.rb +45 -0
- data/{locales → lib/r18n-core/locales}/pt-br.rb +1 -1
- data/lib/r18n-core/locales/pt.rb +37 -0
- data/lib/r18n-core/locales/ru.rb +46 -0
- data/{locales → lib/r18n-core/locales}/sk.rb +13 -9
- data/{locales → lib/r18n-core/locales}/sr-latn.rb +10 -8
- data/{locales → lib/r18n-core/locales}/sv-se.rb +7 -5
- data/lib/r18n-core/locales/th.rb +41 -0
- data/{locales → lib/r18n-core/locales}/tr.rb +7 -6
- data/lib/r18n-core/locales/uk.rb +31 -0
- data/lib/r18n-core/locales/vi.rb +37 -0
- data/{locales → lib/r18n-core/locales}/zh-cn.rb +2 -2
- data/{locales → lib/r18n-core/locales}/zh-tw.rb +4 -4
- data/{locales → lib/r18n-core/locales}/zh.rb +7 -4
- data/lib/r18n-core/translated.rb +38 -37
- data/lib/r18n-core/translated_string.rb +19 -8
- data/lib/r18n-core/translation.rb +24 -19
- data/lib/r18n-core/unsupported_locale.rb +14 -6
- data/lib/r18n-core/untranslated.rb +23 -7
- data/lib/r18n-core/utils.rb +19 -23
- data/lib/r18n-core/version.rb +1 -1
- data/lib/r18n-core/yaml_loader.rb +17 -13
- data/lib/r18n-core/yaml_methods.rb +3 -1
- metadata +245 -118
- data/.rspec +0 -1
- data/Rakefile +0 -13
- data/locales/af.rb +0 -32
- data/locales/az.rb +0 -34
- data/locales/bg.rb +0 -25
- data/locales/de.rb +0 -29
- data/locales/en.rb +0 -48
- data/locales/fi.rb +0 -35
- data/locales/fr.rb +0 -35
- data/locales/it.rb +0 -34
- data/locales/lv.rb +0 -41
- data/locales/mn.rb +0 -27
- data/locales/nl.rb +0 -28
- data/locales/pl.rb +0 -40
- data/locales/pt.rb +0 -29
- data/locales/ru.rb +0 -41
- data/locales/th.rb +0 -37
- data/locales/uk.rb +0 -27
- data/locales/vi.rb +0 -33
- data/r18n-core.gemspec +0 -29
- data/spec/filters_spec.rb +0 -324
- data/spec/i18n_spec.rb +0 -260
- data/spec/locale_spec.rb +0 -216
- data/spec/locales/cs_spec.rb +0 -23
- data/spec/locales/en-us_spec.rb +0 -13
- data/spec/locales/en_spec.rb +0 -13
- data/spec/locales/fa_spec.rb +0 -10
- data/spec/locales/fr_spec.rb +0 -9
- data/spec/locales/hu_spec.rb +0 -17
- data/spec/locales/it_spec.rb +0 -10
- data/spec/locales/no_spec.rb +0 -9
- data/spec/locales/pl_spec.rb +0 -23
- data/spec/locales/ru_spec.rb +0 -23
- data/spec/locales/sk_spec.rb +0 -23
- data/spec/locales/th_spec.rb +0 -9
- data/spec/locales/vi_spec.rb +0 -8
- data/spec/r18n_spec.rb +0 -172
- data/spec/spec_helper.rb +0 -41
- data/spec/translated_spec.rb +0 -163
- data/spec/translation_spec.rb +0 -164
- data/spec/translations/extension/deep/en.yml +0 -1
- data/spec/translations/extension/en.yml +0 -2
- data/spec/translations/extension/notransl.yml +0 -1
- data/spec/translations/general/en.yml +0 -47
- data/spec/translations/general/nolocale.yml +0 -6
- data/spec/translations/general/ru.yml +0 -7
- data/spec/translations/two/en.yml +0 -2
- data/spec/translations/two/fr.yml +0 -0
- data/spec/yaml_loader_spec.rb +0 -61
data/lib/r18n-core/helpers.rb
CHANGED
@@ -32,12 +32,12 @@ module R18n
|
|
32
32
|
end
|
33
33
|
alias i18n r18n
|
34
34
|
|
35
|
-
# Translate message. Alias for
|
35
|
+
# Translate message. Alias for `r18n.t`.
|
36
36
|
def t(*params)
|
37
37
|
R18n.get.t(*params)
|
38
38
|
end
|
39
39
|
|
40
|
-
# Localize object. Alias for
|
40
|
+
# Localize object. Alias for `r18n.l`.
|
41
41
|
def l(*params)
|
42
42
|
R18n.get.l(*params)
|
43
43
|
end
|
data/lib/r18n-core/i18n.rb
CHANGED
@@ -24,14 +24,14 @@ module R18n
|
|
24
24
|
# Locale classes and create pretty way to use it.
|
25
25
|
#
|
26
26
|
# To get translation you can use same with Translation way – use method with
|
27
|
-
# translation
|
28
|
-
# loaded for default locale,
|
29
|
-
# languages for dialects (it will load
|
27
|
+
# translation's name or `[name]` method. Translations will be also
|
28
|
+
# loaded for default locale, `sublocales` from first in `locales` and general
|
29
|
+
# languages for dialects (it will load `fr` for `fr_CA` too).
|
30
30
|
#
|
31
31
|
# Translations will loaded by loader object, which must have 2 methods:
|
32
|
-
# *
|
33
|
-
# *
|
34
|
-
# If you will use default loader (
|
32
|
+
# * `available` – return array of locales of available translations;
|
33
|
+
# * `load(locale)` – return Hash of translation.
|
34
|
+
# If you will use default loader (`R18n.default_loader`) you can pass to I18n
|
35
35
|
# only constructor argument for loader:
|
36
36
|
#
|
37
37
|
# R18n::I18n.new('en', R18n::Loader::YAML.new('dir/with/translations'))
|
@@ -41,16 +41,16 @@ module R18n
|
|
41
41
|
# R18n::I18n.new('en', 'dir/with/translations')
|
42
42
|
#
|
43
43
|
# In translation file you can use strings, numbers, floats (any YAML types)
|
44
|
-
# and pluralizable values (
|
45
|
-
# values, which you can replace in program. Just write
|
46
|
-
#
|
44
|
+
# and pluralizable values (`!!pl`). You can use params in string
|
45
|
+
# values, which you can replace in program. Just write `%1`,
|
46
|
+
# `%2`, etc and set it values as method arguments, when you will be get
|
47
47
|
# value.
|
48
48
|
#
|
49
49
|
# You can use filters for some YAML type or for all strings. See R18n::Filters
|
50
50
|
# for details.
|
51
51
|
#
|
52
|
-
# R18n contain translations for common words (such as
|
53
|
-
# for most supported locales. See
|
52
|
+
# R18n contain translations for common words (such as "OK", "Cancel", etc)
|
53
|
+
# for most supported locales. See `base/` dir.
|
54
54
|
#
|
55
55
|
# == Usage
|
56
56
|
# translations/ru.yml
|
@@ -83,43 +83,37 @@ module R18n
|
|
83
83
|
# i18n.ok #=> "OK"
|
84
84
|
# i18n.cancel #=> "Cancel"
|
85
85
|
class I18n
|
86
|
-
|
86
|
+
@default = 'en'
|
87
87
|
|
88
|
-
|
89
|
-
|
90
|
-
def self.default=(locale)
|
91
|
-
@@default = locale
|
92
|
-
end
|
88
|
+
class << self
|
89
|
+
attr_accessor :default
|
93
90
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
end
|
91
|
+
# Parse HTTP_ACCEPT_LANGUAGE and return array of user locales
|
92
|
+
def parse_http(str)
|
93
|
+
return [] if str.nil?
|
98
94
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
else
|
108
|
-
[locale[0], locale[1].to_f]
|
95
|
+
locales = str.split(',')
|
96
|
+
locales.map! do |locale|
|
97
|
+
locale = locale.split ';q='
|
98
|
+
if locale.size == 1
|
99
|
+
[locale[0], 1.0]
|
100
|
+
else
|
101
|
+
[locale[0], locale[1].to_f]
|
102
|
+
end
|
109
103
|
end
|
104
|
+
locales.sort! { |a, b| b[1] <=> a[1] }
|
105
|
+
locales.map! { |i| i[0] }
|
110
106
|
end
|
111
|
-
locales.sort! { |a, b| b[1] <=> a[1] }
|
112
|
-
locales.map! { |i| i[0] }
|
113
|
-
end
|
114
107
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
108
|
+
# Load default loader for elements in `places` with only constructor
|
109
|
+
# argument.
|
110
|
+
def convert_places(places)
|
111
|
+
Array(places).map! do |loader|
|
112
|
+
if loader.respond_to?(:available) && loader.respond_to?(:load)
|
113
|
+
loader
|
114
|
+
else
|
115
|
+
R18n.default_loader.new(loader)
|
116
|
+
end
|
123
117
|
end
|
124
118
|
end
|
125
119
|
end
|
@@ -133,28 +127,29 @@ module R18n
|
|
133
127
|
# First locale with locale file
|
134
128
|
attr_reader :locale
|
135
129
|
|
136
|
-
# Create i18n for
|
130
|
+
# Create i18n for `locales` with translations from `translation_places` and
|
137
131
|
# locales data. Translations will be also loaded for default locale,
|
138
|
-
#
|
139
|
-
# (it will load
|
132
|
+
# `sublocales` from first in `locales` and general languages for dialects
|
133
|
+
# (it will load `fr` for `fr_CA` too).
|
140
134
|
#
|
141
|
-
#
|
142
|
-
#
|
135
|
+
# `locales` must be a locale code (RFC 3066) or array, ordered by priority.
|
136
|
+
# `translation_places` must be a string with path or array.
|
143
137
|
def initialize(locales, translation_places = nil, opts = {})
|
144
138
|
locales = Array(locales)
|
145
139
|
|
146
|
-
if !locales.empty? && Locale.exists?(locales.first)
|
147
|
-
locales += Locale.load(locales.first).sublocales
|
148
|
-
end
|
149
|
-
locales << @@default
|
150
140
|
locales.each_with_index do |locale, i|
|
151
|
-
|
152
|
-
|
153
|
-
end
|
141
|
+
locales.insert(i + 1, locale.match(/([^_-]+)[_-]/)[1]) if locale.match?(/[^_-]+[_-]/)
|
142
|
+
locales.insert(i + 1, *(Locale.load(locale).sublocales - locales)) if Locale.exists?(locale)
|
154
143
|
end
|
144
|
+
locales << self.class.default
|
155
145
|
locales.map! { |i| i.to_s.downcase }.uniq!
|
156
146
|
@locales_codes = locales
|
157
|
-
@locales = locales.
|
147
|
+
@locales = locales.each_with_object([]) do |locale, result|
|
148
|
+
locale = Locale.load(locale)
|
149
|
+
next unless locale
|
150
|
+
|
151
|
+
result << locale
|
152
|
+
end
|
158
153
|
|
159
154
|
if translation_places
|
160
155
|
@original_places = translation_places
|
@@ -190,16 +185,14 @@ module R18n
|
|
190
185
|
@available_codes ||= @translation_places
|
191
186
|
.inject([]) { |all, i| all + i.available }
|
192
187
|
.uniq.map { |i| i.code.downcase }
|
193
|
-
(@locales_codes & @available_codes).join(',')
|
194
|
-
@filters.hash.
|
195
|
-
R18n.default_loader.hash.to_s + '_' +
|
196
|
-
@translation_places.hash.to_s + '_' +
|
188
|
+
"#{(@locales_codes & @available_codes).join(',')}@" \
|
189
|
+
"#{@filters.hash}_#{R18n.default_loader.hash}_#{@translation_places.hash}_" +
|
197
190
|
R18n.extension_places.hash.to_s
|
198
191
|
end
|
199
192
|
|
200
193
|
# Reload translations.
|
201
194
|
def reload!
|
202
|
-
@
|
195
|
+
@available_locales = @available_codes = nil
|
203
196
|
@translation_places = self.class.convert_places(@original_places)
|
204
197
|
|
205
198
|
available_in_places = @translation_places.map { |i| [i, i.available] }
|
@@ -207,8 +200,6 @@ module R18n
|
|
207
200
|
R18n.extension_places.map { |i| [i, i.available] }
|
208
201
|
|
209
202
|
unless defined? @locale
|
210
|
-
# It's array!
|
211
|
-
# rubocop:disable Perfomance/HashEachMethods
|
212
203
|
available_in_places.each do |_place, available|
|
213
204
|
@locales.each do |locale|
|
214
205
|
if available.include? locale
|
@@ -218,7 +209,6 @@ module R18n
|
|
218
209
|
end
|
219
210
|
break if defined? @locale
|
220
211
|
end
|
221
|
-
# rubocop:enable Perfomance/HashEachMethods
|
222
212
|
end
|
223
213
|
@locale ||= @locales.first
|
224
214
|
unless @locale.supported?
|
@@ -244,8 +234,10 @@ module R18n
|
|
244
234
|
next unless loaded
|
245
235
|
|
246
236
|
available_in_extensions.each do |extension, available|
|
247
|
-
if available.include? locale
|
248
|
-
|
237
|
+
@translation.merge! extension.load(locale), locale if available.include? locale
|
238
|
+
|
239
|
+
if available.include? locale.parent
|
240
|
+
@translation.merge! extension.load(locale.parent), locale.parent
|
249
241
|
end
|
250
242
|
end
|
251
243
|
end
|
@@ -253,26 +245,26 @@ module R18n
|
|
253
245
|
R18n.cache[translation_cache_key] = [@locale, @translation]
|
254
246
|
end
|
255
247
|
|
256
|
-
# Return Array of locales with available translations.
|
248
|
+
# Return `Array` of locales with available translations.
|
257
249
|
def available_locales
|
258
|
-
@
|
250
|
+
@available_locales ||= R18n.available_locales(@translation_places)
|
259
251
|
end
|
260
252
|
|
261
|
-
# Convert
|
262
|
-
# It support Integer
|
253
|
+
# Convert `object` to `String`, according to the rules of the current
|
254
|
+
# locale. It support `Integer`, `Float`, `Time`, `Date` and `DateTime`.
|
263
255
|
#
|
264
|
-
# For time classes you can set
|
265
|
-
#
|
266
|
-
#
|
267
|
-
# name. Default format is
|
256
|
+
# For time classes you can set `format` in standard `strftime` form,
|
257
|
+
# `:full` ("01 Jule, 2009"), `:human` ("yesterday"),
|
258
|
+
# `:standard` ("07/01/09") or `:month` for standalone month
|
259
|
+
# name. Default format is `:standard`.
|
268
260
|
#
|
269
261
|
# i18n.l -12000.5 #=> "−12,000.5"
|
270
262
|
# i18n.l Time.now #=> "07/01/09 12:59"
|
271
263
|
# i18n.l Time.now.to_date #=> "07/01/09"
|
272
264
|
# i18n.l Time.now, :human #=> "now"
|
273
265
|
# i18n.l Time.now, :full #=> "Jule 1st, 2009 12:59"
|
274
|
-
def localize(object, format = nil,
|
275
|
-
locale.localize(object, format, self,
|
266
|
+
def localize(object, format = nil, **kwargs)
|
267
|
+
locale.localize(object, format, i18n: self, **kwargs)
|
276
268
|
end
|
277
269
|
alias l localize
|
278
270
|
|
@@ -281,10 +273,10 @@ module R18n
|
|
281
273
|
@translation
|
282
274
|
end
|
283
275
|
|
284
|
-
# Return translation with special
|
276
|
+
# Return translation with special `name`.
|
285
277
|
#
|
286
|
-
# Translation can contain variable part. Just set is as
|
287
|
-
#
|
278
|
+
# Translation can contain variable part. Just set is as `%1`,
|
279
|
+
# `%2`, etc in translations file and set values in next `params`.
|
288
280
|
def [](name, *params)
|
289
281
|
@translation[name, *params]
|
290
282
|
end
|
data/lib/r18n-core/locale.rb
CHANGED
@@ -23,14 +23,14 @@ require 'bigdecimal'
|
|
23
23
|
module R18n
|
24
24
|
# Information about locale (language, country and other special variant
|
25
25
|
# preferences). Locale was named by RFC 3066. For example, locale for French
|
26
|
-
# speaking people in Canada will be
|
26
|
+
# speaking people in Canada will be `fr-CA`.
|
27
27
|
#
|
28
|
-
# Locale classes are placed in
|
29
|
-
# install
|
28
|
+
# Locale classes are placed in `R18n::Locales` module and storage
|
29
|
+
# install `locales/` dir.
|
30
30
|
#
|
31
|
-
# Each locale has
|
31
|
+
# Each locale has `sublocales` – often known languages for people from this
|
32
32
|
# locale. For example, many Belorussians know Russian and English. If there
|
33
|
-
# is
|
33
|
+
# is't translation for Belorussian, it will be searched in Russian and next in
|
34
34
|
# English translations.
|
35
35
|
#
|
36
36
|
# == Usage
|
@@ -44,78 +44,97 @@ module R18n
|
|
44
44
|
#
|
45
45
|
# == Available data
|
46
46
|
#
|
47
|
-
# *
|
48
|
-
# *
|
49
|
-
# *
|
47
|
+
# * `code` – locale RFC 3066 code;
|
48
|
+
# * `title` – locale name on it language;
|
49
|
+
# * `ltr?` – true on left-to-right writing direction, false for Arabic and
|
50
50
|
# Hebrew);
|
51
|
-
# *
|
52
|
-
# *
|
51
|
+
# * `sublocales` – often known languages for people from this locale;
|
52
|
+
# * `week_start` – does week start from `:monday` or `:sunday`.
|
53
53
|
#
|
54
54
|
# You can see more available data about locale in samples in
|
55
|
-
#
|
55
|
+
# `locales/` dir.
|
56
56
|
class Locale
|
57
|
-
|
57
|
+
@loaded = {}
|
58
58
|
|
59
|
-
|
59
|
+
class << self
|
60
|
+
# Is `locale` constant defined?
|
61
|
+
def exists?(locale)
|
62
|
+
locale = sanitize_code locale
|
63
|
+
name = capitalize(locale)
|
64
|
+
return false unless name
|
60
65
|
|
61
|
-
|
62
|
-
def self.available
|
63
|
-
Dir.glob(File.join(LOCALES_DIR, '*.rb')).map do |i|
|
64
|
-
File.basename(i, '.rb')
|
66
|
+
R18n::Locales.const_defined?(name)
|
65
67
|
end
|
66
|
-
end
|
67
68
|
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
end
|
69
|
+
def sanitize_code(code)
|
70
|
+
code.to_s.gsub(/[^-_a-zA-Z]/, '').tr('_', '-').downcase
|
71
|
+
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
73
|
+
def capitalize(code)
|
74
|
+
lang, region = code.gsub(/\..+/, '').split('-')
|
75
|
+
return unless lang
|
76
|
+
|
77
|
+
lang.capitalize!
|
78
|
+
return lang unless region
|
79
|
+
|
80
|
+
region.size > 2 ? region.capitalize! : region.upcase!
|
81
|
+
"#{lang}#{region}"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Load locale by RFC 3066 `code`.
|
85
|
+
def load(code)
|
86
|
+
code = sanitize_code code
|
87
|
+
name = capitalize(code)
|
88
|
+
return unless name
|
89
|
+
|
90
|
+
@loaded[code] ||= begin
|
91
|
+
if exists?(code)
|
92
|
+
R18n::Locales.const_get(name).new
|
93
|
+
else
|
94
|
+
UnsupportedLocale.new(code)
|
95
|
+
end
|
85
96
|
end
|
86
97
|
end
|
87
|
-
end
|
88
98
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
99
|
+
# Set locale `properties`. Locale class will have methods
|
100
|
+
# for each property name, which return property value:
|
101
|
+
#
|
102
|
+
# class R18n::Locales::En < R18n::Locale
|
103
|
+
# set title: 'English',
|
104
|
+
# code: 'en'
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# locale = R18n::Locales::En.new
|
108
|
+
# locale.title #=> "English"
|
109
|
+
# locale.code #=> "en"
|
110
|
+
def set(properties)
|
111
|
+
properties.each_pair do |key, value|
|
112
|
+
undef_method key if method_defined? key
|
113
|
+
define_method(key) { value }
|
114
|
+
end
|
103
115
|
end
|
104
116
|
end
|
105
117
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
118
|
+
attr_reader :code, :language, :region, :downcased_code, :parent
|
119
|
+
|
120
|
+
def initialize
|
121
|
+
language, region =
|
122
|
+
self.class.name.split('::').last.split(/([A-Z][a-z]+)/)[1, 2]
|
123
|
+
@language = language.downcase.freeze
|
124
|
+
@region = region.upcase.freeze if region
|
125
|
+
@code = "#{@language}#{"-#{region}" if region}"
|
126
|
+
@downcased_code = @code.downcase.tr('-', '_').freeze
|
127
|
+
|
128
|
+
@parent = self.class.superclass.new
|
111
129
|
end
|
112
130
|
|
113
|
-
set sublocales:
|
114
|
-
week_start:
|
115
|
-
time_am:
|
116
|
-
time_pm:
|
117
|
-
time_format: '_ %
|
118
|
-
|
131
|
+
set sublocales: [],
|
132
|
+
week_start: :monday,
|
133
|
+
time_am: 'AM',
|
134
|
+
time_pm: 'PM',
|
135
|
+
time_format: '_ %R',
|
136
|
+
time_with_seconds_format: '_ %T',
|
137
|
+
full_format: '%-d %B',
|
119
138
|
year_format: '_ %Y'
|
120
139
|
|
121
140
|
def month_standalone
|
@@ -150,14 +169,14 @@ module R18n
|
|
150
169
|
"Locale #{code} (#{title})"
|
151
170
|
end
|
152
171
|
|
153
|
-
# Convert
|
154
|
-
# and DateTime
|
172
|
+
# Convert `object` to `String`. It support `Integer`, `Float`, `Time`,
|
173
|
+
# `Date` and `DateTime`.
|
155
174
|
#
|
156
|
-
# For time classes you can set
|
157
|
-
#
|
158
|
-
#
|
159
|
-
# name. Default format is
|
160
|
-
def localize(obj, format = nil, *
|
175
|
+
# For time classes you can set `format` in standard `strftime` form,
|
176
|
+
# `:full` ("01 Jule, 2009"), `:human` ("yesterday"),
|
177
|
+
# `:standard` ("07/01/09") or `:month` for standalone month
|
178
|
+
# name. Default format is `:standard`.
|
179
|
+
def localize(obj, format = nil, *args, **kwargs)
|
161
180
|
case obj
|
162
181
|
when Integer
|
163
182
|
format_integer(obj)
|
@@ -166,7 +185,7 @@ module R18n
|
|
166
185
|
when Time, DateTime, Date
|
167
186
|
return strftime(obj, format) if format.is_a? String
|
168
187
|
return month_standalone[obj.month - 1] if format == :month
|
169
|
-
return obj.to_s if format == :human && !
|
188
|
+
return obj.to_s if format == :human && !kwargs.key?(:i18n)
|
170
189
|
|
171
190
|
type = obj.is_a?(Date) && !obj.is_a?(DateTime) ? 'date' : 'time'
|
172
191
|
format ||= :standard
|
@@ -176,17 +195,22 @@ module R18n
|
|
176
195
|
raise ArgumentError, "Unknown time formatter #{format}"
|
177
196
|
end
|
178
197
|
|
179
|
-
send format_method_name, obj, *
|
198
|
+
send format_method_name, obj, *args, **kwargs
|
180
199
|
else
|
181
|
-
|
200
|
+
format_method_name =
|
201
|
+
"format_#{Utils.underscore(obj.class.name).tr('/', '_')}_#{format}"
|
202
|
+
|
203
|
+
return obj.to_s unless respond_to? format_method_name
|
204
|
+
|
205
|
+
send format_method_name, obj, *args, **kwargs
|
182
206
|
end
|
183
207
|
end
|
184
208
|
|
185
|
-
# Returns the integer in String form, according to the rules
|
186
|
-
# It will also put real typographic minus.
|
209
|
+
# Returns the integer in `String` form, according to the rules
|
210
|
+
# of the locale. It will also put real typographic minus.
|
187
211
|
def format_integer(integer)
|
188
212
|
str = integer.to_s
|
189
|
-
str[0] = '−' if integer
|
213
|
+
str[0] = '−' if integer.negative? # Real typographic minus
|
190
214
|
group = number_group
|
191
215
|
|
192
216
|
str.gsub(/(\d)(?=(\d\d\d)+(?!\d))/) do |match|
|
@@ -194,16 +218,16 @@ module R18n
|
|
194
218
|
end
|
195
219
|
end
|
196
220
|
|
197
|
-
# Returns the float in String form, according to the rules of the locale.
|
221
|
+
# Returns the float in `String` form, according to the rules of the locale.
|
198
222
|
# It will also put real typographic minus.
|
199
223
|
def format_float(float)
|
200
224
|
decimal = number_decimal
|
201
225
|
format_integer(float.to_i) + decimal + float.to_s.split('.').last
|
202
226
|
end
|
203
227
|
|
204
|
-
# Same that
|
205
|
-
# names. In
|
206
|
-
# you can use standard
|
228
|
+
# Same that `Time.strftime`, but translate months and week days
|
229
|
+
# names. In `time` you can use `Time`, `DateTime` or `Date` object.
|
230
|
+
# In `format` you can use standard `strftime` format.
|
207
231
|
def strftime(time, format)
|
208
232
|
translated = ''
|
209
233
|
format.scan(/%[EO]?.|./o) do |c|
|
@@ -226,48 +250,50 @@ module R18n
|
|
226
250
|
time.strftime(translated)
|
227
251
|
end
|
228
252
|
|
229
|
-
# Format
|
230
|
-
def format_time(date, time)
|
231
|
-
strftime(
|
253
|
+
# Format `time` and set `date`
|
254
|
+
def format_time(date, time, with_seconds: false, **_kwargs)
|
255
|
+
strftime(
|
256
|
+
time, with_seconds ? time_with_seconds_format : time_format
|
257
|
+
).sub('_', date.to_s)
|
232
258
|
end
|
233
259
|
|
234
|
-
# Format
|
235
|
-
#
|
236
|
-
# time. For special cases you can replace it in locale
|
237
|
-
def format_time_human(time, i18n
|
260
|
+
# Format `time` in human usable form. For example "5 minutes ago" or
|
261
|
+
# "yesterday". In `now` you can set base time, which be used to get relative
|
262
|
+
# time. For special cases you can replace it in locale's class.
|
263
|
+
def format_time_human(time, i18n:, now: time.class.now, **_kwargs)
|
238
264
|
diff = time - now
|
239
265
|
minutes = time.is_a?(DateTime) ? diff * 24 * 60.0 : diff / 60.0
|
240
266
|
diff = minutes.abs
|
241
267
|
if (diff > 24 * 60) || (time.mday != now.mday && diff > 12 * 24)
|
242
|
-
format_time(format_date_human(time.to_date,
|
268
|
+
format_time(format_date_human(time.to_date, now: now.to_date, i18n: i18n), time)
|
243
269
|
elsif minutes > -1 && minutes < 1
|
244
270
|
i18n.human_time.now
|
245
271
|
elsif minutes >= 60
|
246
272
|
i18n.human_time.after_hours((diff / 60.0).floor)
|
247
273
|
elsif minutes <= -60
|
248
274
|
i18n.human_time.hours_ago((diff / 60.0).floor)
|
249
|
-
elsif minutes
|
275
|
+
elsif minutes.positive?
|
250
276
|
i18n.human_time.after_minutes(minutes.round)
|
251
277
|
else
|
252
278
|
i18n.human_time.minutes_ago(minutes.round.abs)
|
253
279
|
end
|
254
280
|
end
|
255
281
|
|
256
|
-
# Format
|
257
|
-
def format_time_standard(time, *
|
258
|
-
format_time(format_date_standard(time), time)
|
282
|
+
# Format `time` in compact form. For example, "12/31/09 12:59".
|
283
|
+
def format_time_standard(time, *args, **kwargs)
|
284
|
+
format_time(format_date_standard(time), time, *args, **kwargs)
|
259
285
|
end
|
260
286
|
|
261
|
-
# Format
|
262
|
-
# 12:59
|
263
|
-
def format_time_full(time,
|
264
|
-
format_time(format_date_full(time), time)
|
287
|
+
# Format `time` in most official form. For example, "December 31st, 2009
|
288
|
+
# 12:59". For special cases you can replace it in locale's class.
|
289
|
+
def format_time_full(time, **kwargs)
|
290
|
+
format_time(format_date_full(time, **kwargs), time, **kwargs)
|
265
291
|
end
|
266
292
|
|
267
|
-
# Format
|
268
|
-
#
|
269
|
-
#
|
270
|
-
def format_date_human(date,
|
293
|
+
# Format `date` in human usable form. For example "5 days ago" or "yesterday".
|
294
|
+
# In `:now` you can set base time, which be used to get relative time.
|
295
|
+
# For special cases you can replace it in locale's class.
|
296
|
+
def format_date_human(date, *_args, i18n:, now: Date.today, **_kwargs)
|
271
297
|
days = (date - now).to_i
|
272
298
|
case days
|
273
299
|
when -6..-2
|
@@ -281,28 +307,28 @@ module R18n
|
|
281
307
|
when 2..6
|
282
308
|
i18n.human_time.after_days(days)
|
283
309
|
else
|
284
|
-
format_date_full(date, date.year != now.year)
|
310
|
+
format_date_full(date, year: date.year != now.year)
|
285
311
|
end
|
286
312
|
end
|
287
313
|
|
288
|
-
# Format
|
314
|
+
# Format `date` in compact form. For example, "12/31/09".
|
289
315
|
def format_date_standard(date, *_params)
|
290
316
|
strftime(date, date_format)
|
291
317
|
end
|
292
318
|
|
293
|
-
# Format
|
294
|
-
# For special cases you can replace it in locale
|
319
|
+
# Format `date` in most official form. For example, "December 31st, 2009".
|
320
|
+
# For special cases you can replace it in locale's class. If `year` is false
|
295
321
|
# date will be without year.
|
296
|
-
def format_date_full(date, year
|
322
|
+
def format_date_full(date, year: true, **_kwargs)
|
297
323
|
format = full_format
|
298
324
|
format = year_format.sub('_', format) if year
|
299
325
|
strftime(date, format)
|
300
326
|
end
|
301
327
|
|
302
|
-
# Return pluralization type for
|
303
|
-
# cases you can replace it in locale
|
304
|
-
def pluralize(
|
305
|
-
case
|
328
|
+
# Return pluralization type for `number` of items. This is simple form.
|
329
|
+
# For special cases you can replace it in locale's class.
|
330
|
+
def pluralize(number)
|
331
|
+
case number
|
306
332
|
when 0
|
307
333
|
0
|
308
334
|
when 1
|
@@ -314,5 +340,9 @@ module R18n
|
|
314
340
|
end
|
315
341
|
|
316
342
|
# Namespace for Locale sub-classes
|
317
|
-
module Locales
|
343
|
+
module Locales
|
344
|
+
Dir.glob(File.join(__dir__, 'locales', '*.rb')) do |file|
|
345
|
+
autoload Locale.capitalize(File.basename(file, '.*')), file
|
346
|
+
end
|
347
|
+
end
|
318
348
|
end
|