r18n-core 2.2.0 → 3.0.0

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.
Files changed (88) hide show
  1. checksums.yaml +5 -5
  2. data/.rspec +1 -1
  3. data/ChangeLog.md +6 -1
  4. data/README.md +1 -20
  5. data/Rakefile +5 -3
  6. data/lib/r18n-core.rb +55 -55
  7. data/lib/r18n-core/filter_list.rb +34 -36
  8. data/lib/r18n-core/filters.rb +68 -51
  9. data/lib/r18n-core/helpers.rb +17 -17
  10. data/lib/r18n-core/i18n.rb +46 -39
  11. data/lib/r18n-core/locale.rb +79 -70
  12. data/lib/r18n-core/translated.rb +65 -66
  13. data/lib/r18n-core/translated_string.rb +24 -24
  14. data/lib/r18n-core/translation.rb +31 -30
  15. data/lib/r18n-core/unsupported_locale.rb +22 -24
  16. data/lib/r18n-core/untranslated.rb +35 -33
  17. data/lib/r18n-core/utils.rb +26 -25
  18. data/lib/r18n-core/version.rb +4 -1
  19. data/lib/r18n-core/yaml_loader.rb +26 -25
  20. data/lib/r18n-core/yaml_methods.rb +25 -28
  21. data/locales/af.rb +15 -8
  22. data/locales/az.rb +19 -12
  23. data/locales/bg.rb +16 -9
  24. data/locales/ca.rb +16 -9
  25. data/locales/cs.rb +27 -20
  26. data/locales/da.rb +15 -8
  27. data/locales/de.rb +16 -9
  28. data/locales/en-au.rb +10 -5
  29. data/locales/en-gb.rb +12 -5
  30. data/locales/en-us.rb +12 -5
  31. data/locales/en.rb +29 -22
  32. data/locales/eo.rb +14 -7
  33. data/locales/es-us.rb +12 -5
  34. data/locales/es.rb +14 -7
  35. data/locales/fa.rb +48 -32
  36. data/locales/fi.rb +19 -12
  37. data/locales/fr.rb +22 -15
  38. data/locales/gl.rb +15 -8
  39. data/locales/hr.rb +24 -17
  40. data/locales/hu.rb +28 -21
  41. data/locales/id.rb +14 -7
  42. data/locales/it.rb +21 -14
  43. data/locales/ja.rb +15 -8
  44. data/locales/kk.rb +17 -10
  45. data/locales/ko.rb +15 -9
  46. data/locales/lv.rb +24 -17
  47. data/locales/mn.rb +10 -3
  48. data/locales/nb.rb +15 -8
  49. data/locales/nl.rb +15 -8
  50. data/locales/no.rb +11 -16
  51. data/locales/pl.rb +26 -19
  52. data/locales/pt-br.rb +12 -5
  53. data/locales/pt.rb +17 -10
  54. data/locales/ru.rb +26 -19
  55. data/locales/sk.rb +27 -20
  56. data/locales/sr-latn.rb +27 -22
  57. data/locales/sv-se.rb +15 -8
  58. data/locales/th.rb +27 -20
  59. data/locales/tr.rb +16 -9
  60. data/locales/uk.rb +19 -12
  61. data/locales/vi.rb +14 -7
  62. data/locales/zh-cn.rb +12 -5
  63. data/locales/zh-tw.rb +15 -8
  64. data/locales/zh.rb +14 -7
  65. data/r18n-core.gemspec +5 -3
  66. data/spec/filters_spec.rb +71 -67
  67. data/spec/i18n_spec.rb +73 -51
  68. data/spec/locale_spec.rb +73 -68
  69. data/spec/locales/cs_spec.rb +2 -2
  70. data/spec/locales/en-us_spec.rb +9 -9
  71. data/spec/locales/en_spec.rb +2 -2
  72. data/spec/locales/fa_spec.rb +3 -3
  73. data/spec/locales/fr_spec.rb +2 -2
  74. data/spec/locales/hu_spec.rb +7 -7
  75. data/spec/locales/it_spec.rb +3 -3
  76. data/spec/locales/no_spec.rb +9 -0
  77. data/spec/locales/pl_spec.rb +2 -2
  78. data/spec/locales/ru_spec.rb +2 -2
  79. data/spec/locales/sk_spec.rb +2 -2
  80. data/spec/locales/th_spec.rb +2 -2
  81. data/spec/locales/vi_spec.rb +2 -2
  82. data/spec/r18n_spec.rb +44 -38
  83. data/spec/spec_helper.rb +13 -9
  84. data/spec/translated_spec.rb +48 -31
  85. data/spec/translation_spec.rb +29 -27
  86. data/spec/translations/general/en.yml +0 -2
  87. data/spec/yaml_loader_spec.rb +22 -18
  88. metadata +5 -3
