num2words 0.1.3 → 0.1.4
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 +27 -0
- data/config/locales/en.yml +14 -0
- data/config/locales/ru.yml +29 -0
- data/lib/num2words/converter.rb +71 -5
- data/lib/num2words/core_ext.rb +12 -0
- data/lib/num2words/locales/en.rb +5 -0
- data/lib/num2words/locales/ru.rb +5 -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: 1809289bec98157e0b78b8bbe9f18b5fab8fa5f111293105e89b5747d866e43d
|
4
|
+
data.tar.gz: 1e5cfdd50831c7e9f75a8216488268564cda27b7972c70feca0a9d34c05c907b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 353353c876466e244bf2748073d7a3534a5ead257bc8d7f70f35d975a45762f4d2e0023d2cbf6e55136587974278093987fd2bba4d20ec972f33bedc9a1820c2
|
7
|
+
data.tar.gz: 8037de95f9896db0f4b00aa16710836de2337416c646dfc40900f3021a019aba9c04ae7f06842ebc6be73904aca9156258ee766992a861196a3274008ca13ab4
|
data/CHANGELOG.md
CHANGED
@@ -15,6 +15,33 @@
|
|
15
15
|
|
16
16
|
---
|
17
17
|
|
18
|
+
## [0.1.4] - 2025-08-21
|
19
|
+
### Added
|
20
|
+
- Расширение `String#to_words`, возможность преобразовать строки с датами
|
21
|
+
```ruby
|
22
|
+
"21.08.2025".to_words(:ru)
|
23
|
+
# => "двадцать первое августа две тысячи двадцать пятого года"
|
24
|
+
|
25
|
+
"21.08.2025".to_words(:en)
|
26
|
+
# => "the twenty-first of August, two thousand twenty five"
|
27
|
+
```
|
28
|
+
- Расширение `Date#to_words`, добавлена возможность преобразовывать объекты Date и DateTime
|
29
|
+
```ruby
|
30
|
+
Date.new(2025, 8, 21).to_words(:ru)
|
31
|
+
# => "двадцать первого августа две тысячи двадцать пятого года"
|
32
|
+
|
33
|
+
Date.new(2025, 8, 21).to_words(:en)
|
34
|
+
# => "the twenty-first of August, two thousand twenty-five"
|
35
|
+
```
|
36
|
+
- Поддержка параметра `format: :nominative`, можно получать даты в именительном падеже.
|
37
|
+
```ruby
|
38
|
+
Date.new(2025, 8, 21).to_words(:ru, format: :nominative)
|
39
|
+
# => "двадцать первое августа две тысячи двадцать пятый год"
|
40
|
+
|
41
|
+
"19.07.2012".to_words(:ru, format: :nominative)
|
42
|
+
# => "девятнадцатое июля две тысячи двенадцатый год"
|
43
|
+
```
|
44
|
+
|
18
45
|
## [0.1.3] – 2025-08-20
|
19
46
|
### Added
|
20
47
|
- Параметр **`word_case:`** для методов `to_words`, `to_currency` со значениями:
|
data/config/locales/en.yml
CHANGED
@@ -39,3 +39,17 @@ 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
|
+
date:
|
44
|
+
template:
|
45
|
+
default: "the %{day} of %{month}, %{year}"
|
46
|
+
months:
|
47
|
+
default: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
|
48
|
+
|
49
|
+
numbers:
|
50
|
+
ordinals:
|
51
|
+
default:
|
52
|
+
masculine: ["first", "second", "third", "fourth", "fifth", "sixth", "seventh", "eighth", "ninth",
|
53
|
+
"tenth", "eleventh", "twelfth", "thirteenth", "fourteenth" ,"fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth",
|
54
|
+
"twentieth", "twenty-first", "twenty-second", "twenty-third", "twenty-fourth", "twenty-fifth", "twenty-sixth", "twenty-seventh", "twenty-eighth", "twenty-ninth",
|
55
|
+
"thirtieth","thirty-first"]
|
data/config/locales/ru.yml
CHANGED
@@ -34,3 +34,32 @@ ru:
|
|
34
34
|
10000000: ["десятимиллионная", "десятимиллионные", "десятимиллионных"]
|
35
35
|
100000000: ["стомиллионная", "стомиллионные", "стомиллионных"]
|
36
36
|
1000000000: ["миллиардная", "миллиардные", "миллиардных"]
|
37
|
+
|
38
|
+
date:
|
39
|
+
template:
|
40
|
+
default: "%{day} %{month} %{year} года"
|
41
|
+
nominative: "%{day} %{month} %{year} год"
|
42
|
+
months:
|
43
|
+
default: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"]
|
44
|
+
nominative: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"]
|
45
|
+
|
46
|
+
numbers:
|
47
|
+
ordinals:
|
48
|
+
nominative:
|
49
|
+
masculine: ["первый", "второй", "третий", "четвёртый", "пятый", "шестой", "седьмой", "восьмой", "девятый", "десятый",
|
50
|
+
"одиннадцатый", "двенадцатый", "тринадцатый", "четырнадцатый", "пятнадцатый", "шестнадцатый", "семнадцатый", "восемнадцатый", "девятнадцатый",
|
51
|
+
"двадцатый", "двадцать первый", "двадцать второй", "двадцать третий", "двадцать четвёртый", "двадцать пятый", "двадцать шестой", "двадцать седьмой", "двадцать восьмой", "двадцать девятый",
|
52
|
+
"тридцатый", "тридцать первый"]
|
53
|
+
feminine: ["первая", "вторая", "третья", "четвёртая", "пятая", "шестая", "седьмая", "восьмая", "девятая",
|
54
|
+
"десятая", "одиннадцатая", "двенадцатая", "тринадцатая", "четырнадцатая", "пятнадцатая", "шестнадцатая", "семнадцатая", "восемнадцатая", "девятнадцатая",
|
55
|
+
"двадцатая", "двадцать первая", "двадцать вторая", "двадцать третья", "двадцать четвёртая", "двадцать пятая", "двадцать шестая", "двадцать седьмая", "двадцать восьмая", "двадцать девятая",
|
56
|
+
"тридцатая", "тридцать первая"]
|
57
|
+
neuter: ["первое", "второе", "третье", "четвёртое", "пятое", "шестое", "седьмое", "восьмое", "девятое",
|
58
|
+
"десятое", "одиннадцатое", "двенадцатое", "тринадцатое", "четырнадцатое", "пятнадцатое", "шестнадцатое", "семнадцатое", "восемнадцатое", "девятнадцатое",
|
59
|
+
"двадцатое", "двадцать первое", "двадцать второе", "двадцать третье", "двадцать четвёртое", "двадцать пятое", "двадцать шестое", "двадцать седьмое", "двадцать восьмое", "двадцать девятое",
|
60
|
+
"тридцатое", "тридцать первое"]
|
61
|
+
default:
|
62
|
+
masculine: ["первого", "второго", "третьего", "четвёртого", "пятого", "шестого", "седьмого", "восьмого", "девятого",
|
63
|
+
"десятого", "одиннадцатого", "двенадцатого", "тринадцатого", "четырнадцатого", "пятнадцатого", "шестнадцатого", "семнадцатого", "восемнадцатого", "девятнадцатого",
|
64
|
+
"двадцатого", "двадцать первого", "двадцать второго", "двадцать третьего", "двадцать четвёртого", "двадцать пятого", "двадцать шестого", "двадцать седьмого", "двадцать восьмого", "двадцать девятого",
|
65
|
+
"тридцатого", "тридцать первого"]
|
data/lib/num2words/converter.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "date"
|
4
|
+
|
3
5
|
module Num2words
|
4
6
|
class Converter
|
5
7
|
class << self
|
@@ -7,15 +9,19 @@ module Num2words
|
|
7
9
|
locale = args.first.is_a?(Symbol) ? args.first : opts[:locale] || I18n.default_locale
|
8
10
|
feminine = opts[:feminine] || false
|
9
11
|
style = opts[:style] || :fraction
|
10
|
-
word_case = opts[:word_case] || :
|
12
|
+
word_case = opts[:word_case] || :default
|
13
|
+
date_format = opts[:format] || :default
|
11
14
|
locale_data = Locales[locale]
|
12
15
|
|
13
|
-
result =
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
result = case detect_type(number)
|
17
|
+
when :float then to_words_fractional(number, locale, feminine, locale_data, style: style)
|
18
|
+
when :integer then to_words_integer(number, locale, feminine, locale_data)
|
19
|
+
when :date then to_words_date(number, locale, locale_data, format: date_format)
|
20
|
+
else nil
|
17
21
|
end
|
18
22
|
|
23
|
+
raise ArgumentError, "Unsupported input type: #{number.inspect}" if result.nil?
|
24
|
+
|
19
25
|
apply_case(result, word_case)
|
20
26
|
end
|
21
27
|
|
@@ -123,6 +129,47 @@ module Num2words
|
|
123
129
|
words.join(" ")
|
124
130
|
end
|
125
131
|
|
132
|
+
def to_words_date(date, locale, locale_data, format: :default)
|
133
|
+
date = Date.parse(date.to_s) unless date.is_a?(Date)
|
134
|
+
|
135
|
+
day, month, year = [date.day, date.month, date.year]
|
136
|
+
|
137
|
+
months = locale_data::DATE[:months][format] || locale_data::DATE[:months][:default]
|
138
|
+
template = locale_data::TEMPLATE[format] || locale_data::TEMPLATE[:default]
|
139
|
+
|
140
|
+
raise ArgumentError, "Months not found for locale #{locale}" unless months
|
141
|
+
raise ArgumentError, "Template not found for locale #{locale}" unless template
|
142
|
+
|
143
|
+
day_words = to_words_ordinal(day, locale, format, locale_data, gender: :neuter)
|
144
|
+
month_words = months[month - 1]
|
145
|
+
year_words = to_words_ordinal(year, locale, format, locale_data)
|
146
|
+
|
147
|
+
template % { day: day_words, month: month_words, year: year_words }
|
148
|
+
end
|
149
|
+
|
150
|
+
def to_words_ordinal(value, locale, format, locale_data, gender: :masculine)
|
151
|
+
ordinals = locale_data::ORDINALS[format] rescue nil
|
152
|
+
raise ArgumentError, "Ordinals not found for locale #{locale}, format #{format}" unless ordinals
|
153
|
+
|
154
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
155
|
+
raise ArgumentError, "Gender #{gender} not found for locale #{locale}, format #{format}" unless gender_data
|
156
|
+
|
157
|
+
return gender_data[value - 1] if gender_data[value]
|
158
|
+
|
159
|
+
if value > 31
|
160
|
+
thousands = (value / 100) * 100
|
161
|
+
last_two = value % 100
|
162
|
+
|
163
|
+
base_year = to_words_integer(thousands, locale, false, locale_data)
|
164
|
+
last_ordinal = gender_data[last_two - 1] || to_words_integer(last_two, locale, false, locale_data)
|
165
|
+
last_ordinal = to_words_integer(last_two, locale, false, locale_data) if locale == :en
|
166
|
+
|
167
|
+
return [base_year, last_ordinal].join(" ")
|
168
|
+
end
|
169
|
+
|
170
|
+
to_words_integer(value, locale, false, locale_data)
|
171
|
+
end
|
172
|
+
|
126
173
|
def apply_case(text, word_case)
|
127
174
|
case word_case
|
128
175
|
when :upper then text.upcase
|
@@ -132,6 +179,25 @@ module Num2words
|
|
132
179
|
else text
|
133
180
|
end
|
134
181
|
end
|
182
|
+
|
183
|
+
def detect_type(value)
|
184
|
+
case value
|
185
|
+
when Integer then :integer
|
186
|
+
when Float then :float
|
187
|
+
when Date, Time, ::DateTime then :date
|
188
|
+
when String
|
189
|
+
return :integer if /\A-?\d+\z/.match?(value)
|
190
|
+
return :float if /\A-?\d+\.\d+\z/.match?(value)
|
191
|
+
|
192
|
+
begin
|
193
|
+
Date.parse(value)
|
194
|
+
:date
|
195
|
+
rescue ArgumentError
|
196
|
+
:string
|
197
|
+
end
|
198
|
+
else :unknown
|
199
|
+
end
|
200
|
+
end
|
135
201
|
end
|
136
202
|
end
|
137
203
|
end
|
data/lib/num2words/core_ext.rb
CHANGED
@@ -19,3 +19,15 @@ 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
|
data/lib/num2words/locales/en.rb
CHANGED
@@ -15,6 +15,11 @@ 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
|
+
TEMPLATE = I18n.t("num2words.date.template", locale: :en)
|
21
|
+
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :en)
|
18
23
|
end
|
19
24
|
|
20
25
|
register :en, EN
|
data/lib/num2words/locales/ru.rb
CHANGED
@@ -15,6 +15,11 @@ 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
|
+
TEMPLATE = I18n.t("num2words.date.template", locale: :ru)
|
21
|
+
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :ru)
|
18
23
|
end
|
19
24
|
|
20
25
|
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.4
|
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-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: i18n
|