r18n-core 3.2.0 → 4.0.0

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