num2words 0.3.1 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +32 -0
- data/Gemfile +1 -0
- data/README.md +87 -0
- data/config/locales/en.yml +4 -0
- data/config/locales/ru.yml +4 -0
- data/docs/api.md +116 -4
- data/docs/api.ru.md +116 -4
- data/docs/rails.md +141 -0
- data/docs/rails.ru.md +141 -0
- data/lib/num2words/config.rb +98 -0
- data/lib/num2words/converter.rb +10 -6
- data/lib/num2words/errors.rb +49 -0
- data/lib/num2words/rails/helpers.rb +27 -0
- data/lib/num2words/rails/validators/currency_validator.rb +30 -0
- data/lib/num2words/rails/validators/locale_validator.rb +22 -0
- data/lib/num2words/railtie.rb +27 -0
- data/lib/num2words/version.rb +1 -1
- data/lib/num2words.rb +3 -0
- metadata +9 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 131bb24135ba3f8c1345bbd7ccf5c3b27d79b9c9776d7e0ec45b259960be1dbd
|
|
4
|
+
data.tar.gz: 27a943ef2bbaae410ae51d1aca3fe009375f68632e1928b4639a570919619c25
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3601c493e2cf40b2a908daca5980f79c95933316fa2a87393306c479919ec795c15af731e2eb075fd92b9aa61a97fd72badaa575723d8201e5093cecc89e6d88
|
|
7
|
+
data.tar.gz: 5000cdf5a8fcaa4cf2af57cb2ad7640e111f9f2a1eb7fdf94783ac19a76a2cd8aedd2ef44cbecd7eee9647d3bb1be064f2d70f711634aa3de679f83ede17a47d
|
data/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,38 @@
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [0.5.0] - 2026-07-06
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
- Опция `strict: true` для `to_currency`, которая вызывает `Num2words::UnsupportedCurrencyError` при недоступной валюте вместо fallback на валюту по умолчанию.
|
|
18
|
+
- Классы ошибок `Num2words::UnsupportedInputError`, `Num2words::UnsupportedOptionError` и `Num2words::UnsupportedCurrencyAmountError`, совместимые с `ArgumentError`.
|
|
19
|
+
- Rails/ActiveModel сообщения ошибок для валидаторов `num2words_currency` и `num2words_locale`.
|
|
20
|
+
- Публичный metadata API `Num2words.currency_options` для select-полей и настроек.
|
|
21
|
+
- Публичный metadata API `Num2words.locale_options` для select-полей и настроек.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## [0.4.0] - 2026-07-05
|
|
26
|
+
|
|
27
|
+
### Added
|
|
28
|
+
- Опциональные Rails helpers и Railtie:
|
|
29
|
+
- `number_to_words`
|
|
30
|
+
- `currency_to_words`
|
|
31
|
+
- `date_to_words`
|
|
32
|
+
- `time_to_words`
|
|
33
|
+
- `datetime_to_words`
|
|
34
|
+
- Интеграционные specs для проверки Railtie в минимальном Rails-приложении.
|
|
35
|
+
- Подключение Rails helpers в controller helper context.
|
|
36
|
+
- Валидатор ActiveModel `num2words_currency` для проверки валюты по локали.
|
|
37
|
+
- Валидатор ActiveModel `num2words_locale` для проверки поддерживаемой локали.
|
|
38
|
+
- Публичный metadata API `Num2words.available_locales`.
|
|
39
|
+
- Публичный metadata API `Num2words.currency_available?`.
|
|
40
|
+
- Публичный metadata API `Num2words.currency_info`.
|
|
41
|
+
- Публичный metadata API `Num2words.default_currency_info`.
|
|
42
|
+
- Документация по Rails-интеграции: `docs/rails.md` и `docs/rails.ru.md`.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
14
46
|
## [0.3.1] - 2026-07-04
|
|
15
47
|
|
|
16
48
|
### Added
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -14,6 +14,9 @@ Ruby-гем для преобразования чисел, дробей, ден
|
|
|
14
14
|
- Даты, время и дата-время.
|
|
15
15
|
- Регистры вывода: `word_case: :upper | :downcase | :capitalize | :title`.
|
|
16
16
|
- Удобные методы для `Integer`, `Float`, `String`, `Date`, `Time`, `DateTime`.
|
|
17
|
+
- Опциональные Rails helpers и Railtie.
|
|
18
|
+
- ActiveModel validators для локалей и валют.
|
|
19
|
+
- Metadata API для локалей и валют.
|
|
17
20
|
- Интерактивная консоль `num2words-console`.
|
|
18
21
|
|
|
19
22
|
---
|
|
@@ -81,6 +84,9 @@ Num2words.to_currency(BigDecimal("21.05"), :ru)
|
|
|
81
84
|
12.50.to_currency(:ru, code: :USD)
|
|
82
85
|
# => "двенадцать долларов пятьдесят центов"
|
|
83
86
|
|
|
87
|
+
Num2words.to_currency(12.50, :ru, code: :XYZ, strict: true)
|
|
88
|
+
# raises Num2words::UnsupportedCurrencyError
|
|
89
|
+
|
|
84
90
|
1.to_currency(:ru, minor: :nonzero)
|
|
85
91
|
# => "один рубль"
|
|
86
92
|
|
|
@@ -142,6 +148,7 @@ Num2words.to_currency(BigDecimal("21.05"), :ru)
|
|
|
142
148
|
- `word_case: :default | :upper | :downcase | :capitalize | :title` — регистр результата.
|
|
143
149
|
- `minor: :always | :nonzero | :never` — вывод младшей денежной единицы.
|
|
144
150
|
- `code: :USD` — выбор валюты для `to_currency`.
|
|
151
|
+
- `strict: true` — ошибка вместо fallback при недоступной валюте в `to_currency`.
|
|
145
152
|
|
|
146
153
|
Полная справка по API:
|
|
147
154
|
|
|
@@ -153,6 +160,86 @@ Num2words.to_currency(BigDecimal("21.05"), :ru)
|
|
|
153
160
|
- [English](docs/limits.md)
|
|
154
161
|
- [Русский](docs/limits.ru.md)
|
|
155
162
|
|
|
163
|
+
Rails-интеграция:
|
|
164
|
+
|
|
165
|
+
- [English](docs/rails.md)
|
|
166
|
+
- [Русский](docs/rails.ru.md)
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## Rails
|
|
171
|
+
|
|
172
|
+
Если Rails доступен, helpers подключаются автоматически через Railtie.
|
|
173
|
+
|
|
174
|
+
```erb
|
|
175
|
+
<%= number_to_words(123, locale: :ru) %>
|
|
176
|
+
<%= currency_to_words(@payment.amount, locale: :ru, code: @payment.currency) %>
|
|
177
|
+
<%= date_to_words(Date.current, locale: I18n.locale) %>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Также доступны ActiveModel validators:
|
|
181
|
+
|
|
182
|
+
```ruby
|
|
183
|
+
class Payment < ApplicationRecord
|
|
184
|
+
validates :currency, num2words_currency: { locale: ->(payment) { payment.locale } }
|
|
185
|
+
validates :locale, num2words_locale: true
|
|
186
|
+
end
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Metadata API
|
|
192
|
+
|
|
193
|
+
```ruby
|
|
194
|
+
Num2words.available_locales
|
|
195
|
+
# => [:ar, :be, :bg, :bn, :cs, ...]
|
|
196
|
+
|
|
197
|
+
Num2words.currency_available?(:ru, :RUB)
|
|
198
|
+
# => true
|
|
199
|
+
|
|
200
|
+
Num2words.currency_info(:ru, :RUB)
|
|
201
|
+
# => {
|
|
202
|
+
# code: :RUB,
|
|
203
|
+
# major_unit: ["рубль", "рубля", "рублей"],
|
|
204
|
+
# minor_unit: ["копейка", "копейки", "копеек"],
|
|
205
|
+
# symbol: "₽"
|
|
206
|
+
# }
|
|
207
|
+
|
|
208
|
+
Num2words.default_currency_info(:ru)
|
|
209
|
+
# => {
|
|
210
|
+
# code: :RUB,
|
|
211
|
+
# major_unit: ["рубль", "рубля", "рублей"],
|
|
212
|
+
# minor_unit: ["копейка", "копейки", "копеек"],
|
|
213
|
+
# symbol: "₽"
|
|
214
|
+
# }
|
|
215
|
+
|
|
216
|
+
Num2words.currency_options(:ru)
|
|
217
|
+
# => [["RUB — ₽", :RUB], ["USD — $", :USD], ...]
|
|
218
|
+
|
|
219
|
+
Num2words.locale_options
|
|
220
|
+
# => [["ar", :ar], ["be", :be], ["bg", :bg], ...]
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
## Ошибки
|
|
226
|
+
|
|
227
|
+
```ruby
|
|
228
|
+
Num2words.to_currency(10, :ru, code: :XYZ, strict: true)
|
|
229
|
+
# raises Num2words::UnsupportedCurrencyError
|
|
230
|
+
|
|
231
|
+
Num2words.to_words(Object.new, :ru)
|
|
232
|
+
# raises Num2words::UnsupportedInputError
|
|
233
|
+
|
|
234
|
+
Num2words.to_words(0.5, :ru, joiner: :plus)
|
|
235
|
+
# raises Num2words::UnsupportedOptionError
|
|
236
|
+
|
|
237
|
+
Num2words.to_currency("abc", :ru)
|
|
238
|
+
# raises Num2words::UnsupportedCurrencyAmountError
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Ошибки пользовательских аргументов наследуются от `ArgumentError`, поэтому существующий код с `rescue ArgumentError` продолжает работать.
|
|
242
|
+
|
|
156
243
|
---
|
|
157
244
|
|
|
158
245
|
## Консоль
|
data/config/locales/en.yml
CHANGED
data/config/locales/ru.yml
CHANGED
data/docs/api.md
CHANGED
|
@@ -318,6 +318,15 @@ Num2words.to_currency(12.50, :ru, code: :USD)
|
|
|
318
318
|
|
|
319
319
|
If the currency is not available for the locale, `num2words` falls back to the locale default currency and may emit a warning depending on configuration.
|
|
320
320
|
|
|
321
|
+
### `strict`
|
|
322
|
+
|
|
323
|
+
For `to_currency`, enables strict currency validation. When `code:` is unavailable for the locale, the method raises `Num2words::UnsupportedCurrencyError` instead of falling back to the default currency.
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
Num2words.to_currency(12.50, :ru, code: :XYZ, strict: true)
|
|
327
|
+
# raises Num2words::UnsupportedCurrencyError
|
|
328
|
+
```
|
|
329
|
+
|
|
321
330
|
### `minor`
|
|
322
331
|
|
|
323
332
|
Controls minor currency unit output.
|
|
@@ -364,6 +373,99 @@ Num2words.available_currencies(:ru)
|
|
|
364
373
|
# => [:RUB, :USD, :EUR, ...]
|
|
365
374
|
```
|
|
366
375
|
|
|
376
|
+
### `Num2words.currency_available?`
|
|
377
|
+
|
|
378
|
+
Checks whether a currency is available for a locale.
|
|
379
|
+
|
|
380
|
+
```ruby
|
|
381
|
+
Num2words.currency_available?(:ru, :RUB)
|
|
382
|
+
# => true
|
|
383
|
+
|
|
384
|
+
Num2words.currency_available?(:ru, "usd")
|
|
385
|
+
# => true
|
|
386
|
+
|
|
387
|
+
Num2words.currency_available?(:ru, :XYZ)
|
|
388
|
+
# => false
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### `Num2words.currency_info`
|
|
392
|
+
|
|
393
|
+
Returns currency metadata for a locale or `nil` when the currency is unavailable.
|
|
394
|
+
|
|
395
|
+
```ruby
|
|
396
|
+
Num2words.currency_info(:ru, :RUB)
|
|
397
|
+
# => {
|
|
398
|
+
# code: :RUB,
|
|
399
|
+
# major_unit: ["рубль", "рубля", "рублей"],
|
|
400
|
+
# minor_unit: ["копейка", "копейки", "копеек"],
|
|
401
|
+
# symbol: "₽"
|
|
402
|
+
# }
|
|
403
|
+
|
|
404
|
+
Num2words.currency_info(:ru, :XYZ)
|
|
405
|
+
# => nil
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### `Num2words.default_currency_info`
|
|
409
|
+
|
|
410
|
+
Returns metadata for the locale default currency.
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
Num2words.default_currency_info(:ru)
|
|
414
|
+
# => {
|
|
415
|
+
# code: :RUB,
|
|
416
|
+
# major_unit: ["рубль", "рубля", "рублей"],
|
|
417
|
+
# minor_unit: ["копейка", "копейки", "копеек"],
|
|
418
|
+
# symbol: "₽"
|
|
419
|
+
# }
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### `Num2words.currency_options`
|
|
423
|
+
|
|
424
|
+
Returns an array for select inputs and settings screens.
|
|
425
|
+
|
|
426
|
+
```ruby
|
|
427
|
+
Num2words.currency_options(:ru)
|
|
428
|
+
# => [["RUB — ₽", :RUB], ["USD — $", :USD], ...]
|
|
429
|
+
|
|
430
|
+
Num2words.currency_options(:ru, format: :code)
|
|
431
|
+
# => [["RUB", :RUB], ["USD", :USD], ...]
|
|
432
|
+
|
|
433
|
+
Num2words.currency_options(:ru, format: :name)
|
|
434
|
+
# => [["рубль", :RUB], ["доллар", :USD], ...]
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Supported `format:` values:
|
|
438
|
+
|
|
439
|
+
- `:symbol` - currency code and symbol, default.
|
|
440
|
+
- `:code` - currency code only.
|
|
441
|
+
- `:name` - localized major currency unit name.
|
|
442
|
+
|
|
443
|
+
### `Num2words.available_locales`
|
|
444
|
+
|
|
445
|
+
Returns supported locale codes.
|
|
446
|
+
|
|
447
|
+
```ruby
|
|
448
|
+
Num2words.available_locales
|
|
449
|
+
# => [:ar, :be, :bg, :bn, :cs, ...]
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### `Num2words.locale_options`
|
|
453
|
+
|
|
454
|
+
Returns an array of locales for select inputs and settings screens.
|
|
455
|
+
|
|
456
|
+
```ruby
|
|
457
|
+
Num2words.locale_options
|
|
458
|
+
# => [["ar", :ar], ["be", :be], ["bg", :bg], ...]
|
|
459
|
+
|
|
460
|
+
Num2words.locale_options(format: :upcase)
|
|
461
|
+
# => [["AR", :ar], ["BE", :be], ["BG", :bg], ...]
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
Supported `format:` values:
|
|
465
|
+
|
|
466
|
+
- `:code` - locale code, default.
|
|
467
|
+
- `:upcase` - upper-case locale code.
|
|
468
|
+
|
|
367
469
|
### `Num2words.currency_warnings`
|
|
368
470
|
|
|
369
471
|
Controls warnings when requested currency is unavailable.
|
|
@@ -391,32 +493,42 @@ KZT MYR NOK PKR PLN RON RSD RUB SAR SEK THB TRY UAH USD VND
|
|
|
391
493
|
|
|
392
494
|
## Errors
|
|
393
495
|
|
|
496
|
+
User argument errors inherit from `ArgumentError`, so existing code using `rescue ArgumentError` continues to work.
|
|
497
|
+
|
|
394
498
|
Unsupported input type:
|
|
395
499
|
|
|
396
500
|
```ruby
|
|
397
501
|
Num2words.to_words(Object.new, :en)
|
|
398
|
-
# raises
|
|
502
|
+
# raises Num2words::UnsupportedInputError
|
|
399
503
|
```
|
|
400
504
|
|
|
401
505
|
Unsupported options:
|
|
402
506
|
|
|
403
507
|
```ruby
|
|
404
508
|
Num2words.to_words(0.5, :ru, joiner: :plus)
|
|
405
|
-
# raises
|
|
509
|
+
# raises Num2words::UnsupportedOptionError
|
|
406
510
|
|
|
407
511
|
Num2words.to_currency(12, :ru, minor: :sometimes)
|
|
408
|
-
# raises
|
|
512
|
+
# raises Num2words::UnsupportedOptionError
|
|
409
513
|
```
|
|
410
514
|
|
|
411
515
|
Unsupported currency amount:
|
|
412
516
|
|
|
413
517
|
```ruby
|
|
414
518
|
Num2words.to_currency("abc", :en)
|
|
415
|
-
# raises
|
|
519
|
+
# raises Num2words::UnsupportedCurrencyAmountError
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Unsupported currency in strict mode:
|
|
523
|
+
|
|
524
|
+
```ruby
|
|
525
|
+
Num2words.to_currency(10, :ru, code: :XYZ, strict: true)
|
|
526
|
+
# raises Num2words::UnsupportedCurrencyError
|
|
416
527
|
```
|
|
417
528
|
|
|
418
529
|
## Development References
|
|
419
530
|
|
|
420
531
|
- [Numeric limits](limits.md)
|
|
532
|
+
- [Rails integration](rails.md)
|
|
421
533
|
- [Locale development guide](locale_development.md)
|
|
422
534
|
- [Russian locale development guide](locale_development.ru.md)
|
data/docs/api.ru.md
CHANGED
|
@@ -318,6 +318,15 @@ Num2words.to_currency(12.50, :ru, code: :USD)
|
|
|
318
318
|
|
|
319
319
|
Если валюта недоступна для локали, `num2words` использует валюту локали по умолчанию и может вывести warning в зависимости от настроек.
|
|
320
320
|
|
|
321
|
+
### `strict`
|
|
322
|
+
|
|
323
|
+
Для `to_currency` включает строгую проверку валюты. Если `code:` недоступен для локали, метод вызывает `Num2words::UnsupportedCurrencyError` вместо fallback на валюту по умолчанию.
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
Num2words.to_currency(12.50, :ru, code: :XYZ, strict: true)
|
|
327
|
+
# raises Num2words::UnsupportedCurrencyError
|
|
328
|
+
```
|
|
329
|
+
|
|
321
330
|
### `minor`
|
|
322
331
|
|
|
323
332
|
Управляет выводом младшей денежной единицы.
|
|
@@ -364,6 +373,99 @@ Num2words.available_currencies(:ru)
|
|
|
364
373
|
# => [:RUB, :USD, :EUR, ...]
|
|
365
374
|
```
|
|
366
375
|
|
|
376
|
+
### `Num2words.currency_available?`
|
|
377
|
+
|
|
378
|
+
Проверяет, доступна ли валюта для локали.
|
|
379
|
+
|
|
380
|
+
```ruby
|
|
381
|
+
Num2words.currency_available?(:ru, :RUB)
|
|
382
|
+
# => true
|
|
383
|
+
|
|
384
|
+
Num2words.currency_available?(:ru, "usd")
|
|
385
|
+
# => true
|
|
386
|
+
|
|
387
|
+
Num2words.currency_available?(:ru, :XYZ)
|
|
388
|
+
# => false
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### `Num2words.currency_info`
|
|
392
|
+
|
|
393
|
+
Возвращает данные валюты для локали или `nil`, если валюта недоступна.
|
|
394
|
+
|
|
395
|
+
```ruby
|
|
396
|
+
Num2words.currency_info(:ru, :RUB)
|
|
397
|
+
# => {
|
|
398
|
+
# code: :RUB,
|
|
399
|
+
# major_unit: ["рубль", "рубля", "рублей"],
|
|
400
|
+
# minor_unit: ["копейка", "копейки", "копеек"],
|
|
401
|
+
# symbol: "₽"
|
|
402
|
+
# }
|
|
403
|
+
|
|
404
|
+
Num2words.currency_info(:ru, :XYZ)
|
|
405
|
+
# => nil
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### `Num2words.default_currency_info`
|
|
409
|
+
|
|
410
|
+
Возвращает данные валюты по умолчанию для локали.
|
|
411
|
+
|
|
412
|
+
```ruby
|
|
413
|
+
Num2words.default_currency_info(:ru)
|
|
414
|
+
# => {
|
|
415
|
+
# code: :RUB,
|
|
416
|
+
# major_unit: ["рубль", "рубля", "рублей"],
|
|
417
|
+
# minor_unit: ["копейка", "копейки", "копеек"],
|
|
418
|
+
# symbol: "₽"
|
|
419
|
+
# }
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
### `Num2words.currency_options`
|
|
423
|
+
|
|
424
|
+
Возвращает массив для select-полей и настроек.
|
|
425
|
+
|
|
426
|
+
```ruby
|
|
427
|
+
Num2words.currency_options(:ru)
|
|
428
|
+
# => [["RUB — ₽", :RUB], ["USD — $", :USD], ...]
|
|
429
|
+
|
|
430
|
+
Num2words.currency_options(:ru, format: :code)
|
|
431
|
+
# => [["RUB", :RUB], ["USD", :USD], ...]
|
|
432
|
+
|
|
433
|
+
Num2words.currency_options(:ru, format: :name)
|
|
434
|
+
# => [["рубль", :RUB], ["доллар", :USD], ...]
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
Поддерживаемые значения `format:`:
|
|
438
|
+
|
|
439
|
+
- `:symbol` - код и символ валюты, значение по умолчанию.
|
|
440
|
+
- `:code` - только код валюты.
|
|
441
|
+
- `:name` - локализованное название основной денежной единицы.
|
|
442
|
+
|
|
443
|
+
### `Num2words.available_locales`
|
|
444
|
+
|
|
445
|
+
Возвращает список поддерживаемых локалей.
|
|
446
|
+
|
|
447
|
+
```ruby
|
|
448
|
+
Num2words.available_locales
|
|
449
|
+
# => [:ar, :be, :bg, :bn, :cs, ...]
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
### `Num2words.locale_options`
|
|
453
|
+
|
|
454
|
+
Возвращает массив локалей для select-полей и настроек.
|
|
455
|
+
|
|
456
|
+
```ruby
|
|
457
|
+
Num2words.locale_options
|
|
458
|
+
# => [["ar", :ar], ["be", :be], ["bg", :bg], ...]
|
|
459
|
+
|
|
460
|
+
Num2words.locale_options(format: :upcase)
|
|
461
|
+
# => [["AR", :ar], ["BE", :be], ["BG", :bg], ...]
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
Поддерживаемые значения `format:`:
|
|
465
|
+
|
|
466
|
+
- `:code` - код локали, значение по умолчанию.
|
|
467
|
+
- `:upcase` - код локали в верхнем регистре.
|
|
468
|
+
|
|
367
469
|
### `Num2words.currency_warnings`
|
|
368
470
|
|
|
369
471
|
Управляет warning при запросе валюты, недоступной для локали.
|
|
@@ -391,32 +493,42 @@ KZT MYR NOK PKR PLN RON RSD RUB SAR SEK THB TRY UAH USD VND
|
|
|
391
493
|
|
|
392
494
|
## Ошибки
|
|
393
495
|
|
|
496
|
+
Ошибки пользовательских аргументов наследуются от `ArgumentError`, поэтому существующий код с `rescue ArgumentError` продолжает работать.
|
|
497
|
+
|
|
394
498
|
Неподдерживаемый тип входных данных:
|
|
395
499
|
|
|
396
500
|
```ruby
|
|
397
501
|
Num2words.to_words(Object.new, :en)
|
|
398
|
-
# raises
|
|
502
|
+
# raises Num2words::UnsupportedInputError
|
|
399
503
|
```
|
|
400
504
|
|
|
401
505
|
Неподдерживаемые опции:
|
|
402
506
|
|
|
403
507
|
```ruby
|
|
404
508
|
Num2words.to_words(0.5, :ru, joiner: :plus)
|
|
405
|
-
# raises
|
|
509
|
+
# raises Num2words::UnsupportedOptionError
|
|
406
510
|
|
|
407
511
|
Num2words.to_currency(12, :ru, minor: :sometimes)
|
|
408
|
-
# raises
|
|
512
|
+
# raises Num2words::UnsupportedOptionError
|
|
409
513
|
```
|
|
410
514
|
|
|
411
515
|
Некорректная денежная сумма:
|
|
412
516
|
|
|
413
517
|
```ruby
|
|
414
518
|
Num2words.to_currency("abc", :en)
|
|
415
|
-
# raises
|
|
519
|
+
# raises Num2words::UnsupportedCurrencyAmountError
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
Недоступная валюта в строгом режиме:
|
|
523
|
+
|
|
524
|
+
```ruby
|
|
525
|
+
Num2words.to_currency(10, :ru, code: :XYZ, strict: true)
|
|
526
|
+
# raises Num2words::UnsupportedCurrencyError
|
|
416
527
|
```
|
|
417
528
|
|
|
418
529
|
## Документация для разработки
|
|
419
530
|
|
|
420
531
|
- [Числовые ограничения](limits.ru.md)
|
|
532
|
+
- [Rails-интеграция](rails.ru.md)
|
|
421
533
|
- [Locale development guide](locale_development.md)
|
|
422
534
|
- [Русская инструкция по разработке локалей](locale_development.ru.md)
|
data/docs/rails.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Rails Integration
|
|
2
|
+
|
|
3
|
+
`num2words` provides optional Rails helpers without adding Rails as a runtime dependency.
|
|
4
|
+
|
|
5
|
+
If Rails is available, `Num2words::Railtie` automatically includes helpers into Action View. Outside Rails, the helper module can be included manually.
|
|
6
|
+
|
|
7
|
+
The integration is covered by specs with a minimal Rails application, but Rails remains a development/test dependency only.
|
|
8
|
+
|
|
9
|
+
## Helpers
|
|
10
|
+
|
|
11
|
+
Available helpers:
|
|
12
|
+
|
|
13
|
+
- `number_to_words(number, locale: I18n.locale, **options)`
|
|
14
|
+
- `currency_to_words(amount, locale: I18n.locale, **options)`
|
|
15
|
+
- `date_to_words(date, locale: I18n.locale, **options)`
|
|
16
|
+
- `time_to_words(time, locale: I18n.locale, **options)`
|
|
17
|
+
- `datetime_to_words(datetime, locale: I18n.locale, **options)`
|
|
18
|
+
|
|
19
|
+
## Rails Views
|
|
20
|
+
|
|
21
|
+
```erb
|
|
22
|
+
<%= number_to_words(123, locale: :ru) %>
|
|
23
|
+
<%= currency_to_words(@invoice.total, locale: :ru, code: :RUB) %>
|
|
24
|
+
<%= date_to_words(Date.current, locale: I18n.locale) %>
|
|
25
|
+
<%= time_to_words(Time.current, locale: I18n.locale) %>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
When `locale:` is omitted, helpers use `I18n.locale`.
|
|
29
|
+
|
|
30
|
+
```erb
|
|
31
|
+
<%= number_to_words(123) %>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Controllers
|
|
35
|
+
|
|
36
|
+
Helpers are also exposed through the controller helper context:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
class PaymentsController < ApplicationController
|
|
40
|
+
def show
|
|
41
|
+
@amount_in_words = helpers.currency_to_words(@payment.amount, locale: :ru, code: @payment.currency)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## ActiveModel Validations
|
|
47
|
+
|
|
48
|
+
`num2words` provides a currency validator for Rails and ActiveModel models:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
class Payment < ApplicationRecord
|
|
52
|
+
validates :currency, num2words_currency: { locale: :ru }
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Valid values are checked against `Num2words.currency_available?(locale, currency)`.
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
Payment.new(currency: "RUB").valid?
|
|
60
|
+
# => true
|
|
61
|
+
|
|
62
|
+
Payment.new(currency: "XYZ").valid?
|
|
63
|
+
# => false
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The locale can also be dynamic:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
class Payment < ApplicationRecord
|
|
70
|
+
validates :currency, num2words_currency: { locale: ->(payment) { payment.locale } }
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Locale validation is also available:
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
class Payment < ApplicationRecord
|
|
78
|
+
validates :locale, num2words_locale: true
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
Payment.new(locale: "ru").valid?
|
|
84
|
+
# => true
|
|
85
|
+
|
|
86
|
+
Payment.new(locale: "xx").valid?
|
|
87
|
+
# => false
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Valid values are checked against `Num2words.available_locales`.
|
|
91
|
+
|
|
92
|
+
Error messages for `unsupported_currency` and `unsupported_locale` are included in the gem locale files. Rails apps can override them through the standard `errors.messages` keys.
|
|
93
|
+
|
|
94
|
+
## Metadata API
|
|
95
|
+
|
|
96
|
+
For forms, select inputs and settings screens, use the public metadata API:
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
Num2words.available_locales
|
|
100
|
+
Num2words.available_currencies(:ru)
|
|
101
|
+
Num2words.currency_available?(:ru, :RUB)
|
|
102
|
+
Num2words.currency_info(:ru, :RUB)
|
|
103
|
+
Num2words.default_currency_info(:ru)
|
|
104
|
+
Num2words.currency_options(:ru)
|
|
105
|
+
Num2words.locale_options
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Rails form example:
|
|
109
|
+
|
|
110
|
+
```erb
|
|
111
|
+
<%= form.select :currency, Num2words.currency_options(I18n.locale) %>
|
|
112
|
+
<%= form.select :locale, Num2words.locale_options %>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Manual Usage
|
|
116
|
+
|
|
117
|
+
The helpers can be used without Rails:
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
helper = Object.new.extend(Num2words::Rails::Helpers)
|
|
121
|
+
|
|
122
|
+
helper.number_to_words(123, locale: :en)
|
|
123
|
+
# => "one hundred twenty three"
|
|
124
|
+
|
|
125
|
+
helper.currency_to_words("12.50", locale: :ru, code: :USD)
|
|
126
|
+
# => "двенадцать долларов пятьдесят центов"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Options
|
|
130
|
+
|
|
131
|
+
Helpers forward all options to `Num2words.to_words` or `Num2words.to_currency`.
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
number_to_words(0.5, locale: :ru, joiner: :and)
|
|
135
|
+
# => "ноль и пять десятых"
|
|
136
|
+
|
|
137
|
+
currency_to_words(12, locale: :ru, minor: :nonzero)
|
|
138
|
+
# => "двенадцать рублей"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
See [API reference](api.md) for the full option list.
|
data/docs/rails.ru.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Rails-интеграция
|
|
2
|
+
|
|
3
|
+
`num2words` предоставляет optional Rails helpers без добавления Rails как runtime-зависимости.
|
|
4
|
+
|
|
5
|
+
Если Rails доступен, `Num2words::Railtie` автоматически подключает helpers в Action View. Вне Rails модуль helpers можно подключить вручную.
|
|
6
|
+
|
|
7
|
+
Интеграция покрыта specs с минимальным Rails-приложением, но Rails остается зависимостью только для development/test.
|
|
8
|
+
|
|
9
|
+
## Helpers
|
|
10
|
+
|
|
11
|
+
Доступные helpers:
|
|
12
|
+
|
|
13
|
+
- `number_to_words(number, locale: I18n.locale, **options)`
|
|
14
|
+
- `currency_to_words(amount, locale: I18n.locale, **options)`
|
|
15
|
+
- `date_to_words(date, locale: I18n.locale, **options)`
|
|
16
|
+
- `time_to_words(time, locale: I18n.locale, **options)`
|
|
17
|
+
- `datetime_to_words(datetime, locale: I18n.locale, **options)`
|
|
18
|
+
|
|
19
|
+
## Rails views
|
|
20
|
+
|
|
21
|
+
```erb
|
|
22
|
+
<%= number_to_words(123, locale: :ru) %>
|
|
23
|
+
<%= currency_to_words(@invoice.total, locale: :ru, code: :RUB) %>
|
|
24
|
+
<%= date_to_words(Date.current, locale: I18n.locale) %>
|
|
25
|
+
<%= time_to_words(Time.current, locale: I18n.locale) %>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Если `locale:` не передан, helpers используют `I18n.locale`.
|
|
29
|
+
|
|
30
|
+
```erb
|
|
31
|
+
<%= number_to_words(123) %>
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Controllers
|
|
35
|
+
|
|
36
|
+
Helpers также доступны через controller helper context:
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
class PaymentsController < ApplicationController
|
|
40
|
+
def show
|
|
41
|
+
@amount_in_words = helpers.currency_to_words(@payment.amount, locale: :ru, code: @payment.currency)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## ActiveModel validations
|
|
47
|
+
|
|
48
|
+
`num2words` предоставляет валидатор валюты для Rails и ActiveModel моделей:
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
class Payment < ApplicationRecord
|
|
52
|
+
validates :currency, num2words_currency: { locale: :ru }
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Валидные значения проверяются через `Num2words.currency_available?(locale, currency)`.
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
Payment.new(currency: "RUB").valid?
|
|
60
|
+
# => true
|
|
61
|
+
|
|
62
|
+
Payment.new(currency: "XYZ").valid?
|
|
63
|
+
# => false
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Локаль может быть динамической:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
class Payment < ApplicationRecord
|
|
70
|
+
validates :currency, num2words_currency: { locale: ->(payment) { payment.locale } }
|
|
71
|
+
end
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Также доступна проверка локали:
|
|
75
|
+
|
|
76
|
+
```ruby
|
|
77
|
+
class Payment < ApplicationRecord
|
|
78
|
+
validates :locale, num2words_locale: true
|
|
79
|
+
end
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
```ruby
|
|
83
|
+
Payment.new(locale: "ru").valid?
|
|
84
|
+
# => true
|
|
85
|
+
|
|
86
|
+
Payment.new(locale: "xx").valid?
|
|
87
|
+
# => false
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Валидные значения проверяются через `Num2words.available_locales`.
|
|
91
|
+
|
|
92
|
+
Сообщения ошибок для `unsupported_currency` и `unsupported_locale` уже добавлены в locale files гема. Их можно переопределить в Rails-приложении стандартным способом через `errors.messages`.
|
|
93
|
+
|
|
94
|
+
## Metadata API
|
|
95
|
+
|
|
96
|
+
Для форм, select-полей и настроек можно использовать публичные методы metadata API:
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
Num2words.available_locales
|
|
100
|
+
Num2words.available_currencies(:ru)
|
|
101
|
+
Num2words.currency_available?(:ru, :RUB)
|
|
102
|
+
Num2words.currency_info(:ru, :RUB)
|
|
103
|
+
Num2words.default_currency_info(:ru)
|
|
104
|
+
Num2words.currency_options(:ru)
|
|
105
|
+
Num2words.locale_options
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Пример для Rails form:
|
|
109
|
+
|
|
110
|
+
```erb
|
|
111
|
+
<%= form.select :currency, Num2words.currency_options(I18n.locale) %>
|
|
112
|
+
<%= form.select :locale, Num2words.locale_options %>
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Ручное использование
|
|
116
|
+
|
|
117
|
+
Helpers можно использовать без Rails:
|
|
118
|
+
|
|
119
|
+
```ruby
|
|
120
|
+
helper = Object.new.extend(Num2words::Rails::Helpers)
|
|
121
|
+
|
|
122
|
+
helper.number_to_words(123, locale: :en)
|
|
123
|
+
# => "one hundred twenty three"
|
|
124
|
+
|
|
125
|
+
helper.currency_to_words("12.50", locale: :ru, code: :USD)
|
|
126
|
+
# => "двенадцать долларов пятьдесят центов"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Опции
|
|
130
|
+
|
|
131
|
+
Helpers передают все опции в `Num2words.to_words` или `Num2words.to_currency`.
|
|
132
|
+
|
|
133
|
+
```ruby
|
|
134
|
+
number_to_words(0.5, locale: :ru, joiner: :and)
|
|
135
|
+
# => "ноль и пять десятых"
|
|
136
|
+
|
|
137
|
+
currency_to_words(12, locale: :ru, minor: :nonzero)
|
|
138
|
+
# => "двенадцать рублей"
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Полный список опций смотри в [справочнике API](api.ru.md).
|
data/lib/num2words/config.rb
CHANGED
|
@@ -27,6 +27,52 @@ module Num2words
|
|
|
27
27
|
I18n.t("num2words.currencies", locale: locale).keys.map(&:to_sym)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def currency_available?(locale, currency)
|
|
31
|
+
available_currencies(locale).include?(currency.to_s.upcase.to_sym)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def currency_info(locale, currency)
|
|
35
|
+
code = currency.to_s.upcase.to_sym
|
|
36
|
+
data = I18n.t("num2words.currencies", locale: locale)[code]
|
|
37
|
+
|
|
38
|
+
return unless data
|
|
39
|
+
|
|
40
|
+
{
|
|
41
|
+
code: code,
|
|
42
|
+
major_unit: data[:major_unit],
|
|
43
|
+
minor_unit: data[:minor_unit],
|
|
44
|
+
symbol: data[:symbol]
|
|
45
|
+
}
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def default_currency_info(locale = I18n.locale)
|
|
49
|
+
currency_info(locale, default_currency(locale))
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def currency_options(locale = I18n.locale, format: :symbol)
|
|
53
|
+
validate_currency_options_format!(format)
|
|
54
|
+
|
|
55
|
+
available_currencies(locale).map do |code|
|
|
56
|
+
info = currency_info(locale, code)
|
|
57
|
+
|
|
58
|
+
[currency_option_label(info, format), code]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def available_locales
|
|
63
|
+
@available_locales ||= Dir[File.expand_path("../../config/locales/*.yml", __dir__)]
|
|
64
|
+
.map { |file| File.basename(file, ".yml").to_sym }
|
|
65
|
+
.sort
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def locale_options(format: :code)
|
|
69
|
+
validate_locale_options_format!(format)
|
|
70
|
+
|
|
71
|
+
available_locales.map do |locale|
|
|
72
|
+
[locale_option_label(locale, format), locale]
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
30
76
|
def reset!(locale = nil)
|
|
31
77
|
return @local_currency.delete(locale) if locale
|
|
32
78
|
|
|
@@ -34,6 +80,34 @@ module Num2words
|
|
|
34
80
|
@local_currency = {}
|
|
35
81
|
@currency_warnings = true
|
|
36
82
|
end
|
|
83
|
+
|
|
84
|
+
private
|
|
85
|
+
|
|
86
|
+
def validate_currency_options_format!(format)
|
|
87
|
+
return if %i[symbol code name].include?(format)
|
|
88
|
+
|
|
89
|
+
raise UnsupportedOptionError.new(name: :format, value: format)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def validate_locale_options_format!(format)
|
|
93
|
+
return if %i[code upcase].include?(format)
|
|
94
|
+
|
|
95
|
+
raise UnsupportedOptionError.new(name: :format, value: format)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def currency_option_label(info, format)
|
|
99
|
+
case format
|
|
100
|
+
when :code then info[:code].to_s
|
|
101
|
+
when :name then info[:major_unit].first
|
|
102
|
+
else [info[:code], info[:symbol]].compact.join(" — ")
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def locale_option_label(locale, format)
|
|
107
|
+
label = locale.to_s
|
|
108
|
+
|
|
109
|
+
format == :upcase ? label.upcase : label
|
|
110
|
+
end
|
|
37
111
|
end
|
|
38
112
|
|
|
39
113
|
def self.config
|
|
@@ -52,6 +126,30 @@ module Num2words
|
|
|
52
126
|
config.available_currencies(locale)
|
|
53
127
|
end
|
|
54
128
|
|
|
129
|
+
def self.currency_available?(locale, currency)
|
|
130
|
+
config.currency_available?(locale, currency)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def self.currency_info(locale, currency)
|
|
134
|
+
config.currency_info(locale, currency)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def self.default_currency_info(locale = I18n.locale)
|
|
138
|
+
config.default_currency_info(locale)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def self.currency_options(locale = I18n.locale, format: :symbol)
|
|
142
|
+
config.currency_options(locale, format: format)
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.available_locales
|
|
146
|
+
config.available_locales
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def self.locale_options(format: :code)
|
|
150
|
+
config.locale_options(format: format)
|
|
151
|
+
end
|
|
152
|
+
|
|
55
153
|
def self.currency_warnings
|
|
56
154
|
config.currency_warnings
|
|
57
155
|
end
|
data/lib/num2words/converter.rb
CHANGED
|
@@ -33,7 +33,7 @@ module Num2words
|
|
|
33
33
|
else nil
|
|
34
34
|
end
|
|
35
35
|
|
|
36
|
-
raise
|
|
36
|
+
raise UnsupportedInputError, number if result.nil?
|
|
37
37
|
|
|
38
38
|
apply_case(result, word_case)
|
|
39
39
|
end
|
|
@@ -43,12 +43,15 @@ module Num2words
|
|
|
43
43
|
word_case = opts[:word_case] || :downcase
|
|
44
44
|
currency = (opts[:code] || Num2words.default_currency(locale)).to_s.upcase.to_sym
|
|
45
45
|
minor = opts[:minor] || :always
|
|
46
|
+
strict = opts[:strict] || false
|
|
46
47
|
|
|
47
48
|
validate_option!(:minor, minor, %i[always nonzero never])
|
|
48
49
|
|
|
49
50
|
unless Num2words.available_currencies(locale).include?(currency)
|
|
51
|
+
raise UnsupportedCurrencyError.new(locale: locale, currency: currency) if strict
|
|
52
|
+
|
|
50
53
|
warn I18n.t("num2words.warnings.currency_not_available",
|
|
51
|
-
currency: currency, locale: locale) if Num2words.currency_warnings
|
|
54
|
+
currency: currency, lang: locale, locale: locale) if Num2words.currency_warnings
|
|
52
55
|
currency = Num2words.default_currency(locale)
|
|
53
56
|
end
|
|
54
57
|
|
|
@@ -83,7 +86,7 @@ module Num2words
|
|
|
83
86
|
def validate_option!(name, value, allowed_values)
|
|
84
87
|
return if allowed_values.include?(value)
|
|
85
88
|
|
|
86
|
-
raise
|
|
89
|
+
raise UnsupportedOptionError.new(name: name, value: value)
|
|
87
90
|
end
|
|
88
91
|
|
|
89
92
|
def decimal_currency_amount(amount)
|
|
@@ -91,8 +94,8 @@ module Num2words
|
|
|
91
94
|
|
|
92
95
|
normalized_amount = amount.is_a?(String) ? amount.tr(",", ".") : amount.to_s
|
|
93
96
|
BigDecimal(normalized_amount)
|
|
94
|
-
rescue ArgumentError
|
|
95
|
-
raise
|
|
97
|
+
rescue ::ArgumentError
|
|
98
|
+
raise UnsupportedCurrencyAmountError, amount
|
|
96
99
|
end
|
|
97
100
|
|
|
98
101
|
def pluralize(number, singular, few, plural)
|
|
@@ -383,7 +386,8 @@ module Num2words
|
|
|
383
386
|
time_format = short && only == :time ? :short : :default
|
|
384
387
|
|
|
385
388
|
date_part = to_words_date(datetime.to_date, locale, locale_data, format: date_format, date_case: date_case)
|
|
386
|
-
time_part = to_words_time(datetime.
|
|
389
|
+
time_part = to_words_time(Time.new(datetime.year, datetime.month, datetime.day, datetime.hour, datetime.min, datetime.sec),
|
|
390
|
+
locale, locale_data, format: time_format, short: short)
|
|
387
391
|
|
|
388
392
|
return date_part if only == :date
|
|
389
393
|
return time_part if only == :time
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Num2words
|
|
4
|
+
class Error < StandardError; end
|
|
5
|
+
|
|
6
|
+
class ArgumentError < ::ArgumentError; end
|
|
7
|
+
|
|
8
|
+
class UnsupportedInputError < ArgumentError
|
|
9
|
+
attr_reader :input
|
|
10
|
+
|
|
11
|
+
def initialize(input)
|
|
12
|
+
@input = input
|
|
13
|
+
|
|
14
|
+
super("Unsupported input type: #{input.inspect}")
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class UnsupportedOptionError < ArgumentError
|
|
19
|
+
attr_reader :name, :value
|
|
20
|
+
|
|
21
|
+
def initialize(name:, value:)
|
|
22
|
+
@name = name
|
|
23
|
+
@value = value
|
|
24
|
+
|
|
25
|
+
super("Unsupported #{name} option: #{value.inspect}")
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class UnsupportedCurrencyError < Error
|
|
30
|
+
attr_reader :locale, :currency
|
|
31
|
+
|
|
32
|
+
def initialize(locale:, currency:)
|
|
33
|
+
@locale = locale
|
|
34
|
+
@currency = currency
|
|
35
|
+
|
|
36
|
+
super("Currency #{currency} is not supported for locale #{locale}")
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class UnsupportedCurrencyAmountError < ArgumentError
|
|
41
|
+
attr_reader :amount
|
|
42
|
+
|
|
43
|
+
def initialize(amount)
|
|
44
|
+
@amount = amount
|
|
45
|
+
|
|
46
|
+
super("Unsupported currency amount: #{amount.inspect}")
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Num2words
|
|
4
|
+
module Rails
|
|
5
|
+
module Helpers
|
|
6
|
+
def number_to_words(number, locale: I18n.locale, **options)
|
|
7
|
+
Num2words.to_words(number, locale: locale, **options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def currency_to_words(amount, locale: I18n.locale, **options)
|
|
11
|
+
Num2words.to_currency(amount, locale: locale, **options)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def date_to_words(date, locale: I18n.locale, **options)
|
|
15
|
+
Num2words.to_words(date, locale: locale, **options)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def time_to_words(time, locale: I18n.locale, **options)
|
|
19
|
+
Num2words.to_words(time, locale: locale, **options)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def datetime_to_words(datetime, locale: I18n.locale, **options)
|
|
23
|
+
Num2words.to_words(datetime, locale: locale, **options)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model"
|
|
4
|
+
|
|
5
|
+
module Num2words
|
|
6
|
+
module Rails
|
|
7
|
+
module Validators
|
|
8
|
+
class CurrencyValidator < ActiveModel::EachValidator
|
|
9
|
+
def validate_each(record, attribute, value)
|
|
10
|
+
locale = resolve_locale(record)
|
|
11
|
+
currency = value.to_s.upcase.to_sym
|
|
12
|
+
|
|
13
|
+
return if Num2words.currency_available?(locale, currency)
|
|
14
|
+
|
|
15
|
+
record.errors.add(attribute, :unsupported_currency, currency: currency, num2words_locale: locale)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def resolve_locale(record)
|
|
21
|
+
locale = options[:locale]
|
|
22
|
+
locale.respond_to?(:call) ? locale.call(record) : locale || I18n.locale
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
class Num2wordsCurrencyValidator < Num2words::Rails::Validators::CurrencyValidator
|
|
30
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model"
|
|
4
|
+
|
|
5
|
+
module Num2words
|
|
6
|
+
module Rails
|
|
7
|
+
module Validators
|
|
8
|
+
class LocaleValidator < ActiveModel::EachValidator
|
|
9
|
+
def validate_each(record, attribute, value)
|
|
10
|
+
locale = value.to_s.to_sym
|
|
11
|
+
|
|
12
|
+
return if Num2words.available_locales.include?(locale)
|
|
13
|
+
|
|
14
|
+
record.errors.add(attribute, :unsupported_locale, unsupported_locale: locale)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
class Num2wordsLocaleValidator < Num2words::Rails::Validators::LocaleValidator
|
|
22
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "rails/helpers"
|
|
4
|
+
|
|
5
|
+
begin
|
|
6
|
+
require "rails/railtie"
|
|
7
|
+
require_relative "rails/validators/currency_validator"
|
|
8
|
+
require_relative "rails/validators/locale_validator"
|
|
9
|
+
rescue LoadError
|
|
10
|
+
nil
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
if defined?(::Rails::Railtie)
|
|
14
|
+
module Num2words
|
|
15
|
+
class Railtie < ::Rails::Railtie
|
|
16
|
+
initializer "num2words.helpers" do
|
|
17
|
+
ActiveSupport.on_load(:action_view) do
|
|
18
|
+
include Num2words::Rails::Helpers
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
ActiveSupport.on_load(:action_controller) do
|
|
22
|
+
helper Num2words::Rails::Helpers if respond_to?(:helper)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/num2words/version.rb
CHANGED
data/lib/num2words.rb
CHANGED
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative "num2words/i18n"
|
|
4
4
|
require_relative "num2words/version"
|
|
5
|
+
require_relative "num2words/errors"
|
|
5
6
|
require_relative "num2words/converter"
|
|
6
7
|
require_relative "num2words/core_ext"
|
|
7
8
|
require_relative "num2words/locales"
|
|
8
9
|
require_relative "num2words/config"
|
|
10
|
+
require_relative "num2words/rails/helpers"
|
|
11
|
+
require_relative "num2words/railtie"
|
|
9
12
|
|
|
10
13
|
module Num2words
|
|
11
14
|
def self.to_words(number, *args, **opts)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: num2words
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ruslan Fedotov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-07-
|
|
11
|
+
date: 2026-07-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: i18n
|
|
@@ -113,12 +113,15 @@ files:
|
|
|
113
113
|
- docs/limits.ru.md
|
|
114
114
|
- docs/locale_development.md
|
|
115
115
|
- docs/locale_development.ru.md
|
|
116
|
+
- docs/rails.md
|
|
117
|
+
- docs/rails.ru.md
|
|
116
118
|
- exe/num2words-console
|
|
117
119
|
- lib/num2words.rb
|
|
118
120
|
- lib/num2words/config.rb
|
|
119
121
|
- lib/num2words/console.rb
|
|
120
122
|
- lib/num2words/converter.rb
|
|
121
123
|
- lib/num2words/core_ext.rb
|
|
124
|
+
- lib/num2words/errors.rb
|
|
122
125
|
- lib/num2words/i18n.rb
|
|
123
126
|
- lib/num2words/locales.rb
|
|
124
127
|
- lib/num2words/locales/ar.rb
|
|
@@ -171,6 +174,10 @@ files:
|
|
|
171
174
|
- lib/num2words/locales/ur.rb
|
|
172
175
|
- lib/num2words/locales/vi.rb
|
|
173
176
|
- lib/num2words/locales/zh.rb
|
|
177
|
+
- lib/num2words/rails/helpers.rb
|
|
178
|
+
- lib/num2words/rails/validators/currency_validator.rb
|
|
179
|
+
- lib/num2words/rails/validators/locale_validator.rb
|
|
180
|
+
- lib/num2words/railtie.rb
|
|
174
181
|
- lib/num2words/version.rb
|
|
175
182
|
- num2words.gemspec
|
|
176
183
|
homepage: https://github.com/skyrusx/num2words
|