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
@@ -20,6 +20,123 @@ module Num2words
20
20
  DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :hr)
21
21
 
22
22
  ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :hr)
23
+
24
+ FEMININE_MAJOR_CURRENCIES = %i[GBP RUB TRY UAH CZK SEK NOK DKK BYN INR IDR BDT PKR].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
+ GRAMMAR[:conjunction]
51
+ end
52
+
53
+ def default_fraction_word
54
+ GRAMMAR[:default_fraction]
55
+ end
56
+
57
+ def decimal_separator_word
58
+ "zarez"
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 integer_to_words(number, feminine: false)
66
+ cardinal(number, feminine: feminine)
67
+ end
68
+
69
+ def triple_to_words(number, scale_idx, feminine: false)
70
+ return [] if number.zero?
71
+
72
+ words = []
73
+ words << HUNDREDS[number / 100] if number >= 100
74
+ rest = number % 100
75
+
76
+ if rest.between?(10, 19)
77
+ words << TEENS[rest - 10]
78
+ else
79
+ words << TENS[rest / 10] if rest >= 20
80
+ ones = rest % 10
81
+ words << (feminine ? ONES_FEM[ones] : ONES_MASC[ones]) if ones.positive?
82
+ end
83
+
84
+ words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
85
+ words.compact
86
+ end
87
+
88
+ def date_day(day, format:, date_case:)
89
+ ordinal(day, :default)
90
+ end
91
+
92
+ def date_year(year, format:)
93
+ cardinal(year)
94
+ end
95
+
96
+ def ordinal(value, format, gender: :masculine)
97
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
98
+ gender_data = ordinals[gender] || ordinals[:masculine]
99
+
100
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
101
+
102
+ cardinal(value)
103
+ end
104
+
105
+ def cardinal(number, feminine: false)
106
+ integer_value = Integer(number)
107
+ negative = integer_value.negative?
108
+ integer_value = integer_value.abs
109
+
110
+ return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
111
+
112
+ groups = integer_value.to_s
113
+ .chars.reverse.each_slice(3).map(&:reverse)
114
+ .map(&:join).map!(&:to_i).reverse
115
+
116
+ words = []
117
+ groups.each_with_index do |group_value, index|
118
+ next if group_value.zero?
119
+
120
+ scale_idx = groups.size - index - 1
121
+ group_feminine = feminine_group?(scale_idx) || (feminine && scale_idx.zero?)
122
+ group_words = triple_to_words(group_value, scale_idx, feminine: group_feminine)
123
+ words.concat group_words
124
+ end
125
+
126
+ words.unshift(minus_word) if negative
127
+ words.join(" ")
128
+ end
129
+
130
+ def pluralize(number, singular, few, plural)
131
+ number = number.abs
132
+ return plural if (11..14).include?(number % 100)
133
+
134
+ case number % 10
135
+ when 1 then singular
136
+ when 2..4 then few
137
+ else plural
138
+ end
139
+ end
23
140
  end
24
141
 
25
142
  register :hr, HR
@@ -20,6 +20,117 @@ module Num2words
20
20
  DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :hu)
21
21
 
