num2words 0.1.5 → 0.2.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 +43 -0
- data/Gemfile +0 -1
- data/README.md +57 -16
- data/bin/console +2 -14
- data/config/locales/ar.yml +176 -17
- data/config/locales/be.yml +182 -15
- data/config/locales/bg.yml +183 -16
- data/config/locales/bn.yml +185 -12
- data/config/locales/cs.yml +180 -13
- data/config/locales/da.yml +182 -15
- data/config/locales/de.yml +181 -14
- data/config/locales/el.yml +183 -21
- data/config/locales/en.yml +129 -12
- data/config/locales/es.yml +180 -13
- data/config/locales/et.yml +185 -13
- data/config/locales/fa.yml +179 -12
- data/config/locales/fi.yml +180 -8
- data/config/locales/fr.yml +180 -13
- data/config/locales/gu.yml +182 -10
- data/config/locales/he.yml +182 -20
- data/config/locales/hi.yml +182 -15
- data/config/locales/hr.yml +181 -14
- data/config/locales/hu.yml +180 -13
- data/config/locales/id.yml +179 -12
- data/config/locales/it.yml +181 -14
- data/config/locales/ja.yml +188 -21
- data/config/locales/ru.yml +135 -9
- data/exe/num2words-console +7 -0
- data/lib/num2words/config.rb +62 -0
- data/lib/num2words/console.rb +16 -0
- data/lib/num2words/converter.rb +94 -47
- data/lib/num2words/locales/ar.rb +10 -2
- data/lib/num2words/locales/be.rb +10 -2
- data/lib/num2words/locales/bg.rb +10 -2
- data/lib/num2words/locales/bn.rb +10 -2
- data/lib/num2words/locales/cs.rb +10 -2
- data/lib/num2words/locales/da.rb +10 -2
- data/lib/num2words/locales/de.rb +10 -2
- data/lib/num2words/locales/el.rb +10 -2
- data/lib/num2words/locales/en.rb +0 -3
- data/lib/num2words/locales/es.rb +10 -2
- data/lib/num2words/locales/et.rb +10 -2
- data/lib/num2words/locales/fa.rb +10 -2
- data/lib/num2words/locales/fi.rb +10 -2
- data/lib/num2words/locales/fr.rb +10 -2
- data/lib/num2words/locales/gu.rb +10 -2
- data/lib/num2words/locales/he.rb +10 -2
- data/lib/num2words/locales/hi.rb +10 -2
- data/lib/num2words/locales/hr.rb +10 -2
- data/lib/num2words/locales/hu.rb +10 -2
- data/lib/num2words/locales/id.rb +10 -2
- data/lib/num2words/locales/it.rb +10 -2
- data/lib/num2words/locales/ja.rb +10 -2
- data/lib/num2words/locales/ru.rb +0 -3
- data/lib/num2words/version.rb +1 -1
- data/lib/num2words.rb +1 -0
- data/num2words.gemspec +1 -1
- metadata +9 -5
data/config/locales/ru.yml
CHANGED
|
@@ -13,13 +13,6 @@ ru:
|
|
|
13
13
|
- ["миллиард", "миллиарда", "миллиардов"]
|
|
14
14
|
- ["триллион", "триллиона", "триллионов"]
|
|
15
15
|
|
|
16
|
-
currencies:
|
|
17
|
-
RUB:
|
|
18
|
-
name: ["рубль", "рубля", "рублей"]
|
|
19
|
-
fractional:
|
|
20
|
-
name: ["копейка", "копейки", "копеек"]
|
|
21
|
-
feminine: true
|
|
22
|
-
|
|
23
16
|
grammar:
|
|
24
17
|
minus: "минус"
|
|
25
18
|
conjunction: "целых"
|
|
@@ -55,6 +48,10 @@ ru:
|
|
|
55
48
|
"десятого", "одиннадцатого", "двенадцатого", "тринадцатого", "четырнадцатого", "пятнадцатого", "шестнадцатого", "семнадцатого", "восемнадцатого", "девятнадцатого",
|
|
56
49
|
"двадцатого", "двадцать первого", "двадцать второго", "двадцать третьего", "двадцать четвёртого", "двадцать пятого", "двадцать шестого", "двадцать седьмого", "двадцать восьмого", "двадцать девятого",
|
|
57
50
|
"тридцатого", "тридцать первого"]
|
|
51
|
+
neuter: ["первое", "второе", "третье", "четвёртое", "пятое", "шестое", "седьмое", "восьмое", "девятое",
|
|
52
|
+
"десятое", "одиннадцатое", "двенадцатое", "тринадцатое", "четырнадцатое", "пятнадцатое", "шестнадцатое", "семнадцатое", "восемнадцатое", "девятнадцатое",
|
|
53
|
+
"двадцатое", "двадцать первое", "двадцать второе", "двадцать третье", "двадцать четвёртое", "двадцать пятое", "двадцать шестое", "двадцать седьмое", "двадцать восьмое", "двадцать девятое",
|
|
54
|
+
"тридцатое", "тридцать первое"]
|
|
58
55
|
|
|
59
56
|
datetime:
|
|
60
57
|
template: "%{date}, %{time}"
|
|
@@ -63,8 +60,8 @@ ru:
|
|
|
63
60
|
default: "%{day} %{month} %{year} года"
|
|
64
61
|
nominative: "%{day} %{month} %{year} год"
|
|
65
62
|
months:
|
|
66
|
-
default: [
|
|
67
|
-
nominative: [
|
|
63
|
+
default: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"]
|
|
64
|
+
nominative: ["января", "февраля", "марта", "апреля", "мая", "июня", "июля", "августа", "сентября", "октября", "ноября", "декабря"]
|
|
68
65
|
time:
|
|
69
66
|
template:
|
|
70
67
|
hours_only: "%{hours}"
|
|
@@ -74,3 +71,132 @@ ru:
|
|
|
74
71
|
hour: ["час", "часа", "часов"]
|
|
75
72
|
minute: ["минута", "минуты", "минут"]
|
|
76
73
|
second: ["секунда", "секунды", "секунд"]
|
|
74
|
+
|
|
75
|
+
warnings:
|
|
76
|
+
currency_not_available: "Валюта %{currency} недоступна для локали %{lang}, используется текущая."
|
|
77
|
+
|
|
78
|
+
currencies:
|
|
79
|
+
RUB:
|
|
80
|
+
major_unit: ["рубль", "рубля", "рублей"]
|
|
81
|
+
minor_unit: ["копейка", "копейки", "копеек"]
|
|
82
|
+
symbol: "₽"
|
|
83
|
+
USD:
|
|
84
|
+
major_unit: ["доллар", "доллара", "долларов"]
|
|
85
|
+
minor_unit: ["цент", "цента", "центов"]
|
|
86
|
+
symbol: "$"
|
|
87
|
+
EUR:
|
|
88
|
+
major_unit: ["евро", "евро", "евро"]
|
|
89
|
+
minor_unit: ["цент", "цента", "центов"]
|
|
90
|
+
symbol: "€"
|
|
91
|
+
GBP:
|
|
92
|
+
major_unit: ["фунт", "фунта", "фунтов"]
|
|
93
|
+
minor_unit: ["пенс", "пенса", "пенсов"]
|
|
94
|
+
symbol: "£"
|
|
95
|
+
CNY:
|
|
96
|
+
major_unit: ["юань", "юаня", "юаней"]
|
|
97
|
+
minor_unit: ["фэнь", "фэня", "фэней"]
|
|
98
|
+
symbol: "¥"
|
|
99
|
+
JPY:
|
|
100
|
+
major_unit: ["иена", "иены", "иен"]
|
|
101
|
+
minor_unit: ["сэн", "сэн", "сэн"]
|
|
102
|
+
symbol: "¥"
|
|
103
|
+
KRW:
|
|
104
|
+
major_unit: ["вона", "воны", "вон"]
|
|
105
|
+
minor_unit: ["чон", "чона", "чон"]
|
|
106
|
+
symbol: "₩"
|
|
107
|
+
TRY:
|
|
108
|
+
major_unit: ["лира", "лиры", "лир"]
|
|
109
|
+
minor_unit: ["куруш", "куруша", "курушей"]
|
|
110
|
+
symbol: "₺"
|
|
111
|
+
PLN:
|
|
112
|
+
major_unit: ["злотый", "злотых", "злотых"]
|
|
113
|
+
minor_unit: ["грош", "гроша", "грошей"]
|
|
114
|
+
symbol: "zł"
|
|
115
|
+
UAH:
|
|
116
|
+
major_unit: ["гривна", "гривны", "гривен"]
|
|
117
|
+
minor_unit: ["копейка", "копейки", "копеек"]
|
|
118
|
+
symbol: "₴"
|
|
119
|
+
CZK:
|
|
120
|
+
major_unit: ["крона", "кроны", "крон"]
|
|
121
|
+
minor_unit: ["галирж", "галиржа", "галиржей"]
|
|
122
|
+
symbol: "Kč"
|
|
123
|
+
RON:
|
|
124
|
+
major_unit: ["лей", "лея", "леев"]
|
|
125
|
+
minor_unit: ["бан", "бана", "банов"]
|
|
126
|
+
symbol: "lei"
|
|
127
|
+
BGN:
|
|
128
|
+
major_unit: ["лев", "лева", "левов"]
|
|
129
|
+
minor_unit: ["стотинка", "стотинки", "стотинок"]
|
|
130
|
+
symbol: "лв"
|
|
131
|
+
BYN:
|
|
132
|
+
major_unit: ["белорусский рубль", "белорусских рубля", "белорусских рублей"]
|
|
133
|
+
minor_unit: ["копейка", "копейки", "копеек"]
|
|
134
|
+
symbol: "Br"
|
|
135
|
+
KZT:
|
|
136
|
+
major_unit: ["тенге", "тенге", "тенге"]
|
|
137
|
+
minor_unit: ["тиын", "тиына", "тиынов"]
|
|
138
|
+
symbol: "₸"
|
|
139
|
+
ILS:
|
|
140
|
+
major_unit: ["шекель", "шекеля", "шекелей"]
|
|
141
|
+
minor_unit: ["агора", "агоры", "агорот"]
|
|
142
|
+
symbol: "₪"
|
|
143
|
+
SEK:
|
|
144
|
+
major_unit: ["крона", "кроны", "крон"]
|
|
145
|
+
minor_unit: ["эре", "эре", "эре"]
|
|
146
|
+
symbol: "kr"
|
|
147
|
+
NOK:
|
|
148
|
+
major_unit: ["крона", "кроны", "крон"]
|
|
149
|
+
minor_unit: ["эре", "эре", "эре"]
|
|
150
|
+
symbol: "kr"
|
|
151
|
+
DKK:
|
|
152
|
+
major_unit: ["крона", "кроны", "крон"]
|
|
153
|
+
minor_unit: ["эре", "эре", "эре"]
|
|
154
|
+
symbol: "kr"
|
|
155
|
+
HUF:
|
|
156
|
+
major_unit: ["форинт", "форинта", "форинтов"]
|
|
157
|
+
minor_unit: ["филлер", "филлера", "филлеров"]
|
|
158
|
+
symbol: "Ft"
|
|
159
|
+
SAR:
|
|
160
|
+
major_unit: ["риал", "риала", "риалов"]
|
|
161
|
+
minor_unit: ["халяла", "халялы", "халялов"]
|
|
162
|
+
symbol: "﷼"
|
|
163
|
+
INR:
|
|
164
|
+
major_unit: ["рупия", "рупии", "рупий"]
|
|
165
|
+
minor_unit: ["пайса", "пайсы", "пайс"]
|
|
166
|
+
symbol: "₹"
|
|
167
|
+
THB:
|
|
168
|
+
major_unit: ["бат", "бата", "батов"]
|
|
169
|
+
minor_unit: ["сатанг", "сатанга", "сатангов"]
|
|
170
|
+
symbol: "฿"
|
|
171
|
+
VND:
|
|
172
|
+
major_unit: ["донг", "донга", "донгов"]
|
|
173
|
+
minor_unit: ["су", "су", "су"]
|
|
174
|
+
symbol: "₫"
|
|
175
|
+
IDR:
|
|
176
|
+
major_unit: ["рупия", "рупии", "рупий"]
|
|
177
|
+
minor_unit: ["сена", "сены", "сенов"]
|
|
178
|
+
symbol: "Rp"
|
|
179
|
+
IRR:
|
|
180
|
+
major_unit: ["риал", "риала", "риалов"]
|
|
181
|
+
minor_unit: ["динам", "динама", "динамов"]
|
|
182
|
+
symbol: "﷼"
|
|
183
|
+
RSD:
|
|
184
|
+
major_unit: ["динар", "динара", "динаров"]
|
|
185
|
+
minor_unit: ["пара", "пары", "пар"]
|
|
186
|
+
symbol: "дин"
|
|
187
|
+
MYR:
|
|
188
|
+
major_unit: ["ринггит", "ринггита", "ринггитов"]
|
|
189
|
+
minor_unit: ["сен", "сена", "сенов"]
|
|
190
|
+
symbol: "RM"
|
|
191
|
+
BDT:
|
|
192
|
+
major_unit: ["така", "таки", "так"]
|
|
193
|
+
minor_unit: ["пойша", "пойши", "пойш"]
|
|
194
|
+
symbol: "৳"
|
|
195
|
+
PKR:
|
|
196
|
+
major_unit: ["рупия", "рупии", "рупий"]
|
|
197
|
+
minor_unit: ["пайса", "пайсы", "пайс"]
|
|
198
|
+
symbol: "₨"
|
|
199
|
+
KES:
|
|
200
|
+
major_unit: ["шиллинг", "шиллинга", "шиллингов"]
|
|
201
|
+
minor_unit: ["цент", "цента", "центов"]
|
|
202
|
+
symbol: "Sh"
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Num2words
|
|
4
|
+
class Config
|
|
5
|
+
attr_accessor :currency_warnings
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
reset!
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def default_currency(locale = nil, currency = nil)
|
|
12
|
+
if currency
|
|
13
|
+
currency = currency.to_s.upcase.to_sym
|
|
14
|
+
available = available_currencies(locale)
|
|
15
|
+
|
|
16
|
+
if available.include?(currency)
|
|
17
|
+
locale ? @local_currency[locale] = currency : @global_currency = currency
|
|
18
|
+
elsif currency_warnings
|
|
19
|
+
warn I18n.t("num2words.warnings.currency_not_available", lang: locale, currency: currency, locale: locale)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
locale ? (@local_currency[locale] || available_currencies(locale).first || @global_currency) : @global_currency
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def available_currencies(locale = I18n.locale)
|
|
27
|
+
I18n.t("num2words.currencies", locale: locale).keys.map(&:to_sym)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def reset!(locale = nil)
|
|
31
|
+
return @local_currency.delete(locale) if locale
|
|
32
|
+
|
|
33
|
+
@global_currency = available_currencies.first
|
|
34
|
+
@local_currency = {}
|
|
35
|
+
@currency_warnings = true
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def self.config
|
|
40
|
+
@config ||= Config.new
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def self.reset!
|
|
44
|
+
config.reset!(locale)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def self.default_currency(locale = nil, currency = nil)
|
|
48
|
+
config.default_currency(locale, currency)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def self.available_currencies(locale = I18n.locale)
|
|
52
|
+
config.available_currencies(locale)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def self.currency_warnings
|
|
56
|
+
config.currency_warnings
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def self.currency_warnings=(value)
|
|
60
|
+
config.currency_warnings = value
|
|
61
|
+
end
|
|
62
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Num2words
|
|
4
|
+
module Console
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def start
|
|
8
|
+
puts "Добро пожаловать в консоль num2words!"
|
|
9
|
+
puts "Можете использовать: Num2words.to_words(#{Time.now.year})"
|
|
10
|
+
puts "-------------------------------------------------------------"
|
|
11
|
+
|
|
12
|
+
require "irb"
|
|
13
|
+
IRB.start(__FILE__)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/num2words/converter.rb
CHANGED
|
@@ -2,27 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
require "date"
|
|
4
4
|
require "time"
|
|
5
|
+
require "bigdecimal"
|
|
5
6
|
|
|
6
7
|
module Num2words
|
|
7
8
|
class Converter
|
|
8
9
|
class << self
|
|
9
10
|
def to_words(number, *args, **opts)
|
|
10
|
-
locale
|
|
11
|
-
type_only
|
|
12
|
-
type_short
|
|
11
|
+
locale = args[0].is_a?(Symbol) ? args[0] : opts[:locale] || I18n.default_locale
|
|
12
|
+
type_only = args[1].is_a?(Symbol) ? args[1] : opts[:only]
|
|
13
|
+
type_short = args[2].is_a?(TrueClass) || args[2].is_a?(FalseClass) ? args[2] : opts[:short] || false
|
|
13
14
|
|
|
14
|
-
feminine
|
|
15
|
-
style
|
|
16
|
-
word_case
|
|
15
|
+
feminine = opts[:feminine] || false
|
|
16
|
+
style = opts[:style] || :fraction
|
|
17
|
+
word_case = opts[:word_case] || :default
|
|
17
18
|
date_format = opts[:format] || :default
|
|
19
|
+
date_case = opts[:date_case] || :default
|
|
20
|
+
joiner = opts[:joiner] || :default
|
|
21
|
+
|
|
22
|
+
validate_option!(:date_case, date_case, %i[default genitive])
|
|
23
|
+
validate_option!(:joiner, joiner, %i[default and])
|
|
18
24
|
|
|
19
25
|
locale_data = Locales[locale]
|
|
20
26
|
|
|
21
27
|
result = case detect_type(number)
|
|
22
|
-
when :float then to_words_fractional(number, locale, feminine, locale_data, style: style)
|
|
28
|
+
when :float then to_words_fractional(number, locale, feminine, locale_data, style: style, joiner: joiner)
|
|
23
29
|
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)
|
|
30
|
+
when :datetime then to_words_datetime(number, locale, locale_data, format: date_format, only: type_only, short: type_short, date_case: date_case)
|
|
31
|
+
when :date then to_words_date(number, locale, locale_data, format: date_format, date_case: date_case)
|
|
26
32
|
when :time then to_words_time(number, locale, locale_data, short: type_short)
|
|
27
33
|
else nil
|
|
28
34
|
end
|
|
@@ -33,26 +39,60 @@ module Num2words
|
|
|
33
39
|
end
|
|
34
40
|
|
|
35
41
|
def to_currency(amount, *args, **opts)
|
|
36
|
-
locale
|
|
37
|
-
word_case
|
|
38
|
-
|
|
42
|
+
locale = args.first.is_a?(Symbol) ? args.first : opts[:locale] || I18n.default_locale
|
|
43
|
+
word_case = opts[:word_case] || :downcase
|
|
44
|
+
currency = (opts[:code] || Num2words.default_currency(locale)).to_s.upcase.to_sym
|
|
45
|
+
minor = opts[:minor] || :always
|
|
39
46
|
|
|
40
|
-
|
|
41
|
-
major_value = major_str.to_i
|
|
42
|
-
minor_value = minor_str.to_i
|
|
47
|
+
validate_option!(:minor, minor, %i[always nonzero never])
|
|
43
48
|
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
unless Num2words.available_currencies(locale).include?(currency)
|
|
50
|
+
warn I18n.t("num2words.warnings.currency_not_available",
|
|
51
|
+
currency: currency, locale: locale) if Num2words.currency_warnings
|
|
52
|
+
currency = Num2words.default_currency(locale)
|
|
53
|
+
end
|
|
46
54
|
|
|
47
|
-
|
|
48
|
-
|
|
55
|
+
currency_data = I18n.t("num2words.currencies.#{currency}", locale: locale) or
|
|
56
|
+
raise ArgumentError, "Currency #{currency} not defined in locale #{locale}"
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
|
|
58
|
+
decimal_amount = decimal_currency_amount(amount)
|
|
59
|
+
major_value, minor_value = format('%.2f', decimal_amount.abs).split('.').map(&:to_i)
|
|
60
|
+
|
|
61
|
+
parts = [
|
|
62
|
+
to_words(major_value, locale: locale),
|
|
63
|
+
pluralize(major_value, *currency_data[:major_unit])
|
|
64
|
+
]
|
|
65
|
+
|
|
66
|
+
include_minor = minor == :always || (minor == :nonzero && minor_value.positive?)
|
|
67
|
+
if include_minor
|
|
68
|
+
parts.concat([
|
|
69
|
+
to_words(minor_value, locale: locale, feminine: true),
|
|
70
|
+
pluralize(minor_value, *currency_data[:minor_unit])
|
|
71
|
+
])
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
parts.unshift(Locales[locale]::GRAMMAR[:minus] || "minus") if decimal_amount.negative?
|
|
75
|
+
|
|
76
|
+
apply_case(parts.join(" ").strip, word_case)
|
|
52
77
|
end
|
|
53
78
|
|
|
54
79
|
private
|
|
55
80
|
|
|
81
|
+
def validate_option!(name, value, allowed_values)
|
|
82
|
+
return if allowed_values.include?(value)
|
|
83
|
+
|
|
84
|
+
raise ArgumentError, "Unsupported #{name} option: #{value.inspect}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def decimal_currency_amount(amount)
|
|
88
|
+
return amount if amount.is_a?(BigDecimal)
|
|
89
|
+
|
|
90
|
+
normalized_amount = amount.is_a?(String) ? amount.tr(",", ".") : amount.to_s
|
|
91
|
+
BigDecimal(normalized_amount)
|
|
92
|
+
rescue ArgumentError
|
|
93
|
+
raise ArgumentError, "Unsupported currency amount: #{amount.inspect}"
|
|
94
|
+
end
|
|
95
|
+
|
|
56
96
|
def pluralize(number, singular, few, plural)
|
|
57
97
|
number = number.abs
|
|
58
98
|
return plural if (11..14).include?(number % 100)
|
|
@@ -85,21 +125,23 @@ module Num2words
|
|
|
85
125
|
words.compact
|
|
86
126
|
end
|
|
87
127
|
|
|
88
|
-
def to_words_fractional(number, locale, feminine, locale_data, style: :fraction)
|
|
89
|
-
minus_word
|
|
90
|
-
conjunction_word = locale_data::GRAMMAR[:conjunction] || "and"
|
|
128
|
+
def to_words_fractional(number, locale, feminine, locale_data, style: :fraction, joiner: :default)
|
|
129
|
+
minus_word = locale_data::GRAMMAR[:minus] || "minus"
|
|
130
|
+
conjunction_word = joiner.to_sym == :and ? "и" : locale_data::GRAMMAR[:conjunction] || "and"
|
|
91
131
|
default_fraction = locale_data::GRAMMAR[:default_fraction] || "parts"
|
|
92
|
-
fractions_data
|
|
132
|
+
fractions_data = locale_data::FRACTIONS || {}
|
|
93
133
|
|
|
94
|
-
|
|
134
|
+
negative = number.is_a?(String) ? number.start_with?("-") : number.negative?
|
|
135
|
+
sign_word = negative ? minus_word : ""
|
|
95
136
|
|
|
96
|
-
|
|
137
|
+
absolute_number = number.is_a?(String) ? number.sub(/\A-/, "").tr(",", ".") : number.abs.to_s
|
|
138
|
+
integer_string, fraction_string = absolute_number.split('.', 2)
|
|
97
139
|
integer_value = integer_string.to_i
|
|
98
140
|
|
|
99
141
|
return to_words_integer(integer_value, locale, feminine, locale_data) if fraction_string.to_i.zero?
|
|
100
142
|
|
|
101
143
|
fraction_string = fraction_string.sub(/0+\z/, "")
|
|
102
|
-
numerator
|
|
144
|
+
numerator = fraction_string.to_i
|
|
103
145
|
denominator = 10 ** fraction_string.length
|
|
104
146
|
|
|
105
147
|
integer_words = to_words_integer(integer_value, locale, feminine, locale_data)
|
|
@@ -121,6 +163,10 @@ module Num2words
|
|
|
121
163
|
def to_words_integer(number, locale, feminine, locale_data)
|
|
122
164
|
integer_value = Integer(number)
|
|
123
165
|
|
|
166
|
+
minus_word = locale_data::GRAMMAR[:minus] || "minus"
|
|
167
|
+
negative = integer_value.negative?
|
|
168
|
+
integer_value = integer_value.abs
|
|
169
|
+
|
|
124
170
|
return (feminine ? locale_data::ONES_FEM[0] : locale_data::ONES_MASC[0]) if integer_value.zero?
|
|
125
171
|
|
|
126
172
|
groups = integer_value.to_s
|
|
@@ -134,10 +180,11 @@ module Num2words
|
|
|
134
180
|
words.concat triple_to_words(group_value, scale_index, locale_data, feminine: group_feminine)
|
|
135
181
|
end
|
|
136
182
|
|
|
183
|
+
words.unshift(minus_word) if negative
|
|
137
184
|
words.join(" ")
|
|
138
185
|
end
|
|
139
186
|
|
|
140
|
-
def to_words_date(date, locale, locale_data, format: :default)
|
|
187
|
+
def to_words_date(date, locale, locale_data, format: :default, date_case: :default)
|
|
141
188
|
date = Date.parse(date.to_s) unless date.is_a?(Date)
|
|
142
189
|
|
|
143
190
|
day, month, year = [date.day, date.month, date.year]
|
|
@@ -150,9 +197,10 @@ module Num2words
|
|
|
150
197
|
raise ArgumentError, "Months not found for locale #{locale}" unless months
|
|
151
198
|
raise ArgumentError, "Template not found for locale #{locale}" unless template
|
|
152
199
|
|
|
153
|
-
|
|
200
|
+
day_gender = date_case.to_sym == :genitive ? :masculine : :neuter
|
|
201
|
+
day_words = to_words_ordinal(day, locale, format, locale_data, gender: day_gender)
|
|
154
202
|
month_words = months[month - 1]
|
|
155
|
-
year_words
|
|
203
|
+
year_words = to_words_ordinal(year, locale, format, locale_data)
|
|
156
204
|
|
|
157
205
|
template % { day: day_words, month: month_words, year: year_words }
|
|
158
206
|
end
|
|
@@ -164,13 +212,13 @@ module Num2words
|
|
|
164
212
|
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
165
213
|
raise ArgumentError, "Gender #{gender} not found for locale #{locale}, format #{format}" unless gender_data
|
|
166
214
|
|
|
167
|
-
return gender_data[value - 1] if gender_data
|
|
215
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
168
216
|
|
|
169
217
|
if value > 31
|
|
170
218
|
thousands = (value / 100) * 100
|
|
171
|
-
last_two
|
|
219
|
+
last_two = value % 100
|
|
172
220
|
|
|
173
|
-
base_year
|
|
221
|
+
base_year = to_words_integer(thousands, locale, false, locale_data)
|
|
174
222
|
last_ordinal = gender_data[last_two - 1] || to_words_integer(last_two, locale, false, locale_data)
|
|
175
223
|
last_ordinal = to_words_integer(last_two, locale, false, locale_data) if locale == :en
|
|
176
224
|
|
|
@@ -185,7 +233,7 @@ module Num2words
|
|
|
185
233
|
|
|
186
234
|
return time.strftime("%H:%M") if format == :short
|
|
187
235
|
|
|
188
|
-
words
|
|
236
|
+
words = locale_data::TIME[:words]
|
|
189
237
|
template = locale_data::TIME_TEMPLATE
|
|
190
238
|
|
|
191
239
|
hours = [
|
|
@@ -219,14 +267,13 @@ module Num2words
|
|
|
219
267
|
end
|
|
220
268
|
end
|
|
221
269
|
|
|
222
|
-
|
|
223
|
-
def to_words_datetime(datetime, locale, locale_data, format: :default, only: nil, short: false)
|
|
270
|
+
def to_words_datetime(datetime, locale, locale_data, format: :default, only: nil, short: false, date_case: :default)
|
|
224
271
|
datetime = DateTime.parse(datetime) if datetime.is_a?(String)
|
|
225
272
|
|
|
226
273
|
date_format = short && only == :date ? :short : format
|
|
227
274
|
time_format = short && only == :time ? :short : :default
|
|
228
275
|
|
|
229
|
-
date_part = to_words_date(datetime.to_date, locale, locale_data, format: date_format)
|
|
276
|
+
date_part = to_words_date(datetime.to_date, locale, locale_data, format: date_format, date_case: date_case)
|
|
230
277
|
time_part = to_words_time(datetime.to_time, locale, locale_data, format: time_format, short: short)
|
|
231
278
|
|
|
232
279
|
return date_part if only == :date
|
|
@@ -250,19 +297,19 @@ module Num2words
|
|
|
250
297
|
|
|
251
298
|
def detect_type(value)
|
|
252
299
|
case value
|
|
253
|
-
when Integer
|
|
254
|
-
when Float
|
|
255
|
-
when
|
|
256
|
-
when
|
|
257
|
-
when
|
|
300
|
+
when Integer then :integer
|
|
301
|
+
when Float then :float
|
|
302
|
+
when DateTime then :datetime
|
|
303
|
+
when Date then :date
|
|
304
|
+
when Time then :time
|
|
258
305
|
when String
|
|
259
306
|
return :integer if value.match?(/\A-?\d+\z/)
|
|
260
|
-
return :float
|
|
261
|
-
return :time
|
|
307
|
+
return :float if value.match?(/\A-?\d+[\.,]\d+\z/)
|
|
308
|
+
return :time if value.match?(/\A\d{1,2}:\d{2}(:\d{2})?\z/)
|
|
262
309
|
|
|
263
310
|
# Форматы даты
|
|
264
|
-
return :date
|
|
265
|
-
return :date
|
|
311
|
+
return :date if value.match?(/\A\d{1,2}[.\-]\d{1,2}[.\-]\d{2,4}\z/)
|
|
312
|
+
return :date if value.match?(/\A\d{4}-\d{2}-\d{2}\z/)
|
|
266
313
|
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
314
|
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
315
|
|
data/lib/num2words/locales/ar.rb
CHANGED
|
@@ -10,8 +10,16 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :ar)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :ar)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :ar)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :ar)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :ar)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :ar)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :ar)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :ar)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :ar)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :ar)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
register :ar, AR
|
data/lib/num2words/locales/be.rb
CHANGED
|
@@ -10,8 +10,16 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :be)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :be)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :be)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :be)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :be)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :be)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :be)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :be)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :be)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :be)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
register :be, BE
|
data/lib/num2words/locales/bg.rb
CHANGED
|
@@ -10,8 +10,16 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :bg)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :bg)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :bg)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :bg)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :bg)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :bg)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :bg)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :bg)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :bg)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :bg)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
register :bg, BG
|
data/lib/num2words/locales/bn.rb
CHANGED
|
@@ -10,8 +10,16 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :bn)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :bn)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :bn)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :bn)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :bn)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :bn)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :bn)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :bn)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :bn)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :bn)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
register :bn, BN
|
data/lib/num2words/locales/cs.rb
CHANGED
|
@@ -10,8 +10,16 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :cs)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :cs)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :cs)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :cs)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :cs)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :cs)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :cs)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :cs)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :cs)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :cs)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
register :cs, CS
|
data/lib/num2words/locales/da.rb
CHANGED
|
@@ -10,8 +10,16 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :da)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :da)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :da)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :da)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :da)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :da)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :da)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :da)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :da)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :da)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
register :da, DA
|
data/lib/num2words/locales/de.rb
CHANGED
|
@@ -10,8 +10,16 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :de)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :de)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :de)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :de)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :de)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :de)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :de)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :de)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :de)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :de)
|
|
15
23
|
end
|
|
16
24
|
|
|
17
25
|
register :de, DE
|