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,154 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :lv)
11
11
  SCALES = I18n.t("num2words.scales", locale: :lv)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.EUR.name", locale: :lv)
14
- MINOR_UNIT = I18n.t("num2words.currencies.EUR.fractional.name", locale: :lv)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :lv)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :lv)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :lv)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :lv)
18
+ TIME = I18n.t("num2words.time", locale: :lv)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :lv)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :lv)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :lv)
23
+
24
+ module_function
25
+
26
+ def integer_to_words(number, feminine: false)
27
+ cardinal(number, feminine: feminine)
28
+ end
29
+
30
+ def triple_to_words(number, scale_idx, feminine: false)
31
+ return [] if number.zero?
32
+
33
+ words = [under_thousand(number, feminine: feminine)]
34
+ words << scale_form(number, scale_idx) unless scale_idx.zero?
35
+ words
36
+ end
37
+
38
+ def feminine_group?(_scale_idx)
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 ? "un" : GRAMMAR[:conjunction]
48
+ end
49
+
50
+ def default_fraction_word
51
+ GRAMMAR[:default_fraction]
52
+ end
53
+
54
+ def fraction_numerator_feminine?
55
+ true
56
+ end
57
+
58
+ def decimal_separator_word
59
+ "komats"
60
+ end
61
+
62
+ def decimal_fraction_words(fraction_string)
63
+ fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
64
+ end
65
+
66
+ def date_day(day, format:, date_case:)
67
+ ordinal(day, :default, gender: :feminine)
68
+ end
69
+
70
+ def date_year(year, format:)
71
+ cardinal(year)
72
+ end
73
+
74
+ def time_unit_feminine?(_unit)
75
+ true
76
+ end
77
+
78
+ def time_number_words(number, unit:)
79
+ cardinal(number, feminine: true)
80
+ end
81
+
82
+ def currency_major_feminine?(currency)
83
+ %i[BDT BGN CNY CZK DKK GBP IDR INR JPY KZT NOK PKR RON RSD SEK TRY UAH].include?(currency)
84
+ end
85
+
86
+ def currency_minor_feminine?(currency)
87
+ %i[BDT BGN BRL BYN DKK ILS NOK RSD RUB SAR SEK TRY UAH].include?(currency)
88
+ end
89
+
90
+ def currency_number_words(number, currency, unit:)
91
+ feminine = unit == :major ? currency_major_feminine?(currency) : currency_minor_feminine?(currency)
92
+ cardinal(number, feminine: feminine)
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
+ group_feminine = scale_idx.zero? && feminine
121
+ words.concat triple_to_words(group_value, scale_idx, feminine: group_feminine)
122
+ end
123
+
124
+ words.unshift(minus_word) if negative
125
+ words.join(" ")
126
+ end
127
+
128
+ def under_thousand(number, feminine: false)
129
+ return under_hundred(number, feminine: feminine) if number < 100
130
+
131
+ hundreds = number / 100
132
+ rest = number % 100
133
+ words = [HUNDREDS[hundreds]]
134
+ words << under_hundred(rest, feminine: feminine) if rest.positive?
135
+ words.join(" ")
136
+ end
137
+
138
+ def under_hundred(number, feminine: false)
139
+ return (feminine ? ONES_FEM[number] : ONES_MASC[number]) if number < 10
140
+ return TEENS[number - 10] if number < 20
141
+
142
+ tens = number / 10
143
+ ones = number % 10
144
+ words = [TENS[tens]]
145
+ words << (feminine ? ONES_FEM[ones] : ONES_MASC[ones]) if ones.positive?
146
+ words.join(" ")
147
+ end
148
+
149
+ def scale_form(number, scale_idx)
150
+ singular, plural, = SCALES[scale_idx]
151
+ number.abs % 10 == 1 && number.abs % 100 != 11 ? singular : plural
152
+ end
153
+
154
+ def pluralize(number, singular, few, plural)
155
+ number = number.abs
156
+ return singular if number % 10 == 1 && number % 100 != 11
157
+ return plural if number.zero? || (number % 10).zero? || (10..20).include?(number % 100)
158
+
159
+ few
160
+ end
15
161
  end
