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.
Files changed (111) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +65 -0
  3. data/README.md +145 -135
  4. data/bin/console +2 -14
  5. data/config/locales/ar.yml +5 -1
  6. data/config/locales/be.yml +4 -0
  7. data/config/locales/bg.yml +4 -0
  8. data/config/locales/bn.yml +4 -0
  9. data/config/locales/cs.yml +6 -2
  10. data/config/locales/da.yml +4 -0
  11. data/config/locales/de.yml +8 -4
  12. data/config/locales/el.yml +4 -0
  13. data/config/locales/en.yml +4 -0
  14. data/config/locales/es.yml +4 -0
  15. data/config/locales/et.yml +9 -5
  16. data/config/locales/fa.yml +15 -11
  17. data/config/locales/fi.yml +8 -4
  18. data/config/locales/fr.yml +4 -0
  19. data/config/locales/gu.yml +4 -0
  20. data/config/locales/he.yml +6 -2
  21. data/config/locales/hi.yml +4 -0
  22. data/config/locales/hr.yml +8 -4
  23. data/config/locales/hu.yml +6 -2
  24. data/config/locales/id.yml +4 -0
  25. data/config/locales/it.yml +4 -0
  26. data/config/locales/ja.yml +10 -5
  27. data/config/locales/kn.yml +186 -10
  28. data/config/locales/ko.yml +184 -13
  29. data/config/locales/kz.yml +183 -17
  30. data/config/locales/lt.yml +184 -8
  31. data/config/locales/lv.yml +188 -12
  32. data/config/locales/ml.yml +189 -13
  33. data/config/locales/mr.yml +184 -8
  34. data/config/locales/ms.yml +184 -8
  35. data/config/locales/nb.yml +183 -17
  36. data/config/locales/nl.yml +184 -13
  37. data/config/locales/pa.yml +189 -13
  38. data/config/locales/pl.yml +184 -13
  39. data/config/locales/pt.yml +184 -13
  40. data/config/locales/ro.yml +183 -12
  41. data/config/locales/ru.yml +8 -0
  42. data/config/locales/sk.yml +184 -8
  43. data/config/locales/sl.yml +185 -9
  44. data/config/locales/sr.yml +186 -15
  45. data/config/locales/sv.yml +182 -13
  46. data/config/locales/sw.yml +184 -8
  47. data/config/locales/ta.yml +184 -8
  48. data/config/locales/te.yml +185 -9
  49. data/config/locales/th.yml +183 -12
  50. data/config/locales/tr.yml +183 -12
  51. data/config/locales/uk.yml +189 -18
  52. data/config/locales/ur.yml +187 -11
  53. data/config/locales/vi.yml +183 -12
  54. data/config/locales/zh.yml +191 -9
  55. data/exe/num2words-console +7 -0
  56. data/lib/num2words/console.rb +16 -0
  57. data/lib/num2words/converter.rb +195 -47
  58. data/lib/num2words/locales/ar.rb +130 -0
  59. data/lib/num2words/locales/be.rb +101 -0
  60. data/lib/num2words/locales/bg.rb +127 -0
  61. data/lib/num2words/locales/bn.rb +112 -0
  62. data/lib/num2words/locales/cs.rb +106 -0
  63. data/lib/num2words/locales/da.rb +97 -0
  64. data/lib/num2words/locales/de.rb +119 -0
  65. data/lib/num2words/locales/el.rb +143 -0
  66. data/lib/num2words/locales/en.rb +90 -0
  67. data/lib/num2words/locales/es.rb +185 -0
  68. data/lib/num2words/locales/et.rb +104 -0
  69. data/lib/num2words/locales/fa.rb +104 -0
  70. data/lib/num2words/locales/fi.rb +104 -0
  71. data/lib/num2words/locales/fr.rb +121 -0
  72. data/lib/num2words/locales/gu.rb +112 -0
  73. data/lib/num2words/locales/he.rb +130 -0
  74. data/lib/num2words/locales/hi.rb +112 -0
  75. data/lib/num2words/locales/hr.rb +117 -0
  76. data/lib/num2words/locales/hu.rb +111 -0
  77. data/lib/num2words/locales/id.rb +104 -0
  78. data/lib/num2words/locales/it.rb +142 -0
  79. data/lib/num2words/locales/ja.rb +126 -0
  80. data/lib/num2words/locales/kn.rb +122 -2
  81. data/lib/num2words/locales/ko.rb +158 -2
  82. data/lib/num2words/locales/kz.rb +137 -2
  83. data/lib/num2words/locales/lt.rb +146 -2
  84. data/lib/num2words/locales/lv.rb +148 -2
  85. data/lib/num2words/locales/ml.rb +142 -2
  86. data/lib/num2words/locales/mr.rb +142 -2
  87. data/lib/num2words/locales/ms.rb +134 -2
  88. data/lib/num2words/locales/nb.rb +153 -0
  89. data/lib/num2words/locales/nl.rb +142 -2
  90. data/lib/num2words/locales/pa.rb +122 -2
  91. data/lib/num2words/locales/pl.rb +149 -2
  92. data/lib/num2words/locales/pt.rb +164 -2
  93. data/lib/num2words/locales/ro.rb +165 -2
  94. data/lib/num2words/locales/ru.rb +100 -0
  95. data/lib/num2words/locales/sk.rb +124 -2
  96. data/lib/num2words/locales/sl.rb +154 -2
  97. data/lib/num2words/locales/sr.rb +141 -3
  98. data/lib/num2words/locales/sv.rb +141 -2
  99. data/lib/num2words/locales/sw.rb +133 -2
  100. data/lib/num2words/locales/ta.rb +142 -2
  101. data/lib/num2words/locales/te.rb +142 -2
  102. data/lib/num2words/locales/th.rb +133 -2
  103. data/lib/num2words/locales/tr.rb +141 -2
  104. data/lib/num2words/locales/uk.rb +134 -2
  105. data/lib/num2words/locales/ur.rb +130 -2
  106. data/lib/num2words/locales/vi.rb +142 -2
  107. data/lib/num2words/locales/zh.rb +172 -2
  108. data/lib/num2words/version.rb +1 -1
  109. data/num2words.gemspec +3 -3
  110. metadata +13 -10
  111. data/lib/num2words/locales/no.rb +0 -19
