num2words 0.1.6 → 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 +65 -0
- data/README.md +145 -135
- data/bin/console +2 -14
- 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 +8 -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/exe/num2words-console +7 -0
- data/lib/num2words/console.rb +16 -0
- data/lib/num2words/converter.rb +195 -47
- 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 +3 -3
- metadata +13 -10
- data/lib/num2words/locales/no.rb +0 -19
data/lib/num2words/locales/fi.rb
CHANGED
|
@@ -20,6 +20,110 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :fi)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :fi)
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def integer_to_words(number, feminine: false)
|
|
27
|
+
cardinal(number)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
31
|
+
return [] if number.zero?
|
|
32
|
+
|
|
33
|
+
words = []
|
|
34
|
+
words << under_thousand(number) unless scale_idx == 1 && number == 1
|
|
35
|
+
words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
|
|
36
|
+
words
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def minus_word
|
|
40
|
+
GRAMMAR[:minus]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def fraction_joiner(joiner)
|
|
44
|
+
joiner.to_sym == :and ? "ja" : GRAMMAR[:conjunction]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def default_fraction_word
|
|
48
|
+
GRAMMAR[:default_fraction]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def fraction_numerator_feminine?
|
|
52
|
+
false
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def decimal_separator_word
|
|
56
|
+
"pilkku"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def decimal_fraction_words(fraction_string)
|
|
60
|
+
fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def date_day(day, format:, date_case:)
|
|
64
|
+
ordinal(day, :default)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def date_year(year, format:)
|
|
68
|
+
cardinal(year)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def ordinal(value, format, gender: :masculine)
|
|
72
|
+
ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
|
|
73
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
74
|
+
|
|
75
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
76
|
+
|
|
77
|
+
cardinal(value)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def cardinal(number)
|
|
81
|
+
integer_value = Integer(number)
|
|
82
|
+
negative = integer_value.negative?
|
|
83
|
+
integer_value = integer_value.abs
|
|
84
|
+
|
|
85
|
+
return ONES_MASC[0] if integer_value.zero?
|
|
86
|
+
|
|
87
|
+
groups = integer_value.to_s
|
|
88
|
+
.chars.reverse.each_slice(3).map(&:reverse)
|
|
89
|
+
.map(&:join).map!(&:to_i).reverse
|
|
90
|
+
|
|
91
|
+
words = []
|
|
92
|
+
groups.each_with_index do |group_value, index|
|
|
93
|
+
next if group_value.zero?
|
|
94
|
+
|
|
95
|
+
scale_idx = groups.size - index - 1
|
|
96
|
+
words.concat triple_to_words(group_value, scale_idx)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
words.unshift(minus_word) if negative
|
|
100
|
+
words.join(" ")
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def under_thousand(number)
|
|
104
|
+
return under_hundred(number) if number < 100
|
|
105
|
+
|
|
106
|
+
hundreds = number / 100
|
|
107
|
+
rest = number % 100
|
|
108
|
+
words = [HUNDREDS[hundreds]]
|
|
109
|
+
words << under_hundred(rest) if rest.positive?
|
|
110
|
+
words.join
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def under_hundred(number)
|
|
114
|
+
return ONES_MASC[number] if number < 10
|
|
115
|
+
return TEENS[number - 10] if number < 20
|
|
116
|
+
|
|
117
|
+
tens = number / 10
|
|
118
|
+
ones = number % 10
|
|
119
|
+
words = [TENS[tens]]
|
|
120
|
+
words << ONES_MASC[ones] if ones.positive?
|
|
121
|
+
words.join
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def pluralize(number, singular, few, _plural)
|
|
125
|
+
number.abs == 1 ? singular : few
|
|
126
|
+
end
|
|
23
127
|
end
|
|
24
128
|
|
|
25
129
|
register :fi, FI
|
data/lib/num2words/locales/fr.rb
CHANGED
|
@@ -20,6 +20,127 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :fr)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :fr)
|
|
23
|
+
|
|
24
|
+
module_function
|
|
25
|
+
|
|
26
|
+
def minus_word
|
|
27
|
+
GRAMMAR[:minus]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def fraction_joiner(_joiner)
|
|
31
|
+
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 decimal_separator_word
|
|
43
|
+
"virgule"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def decimal_fraction_words(fraction_string)
|
|
47
|
+
fraction_string.chars.map { |digit| under_thousand(digit.to_i) }.join(" ")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def time_unit_feminine?(unit)
|
|
51
|
+
unit == :hour || unit == :minute || unit == :second
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def currency_major_feminine?(currency)
|
|
55
|
+
%i[GBP TRY UAH CZK SEK NOK DKK INR IDR PKR].include?(currency)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def currency_minor_feminine?(currency)
|
|
59
|
+
%i[ILS BGN SAR].include?(currency)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
63
|
+
words = scale_idx == 1 && number == 1 ? [] : under_thousand(number, feminine: feminine).split
|
|
64
|
+
|
|
65
|
+
unless scale_idx.zero?
|
|
66
|
+
scale_forms = SCALES[scale_idx]
|
|
67
|
+
words << (number == 1 ? scale_forms[0] : scale_forms[2])
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
words
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def date_day(day, format:, date_case:)
|
|
74
|
+
return "premier" if day == 1
|
|
75
|
+
|
|
76
|
+
under_thousand(day)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def date_year(year, format:)
|
|
80
|
+
groups = year.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
|
+
scale_index = groups.size - index - 1
|
|
87
|
+
words.concat triple_to_words(group_value, scale_index)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
words.join(" ")
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def under_thousand(number, feminine: false)
|
|
94
|
+
hundreds = number / 100
|
|
95
|
+
rest = number % 100
|
|
96
|
+
|
|
97
|
+
return under_hundred(rest, feminine: feminine) if hundreds.zero?
|
|
98
|
+
|
|
99
|
+
hundred_words = if hundreds == 1
|
|
100
|
+
HUNDREDS[1]
|
|
101
|
+
elsif rest.zero?
|
|
102
|
+
HUNDREDS[hundreds]
|
|
103
|
+
else
|
|
104
|
+
HUNDREDS[hundreds].sub(/s\z/, "")
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
return hundred_words if rest.zero?
|
|
108
|
+
|
|
109
|
+
[hundred_words, under_hundred(rest, feminine: feminine)].join(" ")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def under_hundred(number, feminine: false)
|
|
113
|
+
ones_data = feminine ? ONES_FEM : ONES_MASC
|
|
114
|
+
|
|
115
|
+
return ones_data[number] if number < 10
|
|
116
|
+
return TEENS[number - 10] if number < 20
|
|
117
|
+
|
|
118
|
+
case number
|
|
119
|
+
when 20..69
|
|
120
|
+
tens = number / 10
|
|
121
|
+
ones = number % 10
|
|
122
|
+
return TENS[tens] if ones.zero?
|
|
123
|
+
return "#{TENS[tens]} et #{ones_data[ones]}" if ones == 1
|
|
124
|
+
|
|
125
|
+
"#{TENS[tens]} #{ones_data[ones]}"
|
|
126
|
+
when 70..79
|
|
127
|
+
teen = number - 60
|
|
128
|
+
return "soixante et #{TEENS[1]}" if teen == 11
|
|
129
|
+
|
|
130
|
+
"soixante #{under_hundred(teen, feminine: feminine)}"
|
|
131
|
+
when 80
|
|
132
|
+
"quatre-vingts"
|
|
133
|
+
else
|
|
134
|
+
rest = number - 80
|
|
135
|
+
return "quatre-vingt" if rest.zero?
|
|
136
|
+
|
|
137
|
+
"quatre-vingt #{under_hundred(rest, feminine: feminine)}"
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def pluralize(number, singular, _few, plural)
|
|
142
|
+
number.abs == 1 ? singular : plural
|
|
143
|
+
end
|
|
23
144
|
end
|
|
24
145
|
|
|
25
146
|
register :fr, FR
|
data/lib/num2words/locales/gu.rb
CHANGED
|
@@ -20,6 +20,118 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :gu)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :gu)
|
|
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
|
+
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
|
+
"દશાંશ"
|
|
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, :default)
|
|
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[:default] || 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 = [HUNDREDS[hundreds]]
|
|
128
|
+
words << UNDER_HUNDRED[rest] if rest.positive?
|
|
129
|
+
words.join(" ")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def pluralize(number, singular, few, _plural)
|
|
133
|
+
number.abs == 1 ? singular : few
|
|
134
|
+
end
|
|
23
135
|
end
|
|
24
136
|
|
|
25
137
|
register :gu, GU
|
data/lib/num2words/locales/he.rb
CHANGED
|
@@ -20,6 +20,136 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :he)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :he)
|
|
23
|
+
|
|
24
|
+
FEMININE_MAJOR_CURRENCIES = %i[TRY UAH CZK SEK NOK DKK INR IDR PKR].freeze
|
|
25
|
+
FEMININE_MINOR_CURRENCIES = %i[ILS RUB UAH BGN BYN SAR INR PKR RSD BDT].freeze
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
def integer_to_words(number, feminine: false)
|
|
30
|
+
cardinal(number, feminine: feminine)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
34
|
+
return [] if number.zero?
|
|
35
|
+
|
|
36
|
+
words = []
|
|
37
|
+
scale_forms = SCALES[scale_idx]
|
|
38
|
+
|
|
39
|
+
if scale_idx == 1
|
|
40
|
+
return [scale_forms[0]] if number == 1
|
|
41
|
+
return [scale_forms[1]] if number == 2
|
|
42
|
+
elsif scale_idx.positive? && number == 1
|
|
43
|
+
return [scale_forms[0]]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
words << under_thousand(number, feminine: feminine)
|
|
47
|
+
words << pluralize(number, *scale_forms) unless scale_idx.zero?
|
|
48
|
+
words
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def minus_word
|
|
52
|
+
GRAMMAR[:minus]
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def fraction_joiner(joiner)
|
|
56
|
+
joiner.to_sym == :and ? "ו" : GRAMMAR[:conjunction]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def default_fraction_word
|
|
60
|
+
GRAMMAR[:default_fraction]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def fraction_numerator_feminine?
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def decimal_separator_word
|
|
68
|
+
"נקודה"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def decimal_fraction_words(fraction_string)
|
|
72
|
+
fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def time_unit_feminine?(unit)
|
|
76
|
+
unit == :hour || unit == :minute || unit == :second
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def currency_major_feminine?(currency)
|
|
80
|
+
FEMININE_MAJOR_CURRENCIES.include?(currency)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def currency_minor_feminine?(currency)
|
|
84
|
+
FEMININE_MINOR_CURRENCIES.include?(currency)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def date_day(day, format:, date_case:)
|
|
88
|
+
ordinal(day, :default)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def date_year(year, format:)
|
|
92
|
+
cardinal(year)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def ordinal(value, format, gender: :masculine)
|
|
96
|
+
ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
|
|
97
|
+
gender_data = ordinals[gender] || ordinals[:masculine]
|
|
98
|
+
|
|
99
|
+
return gender_data[value - 1] if value.between?(1, gender_data.length)
|
|
100
|
+
|
|
101
|
+
cardinal(value)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def cardinal(number, feminine: false)
|
|
105
|
+
integer_value = Integer(number)
|
|
106
|
+
negative = integer_value.negative?
|
|
107
|
+
integer_value = integer_value.abs
|
|
108
|
+
|
|
109
|
+
return ONES_MASC[0] if integer_value.zero?
|
|
110
|
+
|
|
111
|
+
groups = integer_value.to_s
|
|
112
|
+
.chars.reverse.each_slice(3).map(&:reverse)
|
|
113
|
+
.map(&:join).map!(&:to_i).reverse
|
|
114
|
+
|
|
115
|
+
words = []
|
|
116
|
+
groups.each_with_index do |group_value, index|
|
|
117
|
+
next if group_value.zero?
|
|
118
|
+
|
|
119
|
+
scale_idx = groups.size - index - 1
|
|
120
|
+
words.concat triple_to_words(group_value, scale_idx, feminine: feminine)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
words.unshift(minus_word) if negative
|
|
124
|
+
words.join(" ")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def under_thousand(number, feminine: false)
|
|
128
|
+
return under_hundred(number, feminine: feminine) if number < 100
|
|
129
|
+
|
|
130
|
+
hundreds = number / 100
|
|
131
|
+
rest = number % 100
|
|
132
|
+
words = [HUNDREDS[hundreds]]
|
|
133
|
+
words << under_hundred(rest, feminine: feminine) if rest.positive?
|
|
134
|
+
words.join(" ")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def under_hundred(number, feminine: false)
|
|
138
|
+
ones_data = feminine ? ONES_FEM : ONES_MASC
|
|
139
|
+
|
|
140
|
+
return ones_data[number] if number < 10
|
|
141
|
+
return TEENS[number - 10] if number < 20
|
|
142
|
+
|
|
143
|
+
tens = number / 10
|
|
144
|
+
ones = number % 10
|
|
145
|
+
words = [TENS[tens]]
|
|
146
|
+
words << "ו#{ones_data[ones]}" if ones.positive?
|
|
147
|
+
words.join(" ")
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def pluralize(number, singular, _few, plural)
|
|
151
|
+
number.abs == 1 ? singular : plural
|
|
152
|
+
end
|
|
23
153
|
end
|
|
24
154
|
|
|
25
155
|
register :he, HE
|
data/lib/num2words/locales/hi.rb
CHANGED
|
@@ -20,6 +20,118 @@ module Num2words
|
|
|
20
20
|
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :hi)
|
|
21
21
|
|
|
22
22
|
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :hi)
|
|
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
|
+
"दशमलव"
|
|
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, :default)
|
|
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[:default] || 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 = [HUNDREDS[hundreds]]
|
|
128
|
+
words << UNDER_HUNDRED[rest] if rest.positive?
|
|
129
|
+
words.join(" ")
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def pluralize(number, singular, few, _plural)
|
|
133
|
+
number.abs == 1 ? singular : few
|
|
134
|
+
end
|
|
23
135
|
end
|
|
24
136
|
|
|
25
137
|
register :hi, HI
|