16
162
 
17
163
  register :lv, LV
@@ -10,8 +10,148 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :ml)
11
11
  SCALES = I18n.t("num2words.scales", locale: :ml)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.INR.name", locale: :ml)
14
- MINOR_UNIT = I18n.t("num2words.currencies.INR.fractional.name", locale: :ml)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :ml)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :ml)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :ml)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :ml)
18
+ TIME = I18n.t("num2words.time", locale: :ml)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :ml)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :ml)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :ml)
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 time_unit_feminine?(_unit)
91
+ false
92
+ end
93
+
94
+ def time_number_words(number, unit:)
95
+ cardinal(number)
96
+ end
97
+
98
+ def currency_major_feminine?(_currency)
99
+ false
100
+ end
101
+
102
+ def currency_minor_feminine?(_currency)
103
+ false
104
+ end
105
+
106
+ def currency_number_words(number, _currency, unit:)
107
+ cardinal(number)
108
+ end
109
+
110
+ def ordinal(value, format, gender: :masculine)
111
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
112
+ gender_data = ordinals[gender] || ordinals[:masculine]
113
+
114
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
115
+
116
+ cardinal(value)
117
+ end
118
+
119
+ def cardinal(number)
120
+ integer_value = Integer(number)
121
+ negative = integer_value.negative?
122
+ integer_value = integer_value.abs
123
+
124
+ return UNDER_HUNDRED[0] if integer_value.zero?
125
+
126
+ remainder = integer_value
127
+ words = []
128
+
129
+ INDIAN_SCALES.each do |value, label|
130
+ next if remainder < value
131
+
132
+ group_value = remainder / value
133
+ remainder %= value
134
+ words << [cardinal(group_value), label].join(" ")
135
+ end
136
+
137
+ words << under_thousand(remainder) if remainder.positive?
138
+ words.unshift(minus_word) if negative
139
+ words.join(" ")
140
+ end
141
+
142
+ def under_thousand(number)
143
+ return UNDER_HUNDRED[number] if number < 100
144
+
145
+ hundreds = number / 100
146
+ rest = number % 100
147
+ words = [HUNDREDS[hundreds]]
148
+ words << UNDER_HUNDRED[rest] if rest.positive?
149
+ words.join(" ")
150
+ end
151
+
152
+ def pluralize(_number, singular, _few, _plural)
153
+ singular
154
+ end
15
155
  end
16
156
 
17
157
  register :ml, ML
@@ -10,8 +10,148 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :mr)
11
11
  SCALES = I18n.t("num2words.scales", locale: :mr)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.INR.name", locale: :mr)
14
- MINOR_UNIT = I18n.t("num2words.currencies.INR.fractional.name", locale: :mr)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :mr)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :mr)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :mr)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :mr)
18
+ TIME = I18n.t("num2words.time", locale: :mr)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :mr)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :mr)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :mr)
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 time_unit_feminine?(_unit)
91
+ false
92
+ end
93
+
94
+ def time_number_words(number, unit:)
95
+ cardinal(number)
96
+ end
97
+
98
+ def currency_major_feminine?(_currency)
99
+ false
100
+ end
101
+
102
+ def currency_minor_feminine?(_currency)
103
+ false
104
+ end
105
+
106
+ def currency_number_words(number, _currency, unit:)
107
+ cardinal(number)
108
+ end
109
+
110
+ def ordinal(value, format, gender: :masculine)
111
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
112
+ gender_data = ordinals[gender] || ordinals[:masculine]
113
+
114
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
115
+
116
+ cardinal(value)
117
+ end
118
+
119
+ def cardinal(number)
120
+ integer_value = Integer(number)
121
+ negative = integer_value.negative?
122
+ integer_value = integer_value.abs
123
+
124
+ return UNDER_HUNDRED[0] if integer_value.zero?
125
+
126
+ remainder = integer_value
127
+ words = []
128
+
129
+ INDIAN_SCALES.each do |value, label|
130
+ next if remainder < value
131
+
132
+ group_value = remainder / value
133
+ remainder %= value
134
+ words << [cardinal(group_value), label].join(" ")
135
+ end
136
+
137
+ words << under_thousand(remainder) if remainder.positive?
138
+ words.unshift(minus_word) if negative
139
+ words.join(" ")
140
+ end
141
+
142
+ def under_thousand(number)
143
+ return UNDER_HUNDRED[number] if number < 100
144
+
145
+ hundreds = number / 100
146
+ rest = number % 100
147
+ words = [HUNDREDS[hundreds]]
148
+ words << UNDER_HUNDRED[rest] if rest.positive?
149
+ words.join(" ")
150
+ end
151
+
152
+ def pluralize(number, singular, few, _plural)
153
+ number.abs == 1 ? singular : few
154
+ end
15
155
  end