@@ -1,21 +1,21 @@
1
- =begin
2
- Mixin with common methods.
1
+ # frozen_string_literal: true
3
2
 
4
- Copyright (C) 2010 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
5
-
6
- This program is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Lesser General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- This program is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Lesser General Public License for more details.
15
-
16
- You should have received a copy of the GNU Lesser General Public License
17
- along with this program. If not, see <http://www.gnu.org/licenses/>.
18
- =end
3
+ # Mixin with common methods.
4
+ #
5
+ # Copyright (C) 2010 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
  module R18n
21
21
  # Useful aliases. Set I18n object before use them:
@@ -1,24 +1,23 @@
1
- =begin
2
- I18n support.
1
+ # frozen_string_literal: true
3
2
 
4
- Copyright (C) 2008 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
5
-
6
- This program is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Lesser General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- This program is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Lesser General Public License for more details.
15
-
16
- You should have received a copy of the GNU Lesser General Public License
17
- along with this program. If not, see <http://www.gnu.org/licenses/>.
18
- =end
3
+ # I18n support.
4
+ #
5
+ # Copyright (C) 2008 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
19
19
 
20
20
  require 'date'
21
- require 'pathname'
22
21
 
23
22
  module R18n
24
23
  # General class to i18n support in your application. It load Translation and
@@ -103,7 +102,7 @@ module R18n
103
102
  locales = str.split(',')
104
103
  locales.map! do |locale|
105
104
  locale = locale.split ';q='
106
- if 1 == locale.size
105
+ if locale.size == 1
107
106
  [locale[0], 1.0]
108
107
  else
109
108
  [locale[0], locale[1].to_f]
@@ -117,7 +116,7 @@ module R18n
117
116
  # argument.
118
117
  def self.convert_places(places)
119
118
  Array(places).map! do |loader|
120
- if loader.respond_to? :available and loader.respond_to? :load
119
+ if loader.respond_to?(:available) && loader.respond_to?(:load)
121
120
  loader
122
121
  else
123
122
  R18n.default_loader.new(loader)
@@ -144,7 +143,7 @@ module R18n
144
143
  def initialize(locales, translation_places = nil, opts = {})
145
144
  locales = Array(locales)
146
145
 
147
- if not locales.empty? and Locale.exists? locales.first
146
+ if !locales.empty? && Locale.exists?(locales.first)
148
147
  locales += Locale.load(locales.first).sublocales
149
148
  end
150
149
  locales << @@default
@@ -166,14 +165,15 @@ module R18n
166
165
 
167
166
  @translation_places = self.class.convert_places(@original_places)
168
167
 
169
- if opts[:on_filters] or opts[:off_filters]
170
- @filters = CustomFilterList.new(opts[:on_filters], opts[:off_filters])
171
- else
172
- @filters = GlobalFilterList.instance
173
- end
168
+ @filters =
169
+ if opts[:on_filters] || opts[:off_filters]
170
+ CustomFilterList.new(opts[:on_filters], opts[:off_filters])
171
+ else
172
+ GlobalFilterList.instance
173
+ end
174
174
 
175
175
  key = translation_cache_key
176
- if R18n.cache.has_key? key
176
+ if R18n.cache.key? key
177
177
  @locale, @translation = *R18n.cache[key]
178
178
  else
179
179
  reload!
@@ -187,8 +187,9 @@ module R18n
187
187
 
188
188
  # Return unique key for current locales in translation and places.
189
189
  def translation_cache_key
190
- @available_codes ||= @translation_places.inject([]) { |all, i|
191
- all + i.available }.uniq.map { |i| i.code.downcase }
190
+ @available_codes ||= @translation_places
191
+ .inject([]) { |all, i| all + i.available }
192
+ .uniq.map { |i| i.code.downcase }
192
193
  (@locales_codes & @available_codes).join(',') + '@' +
193
194
  @filters.hash.to_s + '_' +
194
195
  R18n.default_loader.hash.to_s + '_' +
@@ -202,18 +203,22 @@ module R18n
202
203
  @translation_places = self.class.convert_places(@original_places)