22
22
  ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :hu)
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 ? "és" : 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
+ "vessző"
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
+ ordinal(day, :default)
64
+ end
65
+
66
+ def date_year(year, format:)
67
+ cardinal(year)
68
+ end
69
+
70
+ def ordinal(value, format, gender: :masculine)
71
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
72
+ gender_data = ordinals[gender] || ordinals[:masculine]
73
+
74
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
75
+
76
+ cardinal(value)
77
+ end
78
+
79
+ def cardinal(number)
80
+ integer_value = Integer(number)
81
+ negative = integer_value.negative?
82
+ integer_value = integer_value.abs
83
+
84
+ return ONES_MASC[0] if integer_value.zero?
85
+
86
+ groups = integer_value.to_s
87
+ .chars.reverse.each_slice(3).map(&:reverse)
88
+ .map(&:join).map!(&:to_i).reverse
89
+
90
+ words = []
91
+ groups.each_with_index do |group_value, index|
92
+ next if group_value.zero?
93
+
94
+ scale_idx = groups.size - index - 1
95
+ words.concat triple_to_words(group_value, scale_idx)
96
+ end
97
+
98
+ words.unshift(minus_word) if negative
99
+ words.join(" ")
100
+ end
101
+
102
+ def under_thousand(number)
103
+ return under_hundred(number) if number < 100
104
+
105
+ hundreds = number / 100
106
+ rest = number % 100
107
+ words = [HUNDREDS[hundreds]]
108
+ words << under_hundred(rest) if rest.positive?
109
+ words.join
110
+ end
111
+
112
+ def under_hundred(number)
113
+ return ONES_MASC[number] if number < 10
114
+ return TEENS[number - 10] if number < 20
115
+
116
+ tens = number / 10
117
+ ones = number % 10
118
+ return TENS[tens] if ones.zero?
119
+
120
+ "#{tens_stem(tens)}#{ONES_MASC[ones]}"
121
+ end
122
+
123
+ def tens_stem(tens)
124
+ case tens
125
+ when 2 then "huszon"
126
+ when 3 then "harminc"
127
+ else TENS[tens]
128
+ end
129
+ end
130
+
131
+ def pluralize(_number, singular, _few, _plural)
132
+ singular
133
+ end
23
134
  end
24
135
 
25
136
  register :hu, HU
@@ -20,6 +20,110 @@ module Num2words
20
20
  DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :id)
21
21
 
22
22
  ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :id)
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 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 == 1 ? "seratus" : "#{ONES_MASC[hundreds]} ratus"]
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 = ["#{ONES_MASC[tens]} puluh"]
120
+ words << ONES_MASC[ones] if ones.positive?
121
+ words.join(" ")
122
+ end
123
+
124
+ def pluralize(_number, singular, _few, _plural)
125
+ singular
126
+ end
23
127
  end
24
128
 
25
129
  register :id, ID
@@ -20,6 +20,148 @@ module Num2words
20
20
  DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :it)
21
21
 
22
22
  ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :it)