@@ -10,8 +10,160 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :sl)
11
11
  SCALES = I18n.t("num2words.scales", locale: :sl)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.EUR.name", locale: :sl)
14
- MINOR_UNIT = I18n.t("num2words.currencies.EUR.fractional.name", locale: :sl)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :sl)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :sl)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :sl)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :sl)
18
+ TIME = I18n.t("num2words.time", locale: :sl)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :sl)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :sl)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :sl)
23
+
24
+ FEMININE_MAJOR_CURRENCIES = %i[CZK GBP RUB TRY UAH SEK NOK DKK BGN BYN INR IDR BDT PKR].freeze
25
+ FEMININE_MINOR_CURRENCIES = %i[RUB UAH BGN BYN ILS SAR RSD BDT].freeze
26
+
27
+ module_function
28
+
29
+ def feminine_group?(scale_idx)
30
+ scale_idx == 3
31
+ end
32
+
33
+ def fraction_numerator_feminine?
34
+ true
35
+ end
36
+
37
+ def currency_major_feminine?(currency)
38
+ FEMININE_MAJOR_CURRENCIES.include?(currency)
39
+ end
40
+
41
+ def currency_minor_feminine?(currency)
42
+ FEMININE_MINOR_CURRENCIES.include?(currency)
43
+ end
44
+
45
+ def minus_word
46
+ GRAMMAR[:minus]
47
+ end
48
+
49
+ def fraction_joiner(joiner)
50
+ joiner.to_sym == :and ? "in" : GRAMMAR[:conjunction]
51
+ end
52
+
53
+ def default_fraction_word
54
+ GRAMMAR[:default_fraction]
55
+ end
56
+
57
+ def decimal_separator_word
58
+ "vejica"
59
+ end
60
+
61
+ def decimal_fraction_words(fraction_string)
62
+ fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
63
+ end
64
+
65
+ def time_unit_feminine?(unit)
66
+ %i[hour minute second].include?(unit)
67
+ end
68
+
69
+ def time_number_words(number, unit:)
70
+ cardinal(number, feminine: time_unit_feminine?(unit))
71
+ end
72
+
73
+ def currency_number_words(number, currency, unit:)
74
+ feminine = unit == :major ? currency_major_feminine?(currency) : currency_minor_feminine?(currency)
75
+ cardinal(number, feminine: feminine)
76
+ end
77
+
78
+ def integer_to_words(number, feminine: false)
79
+ cardinal(number, feminine: feminine)
80
+ end
81
+
82
+ def triple_to_words(number, scale_idx, feminine: false)
83
+ return [] if number.zero?
84
+
85
+ words = [under_thousand(number, feminine: feminine)]
86
+ words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
87
+ words
88
+ end
89
+
90
+ def date_day(day, format:, date_case:)
91
+ ordinal(day, :default)
92
+ end
93
+
94
+ def date_year(year, format:)
95
+ cardinal(year)
96
+ end
97
+
98
+ def ordinal(value, format, gender: :masculine)
99
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
100
+ gender_data = ordinals[gender] || ordinals[:masculine]
101
+
102
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
103
+
104
+ cardinal(value)
105
+ end
106
+
107
+ def cardinal(number, feminine: false)
108
+ integer_value = Integer(number)
109
+ negative = integer_value.negative?
110
+ integer_value = integer_value.abs
111
+
112
+ return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
113
+
114
+ groups = integer_value.to_s
115
+ .chars.reverse.each_slice(3).map(&:reverse)
116
+ .map(&:join).map!(&:to_i).reverse
117
+
118
+ words = []
119
+ groups.each_with_index do |group_value, index|
120
+ next if group_value.zero?
121
+
122
+ scale_idx = groups.size - index - 1
123
+ group_feminine = feminine_group?(scale_idx) || (feminine && scale_idx.zero?)
124
+ group_words = triple_to_words(group_value, scale_idx, feminine: group_feminine)
125
+ group_words.shift if scale_idx == 1 && group_value == 1
126
+ words.concat(group_words)
127
+ end
128
+
129
+ words.unshift(minus_word) if negative
130
+ words.join(" ")
131
+ end
132
+
133
+ def under_thousand(number, feminine: false)
134
+ return under_hundred(number, feminine: feminine) if number < 100
135
+
136
+ hundreds = number / 100
137
+ rest = number % 100
138
+ words = [HUNDREDS[hundreds]]
139
+ words << under_hundred(rest, feminine: feminine) if rest.positive?
140
+ words.join(" ")
141
+ end
142
+
143
+ def under_hundred(number, feminine: false)
144
+ return one_word(number, feminine: feminine) if number < 10
145
+ return TEENS[number - 10] if number < 20
146
+ return TENS[number / 10] if (number % 10).zero?
147
+
148
+ ones = number % 10
149
+ tens = number / 10
150
+ "#{compound_one(ones)}in#{TENS[tens]}"
151
+ end
152
+
153
+ def one_word(number, feminine:)
154
+ feminine ? ONES_FEM[number] : ONES_MASC[number]
155
+ end
156
+
157
+ def compound_one(number)
158
+ number == 1 ? "ena" : ONES_MASC[number]
159
+ end
160
+
161
+ def pluralize(number, singular, few, plural)
162
+ number = number.abs
163
+ return plural if (11..14).include?(number % 100)
164
+
165
+ number == 1 ? singular : (number == 2 ? few : plural)
166
+ end
15
167
  end
