num2words 0.1.3 → 0.1.5
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 +50 -0
- data/README.md +85 -23
- data/config/locales/en.yml +24 -0
- data/config/locales/ru.yml +40 -0
- data/lib/num2words/converter.rb +152 -8
- data/lib/num2words/core_ext.rb +24 -0
- data/lib/num2words/locales/en.rb +8 -0
- data/lib/num2words/locales/ru.rb +8 -0
- data/lib/num2words/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7fbb8e0f384b3baf9ca9081c7d2c2095817d883b55796d48196f0bfd5a111fcc
|
4
|
+
data.tar.gz: 1dd172a547a50ac707b78cb626e1ae81b0af1a631e7313b30a48afe414dc5d26
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 73b3f95666700ff9ad74b73c47f207becb76541d185dd0bdee98cbc89b2b33921a7b97651c844bc83029706cc52a84fde1cac98da8151bff8cfa1f77867cd1c2
|
7
|
+
data.tar.gz: 9008411287c518ecbc87c16426e9eaa9aebdb4f526a044a84a135df1c698cde43a16841cd9397faa97a890a3d1326df0945437a2b9112b608454e258f41b8f5f
|
data/CHANGELOG.md
CHANGED
@@ -15,6 +15,56 @@
|
|
15
15
|
|
16
16
|
---
|
17
17
|
|
18
|
+
## [0.1.5] - 2025-08-22
|
19
|
+
### Added
|
20
|
+
- Расширение `Time#to_words`, возможность преобразовать строки с временем
|
21
|
+
```ruby
|
22
|
+
"14:35:42".to_words(:ru)
|
23
|
+
# => "четырнадцать часов тридцать пять минут сорок две секунды"
|
24
|
+
```
|
25
|
+
- Добавлен параметр `short: true` для `time` и `datetime`
|
26
|
+
Возвращает краткий вариант записи для time (`HH:MM`)
|
27
|
+
```ruby
|
28
|
+
"14:35:42".to_words(:ru, short: true)
|
29
|
+
# => "четырнадцать часов тридцать пять минут"
|
30
|
+
```
|
31
|
+
Возвращает краткий вариант записи для datetime на выбор - дата или время
|
32
|
+
```ruby
|
33
|
+
"2024-08-21 14:35:42".to_words(:ru, :time)
|
34
|
+
# => "двадцать первого августа две тысячи двадцать четвёртого года"
|
35
|
+
```
|
36
|
+
- Поддержка перевода времени в разных форматах:
|
37
|
+
- `:hours_only` — только часы
|
38
|
+
- `:hours_minutes` — часы и минуты
|
39
|
+
- `:hours_minutes_seconds` — часы, минуты и секунды
|
40
|
+
|
41
|
+
## [0.1.4] - 2025-08-21
|
42
|
+
### Added
|
43
|
+
- Расширение `String#to_words`, возможность преобразовать строки с датами
|
44
|
+
```ruby
|
45
|
+
"21.08.2025".to_words(:ru)
|
46
|
+
# => "двадцать первое августа две тысячи двадцать пятого года"
|
47
|
+
|
48
|
+
"21.08.2025".to_words(:en)
|
49
|
+
# => "the twenty-first of August, two thousand twenty five"
|
50
|
+
```
|
51
|
+
- Расширение `Date#to_words`, добавлена возможность преобразовывать объекты Date и DateTime
|
52
|
+
```ruby
|
53
|
+
Date.new(2025, 8, 21).to_words(:ru)
|
54
|
+
# => "двадцать первого августа две тысячи двадцать пятого года"
|
55
|
+
|
56
|
+
Date.new(2025, 8, 21).to_words(:en)
|
57
|
+
# => "the twenty-first of August, two thousand twenty-five"
|
58
|
+
```
|
59
|
+
- Поддержка параметра `format: :nominative`, можно получать даты в именительном падеже.
|
60
|
+
```ruby
|
61
|
+
Date.new(2025, 8, 21).to_words(:ru, format: :nominative)
|
62
|
+
# => "двадцать первое августа две тысячи двадцать пятый год"
|
63
|
+
|
64
|
+
"19.07.2012".to_words(:ru, format: :nominative)
|
65
|
+
# => "девятнадцатое июля две тысячи двенадцатый год"
|
66
|
+
```
|
67
|
+
|
18
68
|
## [0.1.3] – 2025-08-20
|
19
69
|
### Added
|
20
70
|
- Параметр **`word_case:`** для методов `to_words`, `to_currency` со значениями:
|
data/README.md
CHANGED
@@ -6,17 +6,20 @@
|
|
6
6
|
|
7
7
|
## ✨ Основные возможности
|
8
8
|
|
9
|
-
- Поддержка
|
10
|
-
-
|
11
|
-
|
12
|
-
|
13
|
-
-
|
14
|
-
|
15
|
-
|
16
|
-
-
|
17
|
-
-
|
18
|
-
-
|
19
|
-
-
|
9
|
+
- Поддержка **чисел, времени, дат и валют**:
|
10
|
+
- `Integer` → `123.to_words(:ru)` → `"сто двадцать три"`
|
11
|
+
- `Float` → `12.5.to_words(:en)` → `"twelve and five tenths"`
|
12
|
+
- `Time / DateTime` → `"2024-08-21 14:35:42".to_words(:ru, :time)` → `"четырнадцать часов тридцать пять минут сорок две секунды"`
|
13
|
+
- `Float.to_currency` → `12.5.to_currency(:ru)` → `"двенадцать рублей пятьдесят копеек"`
|
14
|
+
- Кастомизация вывода:
|
15
|
+
- Краткая форма (`short: true`) → `"четырнадцать часов тридцать пять минут"`
|
16
|
+
- Форматы времени (`:hours_only`, `:hours_minutes`, `:hours_minutes_seconds`)
|
17
|
+
- Выбор локали: `:ru`, `:en` (из коробки), легко расширить YAML-файлами
|
18
|
+
- Расширение **Integer**, **Float**, **Date**, **Time**, **DateTime** удобными методами.
|
19
|
+
- Локали инициализируются только при обращении к ним (`lazy loading`) через `lib/num2words/locales.rb`.
|
20
|
+
- Унифицированный `Converter`, делегирующий работу нужной локали.
|
21
|
+
- Настраиваемые правила разрядов чисел и валют через I18n YAML.
|
22
|
+
|
20
23
|
|
21
24
|
---
|
22
25
|
|
@@ -40,21 +43,64 @@ gem install num2words
|
|
40
43
|
|
41
44
|
```ruby
|
42
45
|
require "num2words"
|
46
|
+
```
|
47
|
+
|
48
|
+
### 🔢 Числа
|
49
|
+
```ruby
|
50
|
+
# Integer
|
51
|
+
123.to_words(:ru) # => "сто двадцать три"
|
52
|
+
123.to_words(:en) # => "one hundred twenty three"
|
53
|
+
|
54
|
+
# Float
|
55
|
+
45.67.to_words(:ru) # => "сорок пять целых шестьдесят семь сотых"
|
56
|
+
45.67.to_words(:en) # => "forty five and sixty seven hundredths"
|
57
|
+
```
|
43
58
|
|
44
|
-
|
45
|
-
|
46
|
-
|
59
|
+
### 💰 Валюта
|
60
|
+
```ruby
|
61
|
+
21.05.to_currency(:ru) # => "двадцать один рубль пять копеек"
|
62
|
+
12.5.to_currency(:en) # => "twelve dollars fifty cents"
|
63
|
+
```
|
47
64
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
65
|
+
### 📅 Дата
|
66
|
+
```ruby
|
67
|
+
"2024-08-21".to_words(:ru, :date)
|
68
|
+
# => "двадцать первое августа две тысячи двадцать четвертого года"
|
52
69
|
|
53
|
-
|
54
|
-
|
55
|
-
12.5.to_currency(locale: :ru) # "двенадцать рублей пятьдесят копеек"
|
70
|
+
"2024-08-21".to_words(:en, :date)
|
71
|
+
# => "the twenty-first of August, two thousand twenty four"
|
56
72
|
```
|
57
73
|
|
74
|
+
### ⏰ Время
|
75
|
+
```ruby
|
76
|
+
"14:35:42".to_words(:ru, :time)
|
77
|
+
# => "четырнадцать часов тридцать пять минут сорок две секунды"
|
78
|
+
|
79
|
+
"14:35:42".to_words(:ru, :time, short: true) # или короткая запись: "14:35:42".to_words(:ru, :time, true)
|
80
|
+
# => "четырнадцать часов тридцать пять минут"
|
81
|
+
|
82
|
+
"14:35:42".to_words(:en, :time)
|
83
|
+
# => "fourteen hours thirty five minutes forty two seconds"
|
84
|
+
```
|
85
|
+
|
86
|
+
### 🕓 Дата и время
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
"2024-08-21 14:35:42".to_words(:ru)
|
90
|
+
# => "двадцать первого августа две тысячи двадцать четвёртого года, четырнадцать часов тридцать пять минут сорок две секунды"
|
91
|
+
|
92
|
+
"2024-08-21 14:35:42".to_words(:en)
|
93
|
+
# => "the twenty-first of August, two thousand twenty four at fourteen hours thirty five minutes forty two seconds"
|
94
|
+
```
|
95
|
+
|
96
|
+
### ⚙️ Опции
|
97
|
+
|
98
|
+
- `locale: :ru | :en` — язык (по умолчанию берётся I18n.locale или :ru).
|
99
|
+
- `:date, :time, :datetime` — формат преобразования для строк.
|
100
|
+
- `short: true` — краткая форма для даты/времени.
|
101
|
+
- `Num2words.to_words(number, locale: :en)` — универсальный способ вызова без расширения базовых классов.
|
102
|
+
- `Num2words.to_currency(number)` — преобразование число в валюту.
|
103
|
+
|
58
104
|
### Консоль 💻
|
59
105
|
|
60
106
|
Num2words поддерживает интерактивную консоль для быстрого тестирования.
|
@@ -138,6 +184,20 @@ bin/console
|
|
138
184
|
- YAML-файл: `config/locales/xx.yml`
|
139
185
|
- Обёртка: `lib/num2words/locales/xx.rb`
|
140
186
|
|
187
|
+
### 🌍 Поддержка локалей (ru / en)
|
188
|
+
|
189
|
+
| Возможность | ru | en |
|
190
|
+
| ----------------------------- | --------- | ---------- |
|
191
|
+
| 🔢 Числа (Integer) | ✔ | ✔ |
|
192
|
+
| 🔢 Числа (Float) | ✔ | ✔ |
|
193
|
+
| 💰 Валюта | ✔ (рубли) | ✔ (rubles) |
|
194
|
+
| 💰 Валюта (short) | ✖ | ✖ |
|
195
|
+
| 💱 Выбор валюты (USD/EUR/…) | ✖ | ✖ |
|
196
|
+
| 📅 Дата | ✔ | ✔ |
|
197
|
+
| ⏰ Время | ✔ | ✔ |
|
198
|
+
| 🕓 Дата и время | ✔ | ✔ |
|
199
|
+
| 📝 Краткая форма даты/времени | ✔ | ✔ |
|
200
|
+
|
141
201
|
---
|
142
202
|
|
143
203
|
## 🧪 Тестирование
|
@@ -149,8 +209,10 @@ bundle exec rspec
|
|
149
209
|
## 📌 Roadmap
|
150
210
|
|
151
211
|
- [x] 🇬🇧 Поддержка английского языка
|
152
|
-
- [
|
153
|
-
- [
|
212
|
+
- [x] 🔠 Опция выбора регистра (строчные/Прописные)
|
213
|
+
- [x] ⏰ Краткая форма даты/времени
|
214
|
+
- [ ] 💵 Поддержка других валют (USD, EUR и т.д)
|
215
|
+
- [ ] 💰 Краткая форма валюты
|
154
216
|
|
155
217
|
---
|
156
218
|
|
data/config/locales/en.yml
CHANGED
@@ -39,3 +39,27 @@ en:
|
|
39
39
|
10000000: ["ten-millionth", "ten-millionths", "ten-millionths"]
|
40
40
|
100000000: ["hundred-millionth", "hundred-millionths", "hundred-millionths"]
|
41
41
|
1000000000: ["billionth", "billionths", "billionths"]
|
42
|
+
|
43
|
+
numbers:
|
44
|
+
ordinals:
|
45
|
+
default:
|
46
|
+
masculine: ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth",
|
47
|
+
"tenth", "eleventh", "twelfth", "thirteenth", "fourteenth" ,"fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth",
|
48
|
+
"twentieth", "twenty-first", "twenty-second", "twenty-third", "twenty-fourth", "twenty-fifth", "twenty-sixth", "twenty-seventh", "twenty-eighth", "twenty-ninth",
|
49
|
+
"thirtieth","thirty-first"]
|
50
|
+
datetime:
|
51
|
+
template: "%{date} at %{time}"
|
52
|
+
date:
|
53
|
+
template:
|
54
|
+
default: "the %{day} of %{month}, %{year}"
|
55
|
+
months:
|
56
|
+
default: [ "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" ]
|
57
|
+
time:
|
58
|
+
template:
|
59
|
+
hours_only: "%{hours}"
|
60
|
+
hours_minutes: "%{hours} %{minutes}"
|
61
|
+
hours_minutes_seconds: "%{hours} %{minutes} %{seconds}"
|
62
|
+
words:
|
63
|
+
hour: ["hour", "hours", "hours"]
|
64
|
+
minute: ["minute", "minutes", "minutes"]
|
65
|
+
second: ["second", "seconds", "seconds"]
|
data/config/locales/ru.yml
CHANGED
@@ -34,3 +34,43 @@ ru:
|
|
34
34
|
10000000: ["десятимиллионная", "десятимиллионные", "десятимиллионных"]
|
35
35
|
100000000: ["стомиллионная", "стомиллионные", "стомиллионных"]
|
36
36
|
1000000000: ["миллиардная", "миллиардные", "миллиардных"]
|
37
|
+
|
38
|
+
numbers:
|
39
|
+
ordinals:
|
40
|
+
nominative:
|
41
|
+
masculine: ["первый", "второй", "третий", "четвёртый", "пятый", "шестой", "седьмой", "восьмой", "девятый", "десятый",
|
42
|
+
"одиннадцатый", "двенадцатый", "тринадцатый", "четырнадцатый", "пятнадцатый", "шестнадцатый", "семнадцатый", "восемнадцатый", "девятнадцатый",
|
43
|
+
"двадцатый", "двадцать первый", "двадцать второй", "двадцать третий", "двадцать четвёртый", "двадцать пятый", "двадцать шестой", "двадцать седьмой", "двадцать восьмой", "двадцать девятый",
|
44
|
+
"тридцатый", "тридцать первый"]
|
45
|
+
feminine: ["первая", "вторая", "третья", "четвёртая", "пятая", "шестая", "седьмая", "восьмая", "девятая",
|
46
|
+
"десятая", "одиннадцатая", "двенадцатая", "тринадцатая", "четырнадцатая", "пятнадцатая", "шестнадцатая", "семнадцатая", "восемнадцатая", "девятнадцатая",
|
47
|
+
"двадцатая", "двадцать первая", "двадцать вторая", "двадцать третья", "двадцать четвёртая", "двадцать пятая", "двадцать шестая", "двадцать седьмая", "двадцать восьмая", "двадцать девятая",
|
48
|
+
"тридцатая", "тридцать первая"]
|
49
|
+
neuter: ["первое", "второе", "третье", "четвёртое", "пятое", "шестое", "седьмое", "восьмое", "девятое",
|
50
|
+
"десятое", "одиннадцатое", "двенадцатое", "тринадцатое", "четырнадцатое", "пятнадцатое", "шестнадцатое", "семнадцатое", "восемнадцатое", "девятнадцатое",
|
51
|
+
"двадцатое", "двадцать первое", "двадцать второе", "двадцать третье", "двадцать четвёртое", "двадцать пятое", "двадцать шестое", "двадцать седьмое", "двадцать восьмое", "двадцать девятое",
|
52
|
+
"тридцатое", "тридцать первое"]
|
53
|
+
default:
|
54
|
+
masculine: ["первого", "второго", "третьего", "четвёртого", "пятого", "шестого", "седьмого", "восьмого", "девятого",
|
55
|
+
"десятого", "одиннадцатого", "двенадцатого", "тринадцатого", "четырнадцатого", "пятнадцатого", "шестнадцатого", "семнадцатого", "восемнадцатого", "девятнадцатого",
|
56
|
+
"двадцатого", "двадцать первого", "двадцать второго", "двадцать третьего", "двадцать четвёртого", "двадцать пятого", "двадцать шестого", "двадцать седьмого", "двадцать восьмого", "двадцать девятого",
|
57
|
+
"тридцатого", "тридцать первого"]
|
58
|
+
|
59
|
+
datetime:
|
60
|
+
template: "%{date}, %{time}"
|
61
|
+
date:
|
62
|
+
template:
|
63
|
+
default: "%{day} %{month} %{year} года"
|
64
|
+
nominative: "%{day} %{month} %{year} год"
|
65
|
+
months:
|
66
|
+
default: [ "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря" ]
|
67
|
+
nominative: [ "января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря" ]
|
68
|
+
time:
|
69
|
+
template:
|
70
|
+
hours_only: "%{hours}"
|
71
|
+
hours_minutes: "%{hours} %{minutes}"
|
72
|
+
hours_minutes_seconds: "%{hours} %{minutes} %{seconds}"
|
73
|
+
words:
|
74
|
+
hour: ["час", "часа", "часов"]
|
75
|
+
minute: ["минута", "минуты", "минут"]
|
76
|
+
second: ["секунда", "секунды", "секунд"]
|
data/lib/num2words/converter.rb
CHANGED
@@ -1,21 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "date"
|
4
|
+
require "time"
|
5
|
+
|
3
6
|
module Num2words
|
4
7
|
class Converter
|
5
8
|
class << self
|
6
9
|
def to_words(number, *args, **opts)
|
7
|
-
locale
|
8
|
-
|
9
|
-
|
10
|
-
|
10
|
+
locale = args[0].is_a?(Symbol) ? args[0] : opts[:locale] || I18n.default_locale
|
11
|
+
type_only = args[1].is_a?(Symbol) ? args[1] : opts[:only]
|
12
|
+
type_short = args[2].is_a?(TrueClass) || args[2].is_a?(FalseClass) ? args[2] : opts[:short] || false
|
13
|
+
|
14
|
+
feminine = opts[:feminine] || false
|
15
|
+
style = opts[:style] || :fraction
|
16
|
+
word_case = opts[:word_case] || :default
|
17
|
+
date_format = opts[:format] || :default
|
18
|
+
|
11
19
|
locale_data = Locales[locale]
|
12
20
|
|
13
|
-
result =
|
14
|
-
|
15
|
-
|
16
|
-
|
21
|
+
result = case detect_type(number)
|
22
|
+
when :float then to_words_fractional(number, locale, feminine, locale_data, style: style)
|
23
|
+
when :integer then to_words_integer(number, locale, feminine, locale_data)
|
24
|
+
when :datetime then to_words_datetime(number, locale, locale_data, format: date_format, only: type_only, short: type_short)
|
25
|
+
when :date then to_words_date(number, locale, locale_data, format: date_format)
|
26
|
+
when :time then to_words_time(number, locale, locale_data, short: type_short)
|
27
|
+
else nil
|
17
28
|
end
|
18
29
|
|
30
|
+
raise ArgumentError, "Unsupported input type: #{number.inspect}" if result.nil?
|
31
|
+
|
19
32
|
apply_case(result, word_case)
|
20
33
|
end
|
21
34
|
|
@@ -41,6 +54,7 @@ module Num2words
|
|
41
54
|
private
|
42
55
|
|
43
56
|
def pluralize(number, singular, few, plural)
|
57
|
+
number = number.abs
|
44
58
|
return plural if (11..14).include?(number % 100)
|
45
59
|
|
46
60
|
case number % 10
|
@@ -123,6 +137,107 @@ module Num2words
|
|
123
137
|
words.join(" ")
|
124
138
|
end
|
125
139
|
|
140
|
+
def to_words_date(date, locale, locale_data, format: :default)
|
141
|
+
date = Date.parse(date.to_s) unless date.is_a?(Date)
|
142
|
+
|
143
|
+
day, month, year = [date.day, date.month, date.year]
|
144
|
+
|
145
|
+
return date.strftime("%d.%m.%Y") if format == :short
|
146
|
+
|
147
|
+
months = locale_data::DATE[:months][format] || locale_data::DATE[:months][:default]
|
148
|
+
template = locale_data::DATE_TEMPLATE[format] || locale_data::DATE_TEMPLATE[:default]
|
149
|
+
|
150
|
+
raise ArgumentError, "Months not found for locale #{locale}" unless months
|
151
|
+
raise ArgumentError, "Template not found for locale #{locale}" unless template
|
152
|
+
|
153
|
+
day_words = to_words_ordinal(day, locale, format, locale_data, gender: :neuter)
|
154
|
+
month_words = months[month - 1]
|
155
|
+
year_words = to_words_ordinal(year, locale, format, locale_data)
|
156
|
+
|
157
|
+
template % { day: day_words, month: month_words, year: year_words }
|
158
|
+
end
|
159
|
+
|
160
|
+
def to_words_ordinal(value, locale, format, locale_data, gender: :masculine)
|
161
|
+
ordinals = locale_data::ORDINALS[format] rescue nil
|
162
|
+
raise ArgumentError, "Ordinals not found for locale #{locale}, format #{format}" unless ordinals
|
163
|
+
|
164
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
165
|
+
raise ArgumentError, "Gender #{gender} not found for locale #{locale}, format #{format}" unless gender_data
|
166
|
+
|
167
|
+
return gender_data[value - 1] if gender_data[value]
|
168
|
+
|
169
|
+
if value > 31
|
170
|
+
thousands = (value / 100) * 100
|
171
|
+
last_two = value % 100
|
172
|
+
|
173
|
+
base_year = to_words_integer(thousands, locale, false, locale_data)
|
174
|
+
last_ordinal = gender_data[last_two - 1] || to_words_integer(last_two, locale, false, locale_data)
|
175
|
+
last_ordinal = to_words_integer(last_two, locale, false, locale_data) if locale == :en
|
176
|
+
|
177
|
+
return [base_year, last_ordinal].join(" ")
|
178
|
+
end
|
179
|
+
|
180
|
+
to_words_integer(value, locale, false, locale_data)
|
181
|
+
end
|
182
|
+
|
183
|
+
def to_words_time(time, locale, locale_data, format: :default, short: false)
|
184
|
+
time = Time.parse(time) if time.is_a?(String)
|
185
|
+
|
186
|
+
return time.strftime("%H:%M") if format == :short
|
187
|
+
|
188
|
+
words = locale_data::TIME[:words]
|
189
|
+
template = locale_data::TIME_TEMPLATE
|
190
|
+
|
191
|
+
hours = [
|
192
|
+
to_words_integer(time.hour, locale, false, locale_data),
|
193
|
+
pluralize(time.hour, *words[:hour])
|
194
|
+
].join(" ")
|
195
|
+
minutes = [
|
196
|
+
to_words_integer(time.min, locale, true, locale_data),
|
197
|
+
pluralize(time.min, *words[:minute])
|
198
|
+
].join(" ")
|
199
|
+
seconds = [
|
200
|
+
to_words_integer(time.sec, locale, true, locale_data),
|
201
|
+
pluralize(time.sec, *words[:second])
|
202
|
+
].join(" ")
|
203
|
+
|
204
|
+
format = if short
|
205
|
+
time.min.zero? && time.sec.zero? ? :hours_only : :hours_minutes
|
206
|
+
else
|
207
|
+
format
|
208
|
+
end
|
209
|
+
|
210
|
+
case format
|
211
|
+
when :hours_only
|
212
|
+
template[:hours_only] % { hours: hours }
|
213
|
+
when :hours_minutes
|
214
|
+
template[:hours_minutes] % { hours: hours, minutes: minutes }
|
215
|
+
when :hours_minutes_seconds, :default
|
216
|
+
template[:hours_minutes_seconds] % { hours: hours, minutes: minutes, seconds: seconds }
|
217
|
+
else
|
218
|
+
raise ArgumentError, "Unsupported time format: #{format}"
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
|
223
|
+
def to_words_datetime(datetime, locale, locale_data, format: :default, only: nil, short: false)
|
224
|
+
datetime = DateTime.parse(datetime) if datetime.is_a?(String)
|
225
|
+
|
226
|
+
date_format = short && only == :date ? :short : format
|
227
|
+
time_format = short && only == :time ? :short : :default
|
228
|
+
|
229
|
+
date_part = to_words_date(datetime.to_date, locale, locale_data, format: date_format)
|
230
|
+
time_part = to_words_time(datetime.to_time, locale, locale_data, format: time_format, short: short)
|
231
|
+
|
232
|
+
return date_part if only == :date
|
233
|
+
return time_part if only == :time
|
234
|
+
|
235
|
+
return "#{date_part}, #{time_part}" if short
|
236
|
+
|
237
|
+
template = locale_data::DATETIME_TEMPLATE
|
238
|
+
template % { date: date_part, time: time_part }
|
239
|
+
end
|
240
|
+
|
126
241
|
def apply_case(text, word_case)
|
127
242
|
case word_case
|
128
243
|
when :upper then text.upcase
|
@@ -132,6 +247,35 @@ module Num2words
|
|
132
247
|
else text
|
133
248
|
end
|
134
249
|
end
|
250
|
+
|
251
|
+
def detect_type(value)
|
252
|
+
case value
|
253
|
+
when Integer then :integer
|
254
|
+
when Float then :float
|
255
|
+
when Date then :date
|
256
|
+
when Time then :time
|
257
|
+
when DateTime then :datetime
|
258
|
+
when String
|
259
|
+
return :integer if value.match?(/\A-?\d+\z/)
|
260
|
+
return :float if value.match?(/\A-?\d+\.\d+\z/)
|
261
|
+
return :time if value.match?(/\A\d{1,2}:\d{2}(:\d{2})?\z/)
|
262
|
+
|
263
|
+
# Форматы даты
|
264
|
+
return :date if value.match?(/\A\d{1,2}[.\-]\d{1,2}[.\-]\d{2,4}\z/)
|
265
|
+
return :date if value.match?(/\A\d{4}-\d{2}-\d{2}\z/)
|
266
|
+
return :datetime if value.match?(/\A\d{1,2}[.\-]\d{1,2}[.\-]\d{2,4}\s+\d{1,2}:\d{2}(:\d{2})?\z/)
|
267
|
+
return :datetime if value.match?(/\A\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2})?([.,]\d+)?(Z|[+\-]\d{2}:?\d{2})?\z/)
|
268
|
+
|
269
|
+
begin
|
270
|
+
date_time = DateTime.parse(value)
|
271
|
+
(date_time.hour != 0 || date_time.min != 0 || date_time.sec != 0) ? :datetime : :date
|
272
|
+
rescue ArgumentError
|
273
|
+
:string
|
274
|
+
end
|
275
|
+
else
|
276
|
+
:unknown
|
277
|
+
end
|
278
|
+
end
|
135
279
|
end
|
136
280
|
end
|
137
281
|
end
|
data/lib/num2words/core_ext.rb
CHANGED
@@ -19,3 +19,27 @@ class Float
|
|
19
19
|
Num2words::Converter.to_currency(self, *args, **opts)
|
20
20
|
end
|
21
21
|
end
|
22
|
+
|
23
|
+
class String
|
24
|
+
def to_words(*args, **opts)
|
25
|
+
Num2words::Converter.to_words(self, *args, **opts)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Date
|
30
|
+
def to_words(*args, **opts)
|
31
|
+
Num2words::Converter.to_words(self.strftime("%d.%m.%Y"), *args, **opts)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Time
|
36
|
+
def to_words(*args, **opts)
|
37
|
+
Num2words::Converter.to_words(self.strftime("%H:%M:%S"), *args, **opts)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class DateTime
|
42
|
+
def to_words(*args, **opts)
|
43
|
+
Num2words::Converter.to_words(self.strftime("%d.%m.%Y %H:%M:%S"), *args, **opts)
|
44
|
+
end
|
45
|
+
end
|
data/lib/num2words/locales/en.rb
CHANGED
@@ -15,6 +15,14 @@ module Num2words
|
|
15
15
|
|
16
16
|
FRACTIONS = I18n.t("num2words.fractions", locale: :en)
|
17
17
|
GRAMMAR = I18n.t("num2words.grammar", locale: :en)
|
18
|
+
|
19
|
+
DATE = I18n.t("num2words.date", locale: :en)
|
20
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :en)
|
21
|
+
TIME = I18n.t("num2words.time", locale: :en)
|
22
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :en)
|
23
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :en)
|
24
|
+
|
25
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :en)
|
18
26
|
end
|
19
27
|
|
20
28
|
register :en, EN
|
data/lib/num2words/locales/ru.rb
CHANGED
@@ -15,6 +15,14 @@ module Num2words
|
|
15
15
|
|
16
16
|
FRACTIONS = I18n.t("num2words.fractions", locale: :ru)
|
17
17
|
GRAMMAR = I18n.t("num2words.grammar", locale: :ru)
|
18
|
+
|
19
|
+
DATE = I18n.t("num2words.date", locale: :ru)
|
20
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :ru)
|
21
|
+
TIME = I18n.t("num2words.time", locale: :ru)
|
22
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :ru)
|
23
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :ru)
|
24
|
+
|
25
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :ru)
|
18
26
|
end
|
19
27
|
|
20
28
|
register :ru, RU
|
data/lib/num2words/version.rb
CHANGED
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.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ruslan Fedotov
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-08-
|
11
|
+
date: 2025-08-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|