23
+
24
+ FEMININE_MAJOR_CURRENCIES = %i[GBP TRY UAH CZK SEK NOK DKK INR IDR PKR].freeze
25
+
26
+ module_function
27
+
28
+ def integer_to_words(number, feminine: false)
29
+ cardinal(number, feminine: feminine)
30
+ end
31
+
32
+ def triple_to_words(number, scale_idx, feminine: false)
33
+ return [] if number.zero?
34
+
35
+ words = []
36
+
37
+ if scale_idx == 1
38
+ return [SCALES[1][0]] if number == 1
39
+
40
+ words << under_thousand(number, feminine: feminine)
41
+ words << SCALES[1][1]
42
+ elsif scale_idx.positive?
43
+ words << (number == 1 ? "un" : under_thousand(number, feminine: feminine))
44
+ words << pluralize(number, *SCALES[scale_idx])
45
+ else
46
+ words << under_thousand(number, feminine: feminine)
47
+ end
48
+
49
+ words
50
+ end
51
+
52
+ def minus_word
53
+ GRAMMAR[:minus]
54
+ end
55
+
56
+ def fraction_joiner(joiner)
57
+ joiner.to_sym == :and ? "e" : GRAMMAR[:conjunction]
58
+ end
59
+
60
+ def default_fraction_word
61
+ GRAMMAR[:default_fraction]
62
+ end
63
+
64
+ def fraction_numerator_feminine?
65
+ false
66
+ end
67
+
68
+ def decimal_separator_word
69
+ GRAMMAR[:conjunction]
70
+ end
71
+
72
+ def decimal_fraction_words(fraction_string)
73
+ fraction_string.chars.map { |digit| cardinal(digit.to_i) }.join(" ")
74
+ end
75
+
76
+ def time_unit_feminine?(unit)
77
+ unit == :hour
78
+ end
79
+
80
+ def currency_major_feminine?(currency)
81
+ FEMININE_MAJOR_CURRENCIES.include?(currency)
82
+ end
83
+
84
+ def currency_minor_feminine?(_currency)
85
+ false
86
+ end
87
+
88
+ def currency_number_words(number, currency, unit:)
89
+ feminine = unit == :major ? currency_major_feminine?(currency) : currency_minor_feminine?(currency)
90
+
91
+ cardinal(number, feminine: feminine)
92
+ end
93
+
94
+ def date_day(day, format:, date_case:)
95
+ cardinal(day)
96
+ end
97
+
98
+ def date_year(year, format:)
99
+ cardinal(year)
100
+ end
101
+
102
+ def ordinal(value, format, gender: :masculine)
103
+ ordinals = ORDINALS[format] || ORDINALS[:default] || ORDINALS[:nominative]
104
+ gender_data = ordinals[gender] || ordinals[:masculine]
105
+
106
+ return gender_data[value - 1] if value.between?(1, gender_data.length)
107
+
108
+ cardinal(value)
109
+ end
110
+
111
+ def cardinal(number, feminine: false)
112
+ integer_value = Integer(number)
113
+ negative = integer_value.negative?
114
+ integer_value = integer_value.abs
115
+
116
+ return ONES_MASC[0] if integer_value.zero?
117
+
118
+ groups = integer_value.to_s
119
+ .chars.reverse.each_slice(3).map(&:reverse)
120
+ .map(&:join).map!(&:to_i).reverse
121
+
122
+ words = []
123
+ groups.each_with_index do |group_value, index|
124
+ next if group_value.zero?
125
+
126
+ scale_idx = groups.size - index - 1
127
+ words.concat triple_to_words(group_value, scale_idx, feminine: feminine)
128
+ end
129
+
130
+ words.unshift(minus_word) if negative
131
+ words.join(" ")
132
+ end
133
+
134
+ def under_thousand(number, feminine: false)
135
+ return under_hundred(number, feminine: feminine) if number < 100
136
+
137
+ hundreds = number / 100
138
+ rest = number % 100
139
+ hundred_word = HUNDREDS[hundreds]
140
+ hundred_word = hundred_word[0...-1] if rest.between?(80, 89)
141
+
142
+ return hundred_word if rest.zero?
143
+
144
+ "#{hundred_word}#{under_hundred(rest, feminine: feminine)}"
145
+ end
146
+
147
+ def under_hundred(number, feminine: false)
148
+ ones_data = feminine ? ONES_FEM : ONES_MASC
149
+
150
+ return ones_data[number] if number < 10
151
+ return TEENS[number - 10] if number < 20
152
+
153
+ tens = number / 10
154
+ ones = number % 10
155
+ return TENS[tens] if ones.zero?
156
+
157
+ tens_word = TENS[tens]
158
+ tens_word = tens_word[0...-1] if [1, 8].include?(ones)
159
+ "#{tens_word}#{ones_data[ones]}"
160
+ end
161
+
162
+ def pluralize(number, singular, _few, plural)
163
+ number.abs == 1 ? singular : plural
164
+ end
23
165
  end
24
166
 
25
167
  register :it, IT
@@ -20,6 +20,132 @@ module Num2words
20
20
  DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :ja)
21
21
 
22
22
  ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :ja)