16
156
 
17
157
  register :mr, MR
@@ -10,8 +10,140 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :ms)
11
11
  SCALES = I18n.t("num2words.scales", locale: :ms)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.MYR.name", locale: :ms)
14
- MINOR_UNIT = I18n.t("num2words.currencies.MYR.fractional.name", locale: :ms)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :ms)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :ms)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :ms)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :ms)
18
+ TIME = I18n.t("num2words.time", locale: :ms)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :ms)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :ms)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :ms)
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 << SCALES[scale_idx][0] 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 ? "dan" : 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
+ GRAMMAR[:conjunction]
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
+ cardinal(day)
65
+ end
66
+
67
+ def date_year(year, format:)
68
+ cardinal(year)
69
+ end
70
+
71
+ def time_unit_feminine?(_unit)
72
+ false
73
+ end
74
+
75
+ def time_number_words(number, unit:)
76
+ cardinal(number)
77
+ end
78
+
79
+ def currency_major_feminine?(_currency)
80
+ false
81
+ end
82
+
83
+ def currency_minor_feminine?(_currency)
84
+ false
85
+ end
86
+
87
+ def currency_number_words(number, _currency, unit:)
88
+ cardinal(number)
89
+ end
90
+
91
+ def ordinal(value, format, gender: :masculine)
92
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
93
+ gender_data = ordinals[gender] || ordinals[:masculine]
94
+
95
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
96
+
97
+ cardinal(value)
98
+ end
99
+
100
+ def cardinal(number)
101
+ integer_value = Integer(number)
102
+ negative = integer_value.negative?
103
+ integer_value = integer_value.abs
104
+
105
+ return ONES_MASC[0] if integer_value.zero?
106
+
107
+ groups = integer_value.to_s
108
+ .chars.reverse.each_slice(3).map(&:reverse)
109
+ .map(&:join).map!(&:to_i).reverse
110
+
111
+ words = []
112
+ groups.each_with_index do |group_value, index|
113
+ next if group_value.zero?
114
+
115
+ scale_idx = groups.size - index - 1
116
+ words.concat triple_to_words(group_value, scale_idx)
117
+ end
118
+
119
+ words.unshift(minus_word) if negative
120
+ words.join(" ")
121
+ end
122
+
123
+ def under_thousand(number)
124
+ return under_hundred(number) if number < 100
125
+
126
+ hundreds = number / 100
127
+ rest = number % 100
128
+ words = [hundreds == 1 ? "seratus" : "#{ONES_MASC[hundreds]} ratus"]
129
+ words << under_hundred(rest) if rest.positive?
130
+ words.join(" ")
131
+ end
132
+
133
+ def under_hundred(number)
134
+ return ONES_MASC[number] if number < 10
135
+ return TEENS[number - 10] if number < 20
136
+
137
+ tens = number / 10
138
+ ones = number % 10
139
+ words = ["#{ONES_MASC[tens]} puluh"]
140
+ words << ONES_MASC[ones] if ones.positive?
141
+ words.join(" ")
142
+ end
143
+
144
+ def pluralize(_number, singular, _few, _plural)
145
+ singular
146
+ end
15
147
  end
16
148
 
17
149
  register :ms, MS