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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -0
  3. data/Gemfile +0 -1
  4. data/README.md +57 -16
  5. data/bin/console +2 -14
  6. data/config/locales/ar.yml +176 -17
  7. data/config/locales/be.yml +182 -15
  8. data/config/locales/bg.yml +183 -16
  9. data/config/locales/bn.yml +185 -12
  10. data/config/locales/cs.yml +180 -13
  11. data/config/locales/da.yml +182 -15
  12. data/config/locales/de.yml +181 -14
  13. data/config/locales/el.yml +183 -21
  14. data/config/locales/en.yml +129 -12
  15. data/config/locales/es.yml +180 -13
  16. data/config/locales/et.yml +185 -13
  17. data/config/locales/fa.yml +179 -12
  18. data/config/locales/fi.yml +180 -8
  19. data/config/locales/fr.yml +180 -13
  20. data/config/locales/gu.yml +182 -10
  21. data/config/locales/he.yml +182 -20
  22. data/config/locales/hi.yml +182 -15
  23. data/config/locales/hr.yml +181 -14
  24. data/config/locales/hu.yml +180 -13
  25. data/config/locales/id.yml +179 -12
  26. data/config/locales/it.yml +181 -14
  27. data/config/locales/ja.yml +188 -21
  28. data/config/locales/ru.yml +135 -9
  29. data/exe/num2words-console +7 -0
  30. data/lib/num2words/config.rb +62 -0
  31. data/lib/num2words/console.rb +16 -0
  32. data/lib/num2words/converter.rb +94 -47
  33. data/lib/num2words/locales/ar.rb +10 -2
  34. data/lib/num2words/locales/be.rb +10 -2
  35. data/lib/num2words/locales/bg.rb +10 -2
  36. data/lib/num2words/locales/bn.rb +10 -2
  37. data/lib/num2words/locales/cs.rb +10 -2
  38. data/lib/num2words/locales/da.rb +10 -2
  39. data/lib/num2words/locales/de.rb +10 -2
  40. data/lib/num2words/locales/el.rb +10 -2
  41. data/lib/num2words/locales/en.rb +0 -3
  42. data/lib/num2words/locales/es.rb +10 -2
  43. data/lib/num2words/locales/et.rb +10 -2
  44. data/lib/num2words/locales/fa.rb +10 -2
  45. data/lib/num2words/locales/fi.rb +10 -2
  46. data/lib/num2words/locales/fr.rb +10 -2
  47. data/lib/num2words/locales/gu.rb +10 -2
  48. data/lib/num2words/locales/he.rb +10 -2
  49. data/lib/num2words/locales/hi.rb +10 -2
  50. data/lib/num2words/locales/hr.rb +10 -2
  51. data/lib/num2words/locales/hu.rb +10 -2
  52. data/lib/num2words/locales/id.rb +10 -2
  53. data/lib/num2words/locales/it.rb +10 -2
  54. data/lib/num2words/locales/ja.rb +10 -2
  55. data/lib/num2words/locales/ru.rb +0 -3
  56. data/lib/num2words/version.rb +1 -1
  57. data/lib/num2words.rb +1 -0
  58. data/num2words.gemspec +1 -1
  59. metadata +9 -5
@@ -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,7 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require "num2words"
5
+ require "num2words/console"
6
+
7
+ Num2words::Console.start
@@ -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
@@ -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 = 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
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 = opts[:feminine] || false
15
- style = opts[:style] || :fraction
16
- word_case = opts[:word_case] || :default
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 = args.first.is_a?(Symbol) ? args.first : opts[:locale] || I18n.default_locale
37
- word_case = opts[:word_case] || :downcase
38
- locale_data = Locales[locale]
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
- major_str, minor_str = sprintf('%.2f', amount).split('.')
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
- major_words = to_words(major_value, locale: locale)
45
- major_name = pluralize(major_value, *locale_data::MAJOR_UNIT)
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
- minor_words = to_words(minor_value, locale: locale, feminine: true)
48
- minor_name = pluralize(minor_value, *locale_data::MINOR_UNIT)
55
+ currency_data = I18n.t("num2words.currencies.#{currency}", locale: locale) or
56
+ raise ArgumentError, "Currency #{currency} not defined in locale #{locale}"
49
57
 
50
- result = [major_words, major_name, minor_words, minor_name].join(" ")
51
- apply_case(result, word_case)
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 = locale_data::GRAMMAR[:minus] || "minus"
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 = locale_data::FRACTIONS || {}
132
+ fractions_data = locale_data::FRACTIONS || {}
93
133
 
94
- sign_word = number.negative? ? minus_word : ""
134
+ negative = number.is_a?(String) ? number.start_with?("-") : number.negative?
135
+ sign_word = negative ? minus_word : ""
95
136
 
96
- integer_string, fraction_string = number.abs.to_s.split('.', 2)
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 = fraction_string.to_i
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
- day_words = to_words_ordinal(day, locale, format, locale_data, gender: :neuter)
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 = to_words_ordinal(year, locale, format, locale_data)
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[value]
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 = value % 100
219
+ last_two = value % 100
172
220
 
173
- base_year = to_words_integer(thousands, locale, false, locale_data)
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 = locale_data::TIME[: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 then :integer
254
- when Float then :float
255
- when Date then :date
256
- when Time then :time
257
- when DateTime then :datetime
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 if value.match?(/\A-?\d+\.\d+\z/)
261
- return :time if value.match?(/\A\d{1,2}:\d{2}(:\d{2})?\z/)
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 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/)
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
 
@@ -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
- MAJOR_UNIT = I18n.t("num2words.currencies.SAR.name", locale: :ar)
14
- MINOR_UNIT = I18n.t("num2words.currencies.SAR.fractional.name", locale: :ar)
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
@@ -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
- MAJOR_UNIT = I18n.t("num2words.currencies.BYN.name", locale: :be)
14
- MINOR_UNIT = I18n.t("num2words.currencies.BYN.fractional.name", locale: :be)
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
@@ -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
- MAJOR_UNIT = I18n.t("num2words.currencies.BGN.name", locale: :bg)
14
- MINOR_UNIT = I18n.t("num2words.currencies.BGN.fractional.name", locale: :bg)
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
@@ -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
- MAJOR_UNIT = I18n.t("num2words.currencies.BDT.name", locale: :bn)
14
- MINOR_UNIT = I18n.t("num2words.currencies.BDT.fractional.name", locale: :bn)
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
@@ -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
- MAJOR_UNIT = I18n.t("num2words.currencies.CZK.name", locale: :cs)
14
- MINOR_UNIT = I18n.t("num2words.currencies.CZK.fractional.name", locale: :cs)
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
@@ -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
- MAJOR_UNIT = I18n.t("num2words.currencies.DKK.name", locale: :da)
14
- MINOR_UNIT = I18n.t("num2words.currencies.DKK.fractional.name", locale: :da)
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
@@ -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
- MAJOR_UNIT = I18n.t("num2words.currencies.EUR.name", locale: :de)
14
- MINOR_UNIT = I18n.t("num2words.currencies.EUR.fractional.name", locale: :de)
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