23
+
24
+ THOUSANDS = ["", "せん", "にせん", "さんぜん", "よんせん", "ごせん", "ろくせん", "ななせん", "はっせん", "きゅうせん"].freeze
25
+ LARGE_SCALES = ["", "まん", "おく", "ちょう", "けい"].freeze
26
+
27
+ class << self
28
+ def integer_to_words(number, feminine: false)
29
+ integer_value = Integer(number)
30
+ negative = integer_value.negative?
31
+ integer_value = integer_value.abs
32
+
33
+ return ONES_MASC[0] if integer_value.zero?
34
+
35
+ groups = integer_value.to_s
36
+ .chars.reverse.each_slice(4).map(&:reverse)
37
+ .map(&:join).map!(&:to_i).reverse
38
+
39
+ words = groups.each_with_index.filter_map do |group_value, index|
40
+ next if group_value.zero?
41
+
42
+ scale_index = groups.size - index - 1
43
+ "#{under_ten_thousand(group_value)}#{LARGE_SCALES.fetch(scale_index, '')}"
44
+ end.join
45
+
46
+ negative ? "#{minus_word}#{words}" : words
47
+ end
48
+
49
+ def triple_to_words(number, scale_idx, feminine: false)
50
+ words = under_ten_thousand(number)
51
+ scale = LARGE_SCALES[scale_idx].to_s
52
+ ["#{words}#{scale}"]
53
+ end
54
+
55
+ def minus_word
56
+ GRAMMAR[:minus]
57
+ end
58
+
59
+ def fraction_joiner(joiner)
60
+ joiner.to_sym == :and ? "と" : GRAMMAR[:conjunction]
61
+ end
62
+
63
+ def default_fraction_word
64
+ GRAMMAR[:default_fraction]
65
+ end
66
+
67
+ def decimal_separator_word
68
+ GRAMMAR[:decimal_separator] || "てん"
69
+ end
70
+
71
+ def decimal_fraction_words(fraction_string)
72
+ fraction_string.chars.map { |digit| ONES_MASC[digit.to_i] }.join
73
+ end
74
+
75
+ def join_decimal_words(words)
76
+ words.compact.reject(&:empty?).join
77
+ end
78
+
79
+ def join_fraction_words(words)
80
+ sign_word, integer_words, conjunction_word, numerator_words, denominator_words = words
81
+ numerator_words = "" if denominator_words.to_s.end_with?(numerator_words.to_s)
82
+
83
+ [sign_word, integer_words, conjunction_word, denominator_words, numerator_words].compact.reject(&:empty?).join
84
+ end
85
+
86
+ def pluralize(number, singular, few, _plural)
87
+ number == 1 ? singular : few
88
+ end
89
+
90
+ def currency_major_feminine?(_currency)
91
+ false
92
+ end
93
+
94
+ def currency_minor_feminine?(_currency)
95
+ false
96
+ end
97
+
98
+ def currency_number_words(number, _currency, unit:)
99
+ integer_to_words(number)
100
+ end
101
+
102
+ def join_currency_parts(parts)
103
+ parts.join
104
+ end
105
+
106
+ def time_unit_feminine?(_unit)
107
+ false
108
+ end
109
+
110
+ def time_number_words(number, unit:)
111
+ integer_to_words(number)
112
+ end
113
+
114
+ def join_time_words(number_words, unit_words)
115
+ "#{number_words}#{unit_words}"
116
+ end
117
+
118
+ def date_day(day, format: :default, date_case: :default)
119
+ integer_to_words(day)
120
+ end
121
+
122
+ def date_year(year, format: :default)
123
+ integer_to_words(year)
124
+ end
125
+
126
+ def under_ten_thousand(number)
127
+ thousands = number / 1000
128
+ remainder = number % 1000
129
+ hundreds = remainder / 100
130
+ rest = remainder % 100
131
+
132
+ [
133
+ THOUSANDS[thousands],
134
+ HUNDREDS[hundreds],
135
+ under_hundred(rest)
136
+ ].compact.reject(&:empty?).join
137
+ end
138
+
139
+ def under_hundred(number)
140
+ return "" if number.zero?
141
+ return TEENS[number - 10] if number.between?(10, 19)
142
+
143
+ tens = number / 10
144
+ ones = number % 10
145
+
146
+ [TENS[tens], ones.positive? ? ONES_MASC[ones] : nil].compact.reject(&:empty?).join
147
+ end
148
+ end
23
149
  end
24
150
 
25
151
  register :ja, JA