16
168
 
17
169
  register :sl, SL
@@ -10,10 +10,148 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :sr)
11
11
  SCALES = I18n.t("num2words.scales", locale: :sr)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.RSD.name", locale: :sr)
14
- MINOR_UNIT = I18n.t("num2words.currencies.RSD.fractional.name", locale: :sr)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :sr)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :sr)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :sr)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :sr)
18
+ TIME = I18n.t("num2words.time", locale: :sr)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :sr)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :sr)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :sr)
23
+
24
+ FEMININE_MAJOR_CURRENCIES = %i[GBP RUB TRY UAH CZK SEK NOK DKK BYN INR IDR BDT PKR HUF].freeze
25
+ FEMININE_MINOR_CURRENCIES = %i[RUB UAH BGN ILS SAR RSD BDT].freeze
26
+
27
+ module_function
28
+
29
+ def feminine_group?(scale_idx)
30
+ scale_idx == 1 || scale_idx == 3
31
+ end
32
+
33
+ def fraction_numerator_feminine?
34
+ true
35
+ end
36
+
37
+ def currency_major_feminine?(currency)
38
+ FEMININE_MAJOR_CURRENCIES.include?(currency)
39
+ end
40
+
41
+ def currency_minor_feminine?(currency)
42
+ FEMININE_MINOR_CURRENCIES.include?(currency)
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 decimal_separator_word
58
+ "зарез"
59
+ end
60
+
61
+ def decimal_fraction_words(fraction_string)
62
+ fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
63
+ end
64
+
65
+ def time_unit_feminine?(unit)
66
+ unit == :second
67
+ end
68
+
69
+ def time_number_words(number, unit:)
70
+ cardinal(number, feminine: time_unit_feminine?(unit))
71
+ end
72
+
73
+ def currency_number_words(number, currency, unit:)
74
+ feminine = unit == :major ? currency_major_feminine?(currency) : currency_minor_feminine?(currency)
75
+ cardinal(number, feminine: feminine)
76
+ end
77
+
78
+ def integer_to_words(number, feminine: false)
79
+ cardinal(number, feminine: feminine)
80
+ end
81
+
82
+ def triple_to_words(number, scale_idx, feminine: false)
83
+ return [] if number.zero?
84
+
85
+ words = []
86
+ words << HUNDREDS[number / 100] if number >= 100
87
+ rest = number % 100
88
+
89
+ if rest.between?(10, 19)
90
+ words << TEENS[rest - 10]
91
+ else
92
+ words << TENS[rest / 10] if rest >= 20
93
+ ones = rest % 10
94
+ words << (feminine ? ONES_FEM[ones] : ONES_MASC[ones]) if ones.positive?
95
+ end
96
+
97
+ words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
98
+ words.compact
99
+ end
100
+
101
+ def date_day(day, format:, date_case:)
102
+ ordinal(day, :default)
103
+ end
104
+
105
+ def date_year(year, format:)
106
+ cardinal(year)
107
+ end
108
+
109
+ def ordinal(value, format, gender: :masculine)
110
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
111
+ gender_data = ordinals[gender] || ordinals[:masculine]
112
+
113
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
114
+
115
+ cardinal(value)
116
+ end
117
+
118
+ def cardinal(number, feminine: false)
119
+ integer_value = Integer(number)
120
+ negative = integer_value.negative?
121
+ integer_value = integer_value.abs
122
+
123
+ return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
124
+
125
+ groups = integer_value.to_s
126
+ .chars.reverse.each_slice(3).map(&:reverse)
127
+ .map(&:join).map!(&:to_i).reverse
128
+
129
+ words = []
130
+ groups.each_with_index do |group_value, index|
131
+ next if group_value.zero?
132
+
133
+ scale_idx = groups.size - index - 1
134
+ group_feminine = feminine_group?(scale_idx) || (feminine && scale_idx.zero?)
135
+ group_words = triple_to_words(group_value, scale_idx, feminine: group_feminine)
136
+ words.concat(group_words)
137
+ end
138
+
139
+ words.unshift(minus_word) if negative
140
+ words.join(" ")
141
+ end
142
+
143
+ def pluralize(number, singular, few, plural)
144
+ number = number.abs
145
+ return plural if (11..14).include?(number % 100)
146
+
147
+ case number % 10
148
+ when 1 then singular
149
+ when 2..4 then few
150
+ else plural
151
+ end
152
+ end
15
153
  end