203
204
 
204
205
  available_in_places = @translation_places.map { |i| [i, i.available] }
205
- available_in_extensions = R18n.extension_places.map {|i| [i, i.available]}
206
+ available_in_extensions =
207
+ R18n.extension_places.map { |i| [i, i.available] }
206
208
 
207
- unless @locale
208
- available_in_places.each do |place, available|
209
+ unless defined? @locale
210
+ # It's array!
211
+ # rubocop:disable Perfomance/HashEachMethods
212
+ available_in_places.each do |_place, available|
209
213
  @locales.each do |locale|
210
214
  if available.include? locale
211
215
  @locale = locale
212
216
  break
213
217
  end
214
218
  end
215
- break if @locale
219
+ break if defined? @locale
216
220
  end
221
+ # rubocop:enable Perfomance/HashEachMethods
217
222
  end
218
223
  @locale ||= @locales.first
219
224
  unless @locale.supported?
@@ -228,17 +233,19 @@ module R18n
228
233
  @translation = Translation.new(@locale, '', filters: @filters)
229
234
  @locales.each do |locale|
230
235
  loaded = false
236
+
231
237
  available_in_places.each do |place, available|
232
238
  if available.include? locale
233
239
  @translation.merge! place.load(locale), locale
234
240
  loaded = true
235
241
  end
236
242
  end
237
- if loaded
238
- available_in_extensions.each do |extension, available|
239
- if available.include? locale
240
- @translation.merge! extension.load(locale), locale
241
- end
243
+
244
+ next unless loaded
245
+
246
+ available_in_extensions.each do |extension, available|
247
+ if available.include? locale
248
+ @translation.merge! extension.load(locale), locale
242
249
  end
243
250
  end
244
251
  end
@@ -267,7 +274,7 @@ module R18n
267
274
  def localize(object, format = nil, *params)
268
275
  locale.localize(object, format, self, *params)
269
276
  end
270
- alias :l :localize
277
+ alias l localize
271
278
 
272
279
  # Return translations.
273
280
  def t
@@ -1,23 +1,22 @@
1
- =begin
2
- Locale to i18n support.
1
+ # frozen_string_literal: true
2
+
3
+ # Locale to i18n support.
4
+ #
5
+ # Copyright (C) 2008 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
6
+ #
7
+ # This program is free software: you can redistribute it and/or modify
8
+ # it under the terms of the GNU Lesser General Public License as published by
9
+ # the Free Software Foundation, either version 3 of the License, or
10
+ # (at your option) any later version.
11
+ #
12
+ # This program is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ # GNU Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public License
18
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
3
19
 
4
- Copyright (C) 2008 Andrey “A.I.” Sitnik <andrey@sitnik.ru>
5
-
6
- This program is free software: you can redistribute it and/or modify
7
- it under the terms of the GNU Lesser General Public License as published by
8
- the Free Software Foundation, either version 3 of the License, or
9
- (at your option) any later version.
10
-
11
- This program is distributed in the hope that it will be useful,
12
- but WITHOUT ANY WARRANTY; without even the implied warranty of
13
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
- GNU Lesser General Public License for more details.
15
-
16
- You should have received a copy of the GNU Lesser General Public License
17
- along with this program. If not, see <http://www.gnu.org/licenses/>.
18
- =end
19
-
20
- require 'pathname'
21
20
  require 'singleton'
22
21
  require 'bigdecimal'
23
22
 
@@ -55,7 +54,7 @@ module R18n
55
54
  # You can see more available data about locale in samples in
56
55
  # <tt>locales/</tt> dir.
57
56
  class Locale
58
- LOCALES_DIR = Pathname(__FILE__).dirname.expand_path + '../../locales/'
57
+ LOCALES_DIR = File.join(__dir__, '..', '..', 'locales')
59
58
 
60
59
  @@loaded = {}
61
60
 
@@ -68,19 +67,19 @@ module R18n
68
67
 
69
68
  # Is +locale+ has info file.
70
69
  def self.exists?(locale)
71
- File.exists?(File.join(LOCALES_DIR, locale.to_s + '.rb'))
70
+ File.exist?(File.join(LOCALES_DIR, "#{locale}.rb"))
72
71
  end
73
72
 
74
73
  # Load locale by RFC 3066 +code+.
75
74
  def self.load(code)
76
75
  original = code.to_s.gsub(/[^-_a-zA-Z]/, '')
