num2words 0.2.0 → 0.3.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 +22 -0
- data/README.md +113 -144
- data/config/locales/ar.yml +5 -1
- data/config/locales/be.yml +4 -0
- data/config/locales/bg.yml +4 -0
- data/config/locales/bn.yml +4 -0
- data/config/locales/cs.yml +6 -2
- data/config/locales/da.yml +4 -0
- data/config/locales/de.yml +8 -4
- data/config/locales/el.yml +4 -0
- data/config/locales/en.yml +4 -0
- data/config/locales/es.yml +4 -0
- data/config/locales/et.yml +9 -5
- data/config/locales/fa.yml +15 -11
- data/config/locales/fi.yml +8 -4
- data/config/locales/fr.yml +4 -0
- data/config/locales/gu.yml +4 -0
- data/config/locales/he.yml +6 -2
- data/config/locales/hi.yml +4 -0
- data/config/locales/hr.yml +8 -4
- data/config/locales/hu.yml +6 -2
- data/config/locales/id.yml +4 -0
- data/config/locales/it.yml +4 -0
- data/config/locales/ja.yml +10 -5
- data/config/locales/kn.yml +186 -10
- data/config/locales/ko.yml +184 -13
- data/config/locales/kz.yml +183 -17
- data/config/locales/lt.yml +184 -8
- data/config/locales/lv.yml +188 -12
- data/config/locales/ml.yml +189 -13
- data/config/locales/mr.yml +184 -8
- data/config/locales/ms.yml +184 -8
- data/config/locales/nb.yml +183 -17
- data/config/locales/nl.yml +184 -13
- data/config/locales/pa.yml +189 -13
- data/config/locales/pl.yml +184 -13
- data/config/locales/pt.yml +184 -13
- data/config/locales/ro.yml +183 -12
- data/config/locales/ru.yml +4 -0
- data/config/locales/sk.yml +184 -8
- data/config/locales/sl.yml +185 -9
- data/config/locales/sr.yml +186 -15
- data/config/locales/sv.yml +182 -13
- data/config/locales/sw.yml +184 -8
- data/config/locales/ta.yml +184 -8
- data/config/locales/te.yml +185 -9
- data/config/locales/th.yml +183 -12
- data/config/locales/tr.yml +183 -12
- data/config/locales/uk.yml +189 -18
- data/config/locales/ur.yml +187 -11
- data/config/locales/vi.yml +183 -12
- data/config/locales/zh.yml +191 -9
- data/lib/num2words/converter.rb +144 -35
- data/lib/num2words/locales/ar.rb +130 -0
- data/lib/num2words/locales/be.rb +101 -0
- data/lib/num2words/locales/bg.rb +127 -0
- data/lib/num2words/locales/bn.rb +112 -0
- data/lib/num2words/locales/cs.rb +106 -0
- data/lib/num2words/locales/da.rb +97 -0
- data/lib/num2words/locales/de.rb +119 -0
- data/lib/num2words/locales/el.rb +143 -0
- data/lib/num2words/locales/en.rb +90 -0
- data/lib/num2words/locales/es.rb +185 -0
- data/lib/num2words/locales/et.rb +104 -0
- data/lib/num2words/locales/fa.rb +104 -0
- data/lib/num2words/locales/fi.rb +104 -0
- data/lib/num2words/locales/fr.rb +121 -0
- data/lib/num2words/locales/gu.rb +112 -0
- data/lib/num2words/locales/he.rb +130 -0
- data/lib/num2words/locales/hi.rb +112 -0
- data/lib/num2words/locales/hr.rb +117 -0
- data/lib/num2words/locales/hu.rb +111 -0
- data/lib/num2words/locales/id.rb +104 -0
- data/lib/num2words/locales/it.rb +142 -0
- data/lib/num2words/locales/ja.rb +126 -0
- data/lib/num2words/locales/kn.rb +122 -2
- data/lib/num2words/locales/ko.rb +158 -2
- data/lib/num2words/locales/kz.rb +137 -2
- data/lib/num2words/locales/lt.rb +146 -2
- data/lib/num2words/locales/lv.rb +148 -2
- data/lib/num2words/locales/ml.rb +142 -2
- data/lib/num2words/locales/mr.rb +142 -2
- data/lib/num2words/locales/ms.rb +134 -2
- data/lib/num2words/locales/nb.rb +153 -0
- data/lib/num2words/locales/nl.rb +142 -2
- data/lib/num2words/locales/pa.rb +122 -2
- data/lib/num2words/locales/pl.rb +149 -2
- data/lib/num2words/locales/pt.rb +164 -2
- data/lib/num2words/locales/ro.rb +165 -2
- data/lib/num2words/locales/ru.rb +100 -0
- data/lib/num2words/locales/sk.rb +124 -2
- data/lib/num2words/locales/sl.rb +154 -2
- data/lib/num2words/locales/sr.rb +141 -3
- data/lib/num2words/locales/sv.rb +141 -2
- data/lib/num2words/locales/sw.rb +133 -2
- data/lib/num2words/locales/ta.rb +142 -2
- data/lib/num2words/locales/te.rb +142 -2
- data/lib/num2words/locales/th.rb +133 -2
- data/lib/num2words/locales/tr.rb +141 -2
- data/lib/num2words/locales/uk.rb +134 -2
- data/lib/num2words/locales/ur.rb +130 -2
- data/lib/num2words/locales/vi.rb +142 -2
- data/lib/num2words/locales/zh.rb +172 -2
- data/lib/num2words/version.rb +1 -1
- data/num2words.gemspec +2 -2
- metadata +6 -6
- data/lib/num2words/locales/no.rb +0 -19
data/lib/num2words/locales/bn.rb
CHANGED
|
@@ -20,6 +20,118 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :bn)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :bn)
|
|
23
|
+
|
|
24
|
+
UNDER_HUNDRED = [
|
|
25
|
+
"শূন্য", "এক", "দুই", "তিন", "চার", "পাঁচ", "ছয়", "সাত", "আট", "নয়",
|
|
26
|
+
"দশ", "এগারো", "বারো", "তেরো", "চৌদ্দ", "পনেরো", "ষোল", "সতেরো", "আঠারো", "উনিশ",
|
|
27
|
+
"বিশ", "একুশ", "বাইশ", "তেইশ", "চব্বিশ", "পঁচিশ", "ছাব্বিশ", "সাতাশ", "আটাশ", "ঊনত্রিশ",
|
|
28
|
+
"ত্রিশ", "একত্রিশ", "বত্রিশ", "তেত্রিশ", "চৌত্রিশ", "পঁয়ত্রিশ", "ছত্রিশ", "সাঁইত্রিশ", "আটত্রিশ", "ঊনচল্লিশ",
|
|
29
|
+
"চল্লিশ", "একচল্লিশ", "বিয়াল্লিশ", "তেতাল্লিশ", "চুয়াল্লিশ", "পঁয়তাল্লিশ", "ছেচল্লিশ", "সাতচল্লিশ", "আটচল্লিশ", "ঊনপঞ্চাশ",
|
|
30
|
+
"পঞ্চাশ", "একান্ন", "বায়ান্ন", "তিপ্পান্ন", "চুয়ান্ন", "পঞ্চান্ন", "ছাপ্পান্ন", "সাতান্ন", "আটান্ন", "ঊনষাট",
|
|
31
|
+
"ষাট", "একষট্টি", "বাষট্টি", "তেষট্টি", "চৌষট্টি", "পঁয়ষট্টি", "ছেষট্টি", "সাতষট্টি", "আটষট্টি", "ঊনসত্তর",
|
|
32
|
+
"সত্তর", "একাত্তর", "বাহাত্তর", "তিয়াত্তর", "চুয়াত্তর", "পঁচাত্তর", "ছিয়াত্তর", "সাতাত্তর", "আটাত্তর", "ঊনআশি",
|
|
33
|
+
"আশি", "একাশি", "বিরাশি", "তিরাশি", "চুরাশি", "পঁচাশি", "ছিয়াশি", "সাতাশি", "আটাশি", "ঊননব্বই",
|
|
34
|
+
"নব্বই", "একানব্বই", "বিরানব্বই", "তিরানব্বই", "চুরানব্বই", "পঁচানব্বই", "ছিয়ানব্বই", "সাতানব্বই", "আটানব্বই", "নিরানব্বই"
|
|
35
|
+
].freeze
|
|
36
|
+
|
|
37
|
+
INDIAN_SCALES = [
|
|
38
|
+
[1_000_000_000, "অরব"],
|
|
39
|
+
[10_000_000, "কোটি"],
|
|
40
|
+
[100_000, "লক্ষ"],
|
|
41
|
+
[1_000, "হাজার"]
|
|
42
|
+
].freeze
|
|
43
|
+
|
|
44
|
+
module_function
|
|
45
|
+
|
|
46
|
+
def integer_to_words(number, feminine: false)
|
|
47
|
+
cardinal(number)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
51
|
+
return [] if number.zero?
|
|
52
|
+
|
|
53
|
+
words = [under_thousand(number)]
|
|
54
|
+
words << SCALES[scale_idx][0] unless scale_idx.zero?
|
|
55
|
+
words
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def minus_word
|
|
59
|
+
GRAMMAR[:minus]
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def fraction_joiner(joiner)
|
|
63
|
+
joiner.to_sym == :and ? "এবং" : GRAMMAR[:conjunction]
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def default_fraction_word
|
|
67
|
+
GRAMMAR[:default_fraction]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def fraction_numerator_feminine?
|
|
71
|
+
false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def decimal_separator_word
|
|
75
|
+
GRAMMAR[:conjunction]
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def decimal_fraction_words(fraction_string)
|
|
79
|
+
fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def date_day(day, format:, date_case:)
|
|
83
|
+
ordinal(day, :nominative, gender: :neuter)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def date_year(year, format:)
|
|
87
|
+
cardinal(year)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def ordinal(value, format, gender: :masculine)
|
|
91
|
+
ordinals = ORDINALS[format] || ORDINALS[:nominative]
|
|
92
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
93
|
+
|
|
94
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
95
|
+
|
|
96
|
+
cardinal(value)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def cardinal(number)
|
|
100
|
+
integer_value = Integer(number)
|
|
101
|
+
negative = integer_value.negative?
|
|
102
|
+
integer_value = integer_value.abs
|
|
103
|
+
|
|
104
|
+
return UNDER_HUNDRED[0] if integer_value.zero?
|
|
105
|
+
|
|
106
|
+
remainder = integer_value
|
|
107
|
+
words = []
|
|
108
|
+
|
|
109
|
+
INDIAN_SCALES.each do |value, label|
|
|
110
|
+
next if remainder < value
|
|
111
|
+
|
|
112
|
+
group_value = remainder / value
|
|
113
|
+
remainder %= value
|
|
114
|
+
words << [cardinal(group_value), label].join(" ")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
words << under_thousand(remainder) if remainder.positive?
|
|
118
|
+
words.unshift(minus_word) if negative
|
|
119
|
+
words.join(" ")
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def under_thousand(number)
|
|
123
|
+
return UNDER_HUNDRED[number] if number < 100
|
|
124
|
+
|
|
125
|
+
hundreds = number / 100
|
|
126
|
+
rest = number % 100
|
|
127
|
+
words = ["#{UNDER_HUNDRED[hundreds]}শ"]
|
|
128
|
+
words << UNDER_HUNDRED[rest] if rest.positive?
|
|
129
|
+
words.join(" ")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def pluralize(_number, singular, _few, _plural)
|
|
133
|
+
singular
|
|
134
|
+
end
|
|
23
135
|
end
|
|
24
136
|
|
|
25
137
|
register :bn, BN
|
data/lib/num2words/locales/cs.rb
CHANGED
|
@@ -20,6 +20,112 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :cs)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :cs)
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def fraction_numerator_feminine?
|
|
27
|
+
true
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def feminine_group?(scale_idx)
|
|
31
|
+
scale_idx == 3
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def currency_major_feminine?(currency)
|
|
35
|
+
%i[CZK GBP UAH].include?(currency)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def currency_minor_feminine?(currency)
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def minus_word
|
|
43
|
+
GRAMMAR[:minus]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def fraction_joiner(joiner)
|
|
47
|
+
joiner.to_sym == :and ? "a" : GRAMMAR[:conjunction]
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def default_fraction_word
|
|
51
|
+
GRAMMAR[:default_fraction]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def integer_to_words(number, feminine: false)
|
|
55
|
+
cardinal(number, feminine: feminine)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
59
|
+
return [] if number.zero?
|
|
60
|
+
|
|
61
|
+
words = []
|
|
62
|
+
words << HUNDREDS[number / 100] if number >= 100
|
|
63
|
+
rest = number % 100
|
|
64
|
+
|
|
65
|
+
if rest.between?(10, 19)
|
|
66
|
+
words << TEENS[rest - 10]
|
|
67
|
+
else
|
|
68
|
+
words << TENS[rest / 10] if rest >= 20
|
|
69
|
+
ones = rest % 10
|
|
70
|
+
words << (feminine ? ONES_FEM[ones] : ONES_MASC[ones]) if ones.positive?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
|
|
74
|
+
words.compact
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def date_day(day, format:, date_case:)
|
|
78
|
+
ordinal(day, :default)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def date_year(year, format:)
|
|
82
|
+
cardinal(year)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def ordinal(value, format, gender: :masculine)
|
|
86
|
+
ordinals = ORDINALS[format]
|
|
87
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
88
|
+
|
|
89
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
90
|
+
|
|
91
|
+
cardinal(value)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def cardinal(number, feminine: false)
|
|
95
|
+
integer_value = Integer(number)
|
|
96
|
+
negative = integer_value.negative?
|
|
97
|
+
integer_value = integer_value.abs
|
|
98
|
+
|
|
99
|
+
return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
|
|
100
|
+
|
|
101
|
+
groups = integer_value.to_s
|
|
102
|
+
.chars.reverse.each_slice(3).map(&:reverse)
|
|
103
|
+
.map(&:join).map!(&:to_i).reverse
|
|
104
|
+
|
|
105
|
+
words = []
|
|
106
|
+
groups.each_with_index do |group_value, index|
|
|
107
|
+
next if group_value.zero?
|
|
108
|
+
|
|
109
|
+
scale_idx = groups.size - index - 1
|
|
110
|
+
group_words = triple_to_words(group_value, scale_idx, feminine: feminine_group?(scale_idx) || (feminine && scale_idx.zero?))
|
|
111
|
+
group_words.shift if scale_idx == 1 && group_value == 1
|
|
112
|
+
words.concat group_words
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
words.unshift(minus_word) if negative
|
|
116
|
+
words.join(" ")
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def pluralize(number, singular, few, plural)
|
|
120
|
+
number = number.abs
|
|
121
|
+
return plural if (11..14).include?(number % 100)
|
|
122
|
+
|
|
123
|
+
case number % 10
|
|
124
|
+
when 1 then singular
|
|
125
|
+
when 2..4 then few
|
|
126
|
+
else plural
|
|
127
|
+
end
|
|
128
|
+
end
|
|
23
129
|
end
|
|
24
130
|
|
|
25
131
|
register :cs, CS
|
data/lib/num2words/locales/da.rb
CHANGED
|
@@ -20,6 +20,103 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :da)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :da)
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def minus_word
|
|
27
|
+
GRAMMAR[:minus]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def fraction_joiner(joiner)
|
|
31
|
+
joiner.to_sym == :and ? "og" : GRAMMAR[:conjunction]
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def default_fraction_word
|
|
35
|
+
GRAMMAR[:default_fraction]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def fraction_numerator_feminine?
|
|
39
|
+
false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def integer_to_words(number, feminine: false)
|
|
43
|
+
cardinal(number, feminine: feminine)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def date_day(day, format:, date_case:)
|
|
47
|
+
ordinal(day, :nominative)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
51
|
+
triple_words(number, feminine: feminine).tap do |words|
|
|
52
|
+
words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def date_year(year, format:)
|
|
57
|
+
cardinal(year)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def ordinal(value, format, gender: :masculine)
|
|
61
|
+
ordinals = ORDINALS[format] || ORDINALS[:nominative]
|
|
62
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
63
|
+
|
|
64
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
65
|
+
|
|
66
|
+
cardinal(value)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def pluralize(number, singular, few, plural)
|
|
70
|
+
number.abs == 1 ? singular : plural
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def cardinal(number, feminine: false)
|
|
74
|
+
integer_value = Integer(number)
|
|
75
|
+
negative = integer_value.negative?
|
|
76
|
+
integer_value = integer_value.abs
|
|
77
|
+
|
|
78
|
+
return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
|
|
79
|
+
|
|
80
|
+
groups = integer_value.to_s
|
|
81
|
+
.chars.reverse.each_slice(3).map(&:reverse)
|
|
82
|
+
.map(&:join).map!(&:to_i).reverse
|
|
83
|
+
|
|
84
|
+
words = []
|
|
85
|
+
groups.each_with_index do |group_value, index|
|
|
86
|
+
next if group_value.zero?
|
|
87
|
+
|
|
88
|
+
scale_idx = groups.size - index - 1
|
|
89
|
+
group_words = triple_to_words(group_value, scale_idx, feminine: feminine && scale_idx.zero?)
|
|
90
|
+
group_words[0] = "et" if scale_idx == 1 && group_value == 1
|
|
91
|
+
group_words.unshift("og") if scale_idx.zero? && words.any? && group_value < 100
|
|
92
|
+
words.concat(group_words)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
words.unshift(minus_word) if negative
|
|
96
|
+
words.join(" ")
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def triple_words(number, feminine: false)
|
|
100
|
+
return [] if number.zero?
|
|
101
|
+
|
|
102
|
+
words = []
|
|
103
|
+
hundreds = number / 100
|
|
104
|
+
rest = number % 100
|
|
105
|
+
|
|
106
|
+
words << HUNDREDS[hundreds] if hundreds.positive?
|
|
107
|
+
words << "og" if hundreds.positive? && rest.positive?
|
|
108
|
+
words << under_hundred(rest, feminine: feminine) if rest.positive?
|
|
109
|
+
words.compact
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def under_hundred(number, feminine: false)
|
|
113
|
+
return TEENS[number - 10] if number.between?(10, 19)
|
|
114
|
+
return TENS[number / 10] if (number % 10).zero?
|
|
115
|
+
return (feminine ? ONES_FEM[number] : ONES_MASC[number]) if number < 10
|
|
116
|
+
|
|
117
|
+
ones = feminine ? ONES_FEM[number % 10] : ONES_MASC[number % 10]
|
|
118
|
+
"#{ones}og#{TENS[number / 10]}"
|
|
119
|
+
end
|
|
23
120
|
end
|
|
24
121
|
|
|
25
122
|
register :da, DA
|
data/lib/num2words/locales/de.rb
CHANGED
|
@@ -20,6 +20,125 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :de)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :de)
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def feminine_group?(scale_idx)
|
|
27
|
+
scale_idx >= 2
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def fraction_numerator_feminine?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def minus_word
|
|
35
|
+
GRAMMAR[:minus]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def fraction_joiner(joiner)
|
|
39
|
+
joiner.to_sym == :and ? "und" : GRAMMAR[:conjunction]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def default_fraction_word
|
|
43
|
+
GRAMMAR[:default_fraction]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def integer_to_words(number, feminine: false)
|
|
47
|
+
cardinal(number, feminine: feminine)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def currency_major_feminine?(currency)
|
|
51
|
+
%i[UAH CZK SEK NOK DKK INR IDR PKR].include?(currency)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def currency_minor_feminine?(currency)
|
|
55
|
+
false
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def currency_number_words(number, currency, unit:)
|
|
59
|
+
return cardinal(number, feminine: currency_major_feminine?(currency)) unless Integer(number) == 1
|
|
60
|
+
|
|
61
|
+
unit == :major && currency_major_feminine?(currency) ? "eine" : "ein"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
65
|
+
return [] if number.zero?
|
|
66
|
+
|
|
67
|
+
words = [under_thousand(number, feminine: feminine)]
|
|
68
|
+
words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
|
|
69
|
+
words
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def date_day(day, format:, date_case:)
|
|
73
|
+
ordinal(day, :default)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def date_year(year, format:)
|
|
77
|
+
cardinal(year).delete(" ")
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def ordinal(value, format, gender: :masculine)
|
|
81
|
+
ordinals = ORDINALS[format] || ORDINALS[:nominative]
|
|
82
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
83
|
+
|
|
84
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
85
|
+
|
|
86
|
+
cardinal(value)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def cardinal(number, feminine: false)
|
|
90
|
+
integer_value = Integer(number)
|
|
91
|
+
negative = integer_value.negative?
|
|
92
|
+
integer_value = integer_value.abs
|
|
93
|
+
|
|
94
|
+
return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
|
|
95
|
+
|
|
96
|
+
groups = integer_value.to_s
|
|
97
|
+
.chars.reverse.each_slice(3).map(&:reverse)
|
|
98
|
+
.map(&:join).map!(&:to_i).reverse
|
|
99
|
+
|
|
100
|
+
words = []
|
|
101
|
+
groups.each_with_index do |group_value, index|
|
|
102
|
+
next if group_value.zero?
|
|
103
|
+
|
|
104
|
+
scale_idx = groups.size - index - 1
|
|
105
|
+
group_feminine = feminine_group?(scale_idx) || (feminine && scale_idx.zero?)
|
|
106
|
+
group_words = triple_to_words(group_value, scale_idx, feminine: group_feminine)
|
|
107
|
+
group_words.shift if scale_idx == 1 && group_value == 1
|
|
108
|
+
words.concat(group_words)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
words.unshift(minus_word) if negative
|
|
112
|
+
words.join(" ")
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def under_thousand(number, feminine: false)
|
|
116
|
+
return under_hundred(number, feminine: feminine) if number < 100
|
|
117
|
+
|
|
118
|
+
hundreds = number / 100
|
|
119
|
+
rest = number % 100
|
|
120
|
+
hundred_words = hundreds == 1 ? "einhundert" : "#{under_hundred(hundreds)}hundert"
|
|
121
|
+
|
|
122
|
+
return hundred_words if rest.zero?
|
|
123
|
+
|
|
124
|
+
"#{hundred_words}#{under_hundred(rest, feminine: feminine)}"
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def under_hundred(number, feminine: false)
|
|
128
|
+
return feminine ? ONES_FEM[number] : ONES_MASC[number] if number < 10
|
|
129
|
+
return TEENS[number - 10] if number < 20
|
|
130
|
+
return TENS[number / 10] if (number % 10).zero?
|
|
131
|
+
|
|
132
|
+
ones = number % 10
|
|
133
|
+
tens = number / 10
|
|
134
|
+
ones_word = ones == 1 ? "ein" : ONES_MASC[ones]
|
|
135
|
+
|
|
136
|
+
"#{ones_word}und#{TENS[tens]}"
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def pluralize(number, singular, few, plural)
|
|
140
|
+
number.abs == 1 ? singular : plural
|
|
141
|
+
end
|
|
23
142
|
end
|
|
24
143
|
|
|
25
144
|
register :de, DE
|
data/lib/num2words/locales/el.rb
CHANGED
|
@@ -20,6 +20,149 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :el)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :el)
|
|
23
|
+
|
|
24
|
+
ONES_NEUT = ["μηδέν", "ένα", "δύο", "τρία", "τέσσερα", "πέντε", "έξι", "επτά", "οκτώ", "εννέα"].freeze
|
|
25
|
+
TEENS_MASC = ["δέκα", "έντεκα", "δώδεκα", "δεκατρείς", "δεκατέσσερις", "δεκαπέντε", "δεκαέξι", "δεκαεπτά", "δεκαοκτώ", "δεκαεννέα"].freeze
|
|
26
|
+
TEENS_FEM = TEENS_MASC
|
|
27
|
+
TEENS_NEUT = TEENS
|
|
28
|
+
FEMININE_MAJOR_CURRENCIES = %i[GBP TRY UAH CZK SEK NOK DKK INR IDR PKR].freeze
|
|
29
|
+
NEUTER_MAJOR_CURRENCIES = %i[EUR USD RUB KRW PLN RON BGN BYN KZT ILS HUF SAR THB VND IRR RSD MYR BDT KES BRL CNY JPY].freeze
|
|
30
|
+
NEUTER_MINOR_CURRENCIES = %i[EUR USD GBP JPY CNY RUB KRW TRY PLN UAH CZK RON BGN BYN KZT SEK NOK DKK HUF THB VND IDR IRR MYR KES BRL].freeze
|
|
31
|
+
|
|
32
|
+
module_function
|
|
33
|
+
|
|
34
|
+
def integer_to_words(number, feminine: false)
|
|
35
|
+
cardinal(number, gender: feminine ? :feminine : :masculine)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
39
|
+
gender = feminine ? :feminine : :masculine
|
|
40
|
+
gender = :feminine if scale_idx == 1
|
|
41
|
+
gender = :neuter if scale_idx > 1
|
|
42
|
+
triple_words(number, scale_idx, gender: gender)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def minus_word
|
|
46
|
+
GRAMMAR[:minus]
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def fraction_joiner(joiner)
|
|
50
|
+
joiner.to_sym == :and ? "και" : GRAMMAR[:conjunction]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def default_fraction_word
|
|
54
|
+
GRAMMAR[:default_fraction]
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def fraction_numerator_feminine?
|
|
58
|
+
false
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def time_unit_feminine?(unit)
|
|
62
|
+
unit == :hour
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def currency_number_words(number, currency, unit:)
|
|
66
|
+
gender = unit == :major ? currency_major_gender(currency) : currency_minor_gender(currency)
|
|
67
|
+
cardinal(number, gender: gender)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def date_day(day, format:, date_case:)
|
|
71
|
+
ordinal(day, :default)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def date_year(year, format:)
|
|
75
|
+
cardinal(year, gender: :neuter)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def ordinal(value, format, gender: :masculine)
|
|
79
|
+
ordinals = ORDINALS[format] || ORDINALS[:nominative]
|
|
80
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
81
|
+
|
|
82
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
83
|
+
|
|
84
|
+
cardinal(value)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def cardinal(number, gender: :masculine)
|
|
88
|
+
integer_value = Integer(number)
|
|
89
|
+
negative = integer_value.negative?
|
|
90
|
+
integer_value = integer_value.abs
|
|
91
|
+
|
|
92
|
+
return ones(gender)[0] if integer_value.zero?
|
|
93
|
+
|
|
94
|
+
groups = integer_value.to_s
|
|
95
|
+
.chars.reverse.each_slice(3).map(&:reverse)
|
|
96
|
+
.map(&:join).map!(&:to_i).reverse
|
|
97
|
+
|
|
98
|
+
words = []
|
|
99
|
+
groups.each_with_index do |group_value, index|
|
|
100
|
+
next if group_value.zero?
|
|
101
|
+
|
|
102
|
+
scale_idx = groups.size - index - 1
|
|
103
|
+
group_gender = scale_idx.zero? ? gender : scale_gender(scale_idx)
|
|
104
|
+
group_words = triple_words(group_value, scale_idx, gender: group_gender)
|
|
105
|
+
group_words.shift if scale_idx == 1 && group_value == 1
|
|
106
|
+
words.concat group_words
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
words.unshift(minus_word) if negative
|
|
110
|
+
words.join(" ")
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def triple_words(number, scale_idx, gender:)
|
|
114
|
+
return [] if number.zero?
|
|
115
|
+
|
|
116
|
+
words = []
|
|
117
|
+
words << HUNDREDS[number / 100] if number >= 100
|
|
118
|
+
rest = number % 100
|
|
119
|
+
|
|
120
|
+
if rest.between?(10, 19)
|
|
121
|
+
words << teens(gender)[rest - 10]
|
|
122
|
+
else
|
|
123
|
+
words << TENS[rest / 10] if rest >= 20
|
|
124
|
+
value = rest % 10
|
|
125
|
+
words << ones(gender)[value] if value.positive?
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
|
|
129
|
+
words.compact
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def scale_gender(scale_idx)
|
|
133
|
+
scale_idx == 1 ? :feminine : :neuter
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def ones(gender)
|
|
137
|
+
case gender
|
|
138
|
+
when :feminine then ONES_FEM
|
|
139
|
+
when :neuter then ONES_NEUT
|
|
140
|
+
else ONES_MASC
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def teens(gender)
|
|
145
|
+
case gender
|
|
146
|
+
when :feminine then TEENS_FEM
|
|
147
|
+
when :neuter then TEENS_NEUT
|
|
148
|
+
else TEENS_MASC
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def currency_major_gender(currency)
|
|
153
|
+
return :feminine if FEMININE_MAJOR_CURRENCIES.include?(currency)
|
|
154
|
+
return :neuter if NEUTER_MAJOR_CURRENCIES.include?(currency)
|
|
155
|
+
|
|
156
|
+
:masculine
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
def currency_minor_gender(currency)
|
|
160
|
+
NEUTER_MINOR_CURRENCIES.include?(currency) ? :neuter : :feminine
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def pluralize(number, singular, few, plural)
|
|
164
|
+
number.abs == 1 ? singular : few
|
|
165
|
+
end
|
|
23
166
|
end
|
|
24
167
|
|
|
25
168
|
register :el, EL
|
data/lib/num2words/locales/en.rb
CHANGED
|
@@ -20,6 +20,96 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :en)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :en)
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def feminine_group?(_scale_idx)
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def fraction_numerator_feminine?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def minus_word
|
|
35
|
+
GRAMMAR[:minus]
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def fraction_joiner(_joiner)
|
|
39
|
+
GRAMMAR[:conjunction]
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def default_fraction_word
|
|
43
|
+
GRAMMAR[:default_fraction]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def decimal_separator_word
|
|
47
|
+
"point"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def decimal_fraction_words(fraction_string)
|
|
51
|
+
fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
55
|
+
words = []
|
|
56
|
+
|
|
57
|
+
words << HUNDREDS[number / 100] if number >= 100
|
|
58
|
+
rest = number % 100
|
|
59
|
+
|
|
60
|
+
if rest.between?(10, 19)
|
|
61
|
+
words << TEENS[rest - 10]
|
|
62
|
+
else
|
|
63
|
+
words << TENS[rest / 10] if rest >= 20
|
|
64
|
+
ones = rest % 10
|
|
65
|
+
words << (feminine ? ONES_FEM[ones] : ONES_MASC[ones]) if ones.positive?
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
|
|
69
|
+
words.compact
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def date_day(day, format:, date_case:)
|
|
73
|
+
ordinal(day, format)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def date_year(year, format:)
|
|
77
|
+
cardinal(year)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def ordinal(value, format, gender: :masculine)
|
|
81
|
+
ordinals = ORDINALS[format]
|
|
82
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
83
|
+
|
|
84
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
85
|
+
|
|
86
|
+
cardinal(value)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def cardinal(number, feminine: false)
|
|
90
|
+
integer_value = Integer(number)
|
|
91
|
+
negative = integer_value.negative?
|
|
92
|
+
integer_value = integer_value.abs
|
|
93
|
+
|
|
94
|
+
return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
|
|
95
|
+
|
|
96
|
+
groups = integer_value.to_s
|
|
97
|
+
.chars.reverse.each_slice(3).map(&:reverse)
|
|
98
|
+
.map(&:join).map!(&:to_i).reverse
|
|
99
|
+
|
|
100
|
+
words = []
|
|
101
|
+
groups.each_with_index do |group_value, index|
|
|
102
|
+
scale_idx = groups.size - index - 1
|
|
103
|
+
words.concat triple_to_words(group_value, scale_idx, feminine: feminine)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
words.unshift(minus_word) if negative
|
|
107
|
+
words.join(" ")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def pluralize(number, singular, few, plural)
|
|
111
|
+
number.abs == 1 ? singular : plural
|
|
112
|
+
end
|
|
23
113
|
end
|
|
24
114
|
|
|
25
115
|
register :en, EN
|