16
154
 
17
- register :sr, Sr
155
+ register :sr, SR
18
156
  end
19
157
  end
@@ -10,8 +10,147 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :sv)
11
11
  SCALES = I18n.t("num2words.scales", locale: :sv)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.SEK.name", locale: :sv)
14
- MINOR_UNIT = I18n.t("num2words.currencies.SEK.fractional.name", locale: :sv)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :sv)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :sv)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :sv)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :sv)
18
+ TIME = I18n.t("num2words.time", locale: :sv)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :sv)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :sv)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :sv)
23
+
24
+ COMMON_GENDER_MAJOR_CURRENCIES = %i[
25
+ BDT BGN BRL BYN CNY CZK DKK EUR HUF IDR ILS INR IRR JPY KES KRW
26
+ KZT MYR NOK PKR PLN RON RSD RUB SAR SEK THB TRY UAH USD VND
27
+ ].freeze
28
+
29
+ module_function
30
+
31
+ def minus_word
32
+ GRAMMAR[:minus]
33
+ end
34
+
35
+ def fraction_joiner(joiner)
36
+ joiner.to_sym == :and ? "och" : GRAMMAR[:conjunction]
37
+ end
38
+
39
+ def default_fraction_word
40
+ GRAMMAR[:default_fraction]
41
+ end
42
+
43
+ def fraction_numerator_feminine?
44
+ false
45
+ end
46
+
47
+ def decimal_separator_word
48
+ "komma"
49
+ end
50
+
51
+ def decimal_fraction_words(fraction_string)
52
+ fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
53
+ end
54
+
55
+ def currency_major_feminine?(currency)
56
+ COMMON_GENDER_MAJOR_CURRENCIES.include?(currency)
57
+ end
58
+
59
+ def currency_minor_feminine?(_currency)
60
+ false
61
+ end
62
+
63
+ def currency_number_words(number, currency, unit:)
64
+ feminine = unit == :major && currency_major_feminine?(currency)
65
+ cardinal(number, feminine: feminine)
66
+ end
67
+
68
+ def integer_to_words(number, feminine: false)
69
+ cardinal(number, feminine: feminine)
70
+ end
71
+
72
+ def triple_to_words(number, scale_idx, feminine: false)
73
+ return [] if number.zero?
74
+
75
+ words = []
76
+ words << scale_number_words(number, scale_idx, feminine: feminine)
77
+ words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
78
+ words
79
+ end
80
+
81
+ def date_day(day, format:, date_case:)
82
+ ordinal(day, :nominative)
83
+ end
84
+
85
+ def date_year(year, format:)
86
+ cardinal(year)
87
+ end
88
+
89
+ def ordinal(value, format, gender: :masculine)
90
+ ordinals = ORDINALS[format] || ORDINALS[:nominative]
91
+ gender_data = ordinals[gender] || ordinals[:masculine]
92
+
93
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
94
+
95
+ cardinal(value)
96
+ end
97
+
98
+ def cardinal(number, feminine: false)
99
+ integer_value = Integer(number)
100
+ negative = integer_value.negative?
101
+ integer_value = integer_value.abs
102
+
103
+ return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
104
+
105
+ groups = integer_value.to_s
106
+ .chars.reverse.each_slice(3).map(&:reverse)
107
+ .map(&:join).map!(&:to_i).reverse
108
+
109
+ words = []
110
+ groups.each_with_index do |group_value, index|
111
+ next if group_value.zero?
112
+
113
+ scale_idx = groups.size - index - 1
114
+ group_words = triple_to_words(group_value, scale_idx, feminine: feminine && scale_idx.zero?)
115
+ words.concat(group_words)
116
+ end
117
+
118
+ words.unshift(minus_word) if negative
119
+ words.join(" ")
120
+ end
121
+
122
+ def scale_number_words(number, scale_idx, feminine:)
123
+ return "ett" if scale_idx == 1 && number == 1
124
+ return "en" if scale_idx > 1 && number == 1
125
+
126
+ under_thousand(number, feminine: feminine)
127
+ end
128
+
129
+ def under_thousand(number, feminine: false)
130
+ return under_hundred(number, feminine: feminine) if number < 100
131
+
132
+ hundreds = number / 100
133
+ rest = number % 100
134
+ words = [HUNDREDS[hundreds]]
135
+ words << under_hundred(rest, feminine: feminine) if rest.positive?
136
+ words.join(" ")
137
+ end
138
+
139
+ def under_hundred(number, feminine: false)
140
+ return one_word(number, feminine: feminine) if number < 10
141
+ return TEENS[number - 10] if number < 20
142
+ return TENS[number / 10] if (number % 10).zero?
143
+
144
+ "#{TENS[number / 10]}#{one_word(number % 10, feminine: feminine)}"
145
+ end
146
+
147
+ def one_word(number, feminine:)
148
+ feminine ? ONES_FEM[number] : ONES_MASC[number]
149
+ end
150
+
151
+ def pluralize(number, singular, _few, plural)
152
+ number.abs == 1 ? singular : plural
153
+ end
15
154
  end