77
- code = original.gsub('_', '-').downcase
76
+ code = original.tr('_', '-').downcase
78
77
 
79
78
  @@loaded[code] ||= begin
80
79
  if exists? code
81
- require LOCALES_DIR.join("#{code}.rb").to_s
82
- name = code.gsub(/[\w\d]+/) { |i| i.capitalize }.gsub('-', '')
83
- eval('R18n::Locales::' + name).new
80
+ require File.join(LOCALES_DIR, "#{code}.rb")
81
+ name = code.gsub(/\w+/, &:capitalize).delete('-')
82
+ R18n::Locales.const_get(name).new
84
83
  else
85
84
  UnsupportedLocale.new(original)
86
85
  end
@@ -111,7 +110,7 @@ module R18n
111
110
  lang.downcase + (culture ? '-' + culture.upcase : '')
112
111
  end
113
112
 
114
- set sublocales: %w{en},
113
+ set sublocales: %w[en],
115
114
  week_start: :monday,
116
115
  time_am: 'AM',
117
116
  time_pm: 'PM',
@@ -119,16 +118,26 @@ module R18n
119
118
  full_format: '%e %B',
120
119
  year_format: '_ %Y'
121
120
 
122
- def month_standalone; month_names; end
123
- def month_abbrs; month_names; end
124
- def wday_abbrs; wday_names; end
121
+ def month_standalone
122
+ month_names
123
+ end
124
+
125
+ def month_abbrs
126
+ month_names
127
+ end
128
+
129
+ def wday_abbrs
130
+ wday_names
131
+ end
125
132
 
126
133
  # Is locale has left-to-right write direction.
127
- def ltr?; true; end
134
+ def ltr?
135
+ true
136
+ end
128
137
 
129
138
  # Is another locale has same code.
130
- def ==(locale)
131
- self.class == locale.class
139
+ def ==(other)
140
+ self.class == other.class
132
141
  end
133
142
 
134
143
  # Is locale has information file. In this class always return true.
@@ -156,13 +165,13 @@ module R18n
156
165
  format_float(obj.to_f)
157
166
  when Time, DateTime, Date
158
167
  return strftime(obj, format) if format.is_a? String
159
- return month_standalone[obj.month - 1] if :month == format
160
- return obj.to_s if :human == format and not params.first.is_a? I18n
168
+ return month_standalone[obj.month - 1] if format == :month
169
+ return obj.to_s if format == :human && !params.first.is_a?(I18n)
161
170
 
162
171
  type = obj.is_a?(Date) && !obj.is_a?(DateTime) ? 'date' : 'time'
163
- format = :standard unless format
172
+ format ||= :standard
164
173
 
165
- unless [:human, :full, :standard].include? format
174
+ unless %i[human full standard].include? format
166
175
  raise ArgumentError, "Unknown time formatter #{format}"
167
176
  end
168
177
 
@@ -176,7 +185,7 @@ module R18n
176
185
  # It will also put real typographic minus.
177
186
  def format_integer(integer)
178
187
  str = integer.to_s
179
- str[0] = '−' if 0 > integer # Real typographic minus
188
+ str[0] = '−' if integer < 0 # Real typographic minus
180
189
  group = number_group
181
190
 
182
191
  str.gsub(/(\d)(?=(\d\d\d)+(?!\d))/) do |match|
@@ -188,7 +197,7 @@ module R18n
188
197
  # It will also put real typographic minus.
189
198
  def format_float(float)
190
199
  decimal = number_decimal
191
- self.format_integer(float.to_i) + decimal + float.to_s.split('.').last
200
+ format_integer(float.to_i) + decimal + float.to_s.split('.').last
192
201
  end
193
202
 
194
203
  # Same that <tt>Time.strftime</tt>, but translate months and week days
@@ -197,20 +206,21 @@ module R18n
197
206
  def strftime(time, format)
198
207
  translated = ''
199
208
  format.scan(/%[EO]?.|./o) do |c|
200
- case c.sub(/^%[EO]?(.)$/o, '%\\1')
201
- when '%A'
202
- translated << wday_names[time.wday]
203
- when '%a'
204
- translated << wday_abbrs[time.wday]
205
- when '%B'
206
- translated << month_names[time.month - 1]
207
- when '%b'
208
- translated << month_abbrs[time.month - 1]
209
- when '%p'
210
- translated << (time.hour < 12 ? time_am : time_pm)
211
- else
212
- translated << c
213
- end
209
+ translated +=
210
+ case c.sub(/^%[EO]?(.)$/o, '%\\1')
211
+ when '%A'
212
+ wday_names[time.wday]
213
+ when '%a'
214
+ wday_abbrs[time.wday]
215
+ when '%B'
216
+ month_names[time.month - 1]
217
+ when '%b'
218
+ month_abbrs[time.month - 1]
219
+ when '%p'
220
+ time.hour < 12 ? time_am : time_pm
221
+ else
222
+ c
223
+ end
214
224
  end