16
155
 
17
156
  register :sv, SV
@@ -10,8 +10,139 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :sw)
11
11
  SCALES = I18n.t("num2words.scales", locale: :sw)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.KES.name", locale: :sw)
14
- MINOR_UNIT = I18n.t("num2words.currencies.KES.fractional.name", locale: :sw)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :sw)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :sw)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :sw)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :sw)
18
+ TIME = I18n.t("num2words.time", locale: :sw)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :sw)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :sw)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :sw)
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 = [under_thousand(number)]
34
+ words << SCALES[scale_idx][0] unless scale_idx.zero?
35
+ words
36
+ end
37
+
38
+ def minus_word
39
+ GRAMMAR[:minus]
40
+ end
41
+
42
+ def fraction_joiner(joiner)
43
+ joiner.to_sym == :and ? "na" : GRAMMAR[:conjunction]
44
+ end
45
+
46
+ def default_fraction_word
47
+ GRAMMAR[:default_fraction]
48
+ end
49
+
50
+ def fraction_numerator_feminine?
51
+ false
52
+ end
53
+
54
+ def decimal_separator_word
55
+ GRAMMAR[:conjunction]
56
+ end
57
+
58
+ def decimal_fraction_words(fraction_string)
59
+ fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
60
+ end
61
+
62
+ def date_day(day, format:, date_case:)
63
+ cardinal(day)
64
+ end
65
+
66
+ def date_year(year, format:)
67
+ cardinal(year)
68
+ end
69
+
70
+ def time_unit_feminine?(_unit)
71
+ false
72
+ end
73
+
74
+ def time_number_words(number, unit:)
75
+ cardinal(number)
76
+ end
77
+
78
+ def currency_major_feminine?(_currency)
79
+ false
80
+ end
81
+
82
+ def currency_minor_feminine?(_currency)
83
+ false
84
+ end
85
+
86
+ def currency_number_words(number, _currency, unit:)
87
+ cardinal(number)
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 ONES_MASC[0] if integer_value.zero?
105
+
106
+ groups = integer_value.to_s
107
+ .chars.reverse.each_slice(3).map(&:reverse)
108
+ .map(&:join).map!(&:to_i).reverse
109
+
110
+ words = []
111
+ groups.each_with_index do |group_value, index|
112
+ next if group_value.zero?
113
+
114
+ scale_idx = groups.size - index - 1
115
+ words.concat triple_to_words(group_value, scale_idx)
116
+ end
117
+
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(" na ")
130
+ end
131
+
132
+ def under_hundred(number)
133
+ return ONES_MASC[number] if number < 10
134
+ return TEENS[number - 10] if number < 20
135
+
136
+ tens = number / 10
137
+ ones = number % 10
138
+ words = [TENS[tens]]
139
+ words << ONES_MASC[ones] if ones.positive?
140
+ words.join(" na ")
141
+ end
142
+
143
+ def pluralize(_number, singular, _few, _plural)
144
+ singular
145
+ end
15
146
  end
16
147
 
17
148
  register :sw, SW