215
225
  time.strftime(translated)
216
226
  end
@@ -223,42 +233,40 @@ module R18n
223
233
  # Format +time+ in human usable form. For example “5 minutes ago” or
224
234
  # “yesterday”. In +now+ you can set base time, which be used to get relative
225
235
  # time. For special cases you can replace it in locale’s class.
226
- def format_time_human(time, i18n, now = Time.now, *params)
236
+ def format_time_human(time, i18n, now = Time.now, *_params)
227
237
  diff = time - now
228
238
  minutes = time.is_a?(DateTime) ? diff * 24 * 60.0 : diff / 60.0
229
239
  diff = minutes.abs
230
- if (diff > 24 * 60) or (time.mday != now.mday and diff > 12 * 24)
240
+ if (diff > 24 * 60) || (time.mday != now.mday && diff > 12 * 24)
231
241
  format_time(format_date_human(time.to_date, i18n, now.to_date), time)
242
+ elsif minutes > -1 && minutes < 1
243
+ i18n.human_time.now
244
+ elsif minutes >= 60
245
+ i18n.human_time.after_hours((diff / 60.0).floor)
246
+ elsif minutes <= -60
247
+ i18n.human_time.hours_ago((diff / 60.0).floor)
248
+ elsif minutes > 0
249
+ i18n.human_time.after_minutes(minutes.round)
232
250
  else
233
- if -1 < minutes and 1 > minutes
234
- i18n.human_time.now
235
- elsif 60 <= minutes
236
- i18n.human_time.after_hours((diff / 60.0).floor)
237
- elsif -60 >= minutes
238
- i18n.human_time.hours_ago((diff / 60.0).floor)
239
- elsif 0 < minutes
240
- i18n.human_time.after_minutes(minutes.round)
241
- else
242
- i18n.human_time.minutes_ago(minutes.round.abs)
243
- end
251
+ i18n.human_time.minutes_ago(minutes.round.abs)
244
252
  end
245
253
  end
246
254
 
247
255
  # Format +time+ in compact form. For example, “12/31/09 12:59”.
248
- def format_time_standard(time, *params)
256
+ def format_time_standard(time, *_params)
249
257
  format_time(format_date_standard(time), time)
250
258
  end
251
259
 
252
260
  # Format +time+ in most official form. For example, “December 31st, 2009
253
261
  # 12:59”. For special cases you can replace it in locale’s class.
254
- def format_time_full(time, *params)
262
+ def format_time_full(time, *_params)
255
263
  format_time(format_date_full(time), time)
256
264
  end
257
265
 
258
266
  # Format +date+ in human usable form. For example “5 days ago” or
259
267
  # “yesterday”. In +now+ you can set base time, which be used to get relative
260
268
  # time. For special cases you can replace it in locale’s class.
261
- def format_date_human(date, i18n, now = Date.today, *params)
269
+ def format_date_human(date, i18n, now = Date.today, *_params)
262
270
  days = (date - now).to_i
263
271
  case days
264
272
  when -6..-2
@@ -277,14 +285,14 @@ module R18n
277
285
  end
278
286
 
279
287
  # Format +date+ in compact form. For example, “12/31/09”.
280
- def format_date_standard(date, *params)
288
+ def format_date_standard(date, *_params)
281
289
  strftime(date, date_format)
282
290
  end
283
291
 
284
292
  # Format +date+ in most official form. For example, “December 31st, 2009”.
285
293
  # For special cases you can replace it in locale’s class. If +year+ is false
286
294
  # date will be without year.
287
- def format_date_full(date, year = true, *params)
295
+ def format_date_full(date, year = true, *_params)
288
296
  format = full_format
289
297
  format = year_format.sub('_', format) if year
290
298
  strftime(date, format)
@@ -304,5 +312,6 @@ module R18n
304
312
  end
305
313
  end
306
314
 
315
+ # Namespace for Locale sub-classes
307
316
  module Locales; end
308
317
  end