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
@@ -0,0 +1,153 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Num2words
4
+ module Locales
5
+ module NB
6
+ ONES_MASC = I18n.t("num2words.ones_masc", locale: :nb)
7
+ ONES_FEM = I18n.t("num2words.ones_fem", locale: :nb)
8
+ TEENS = I18n.t("num2words.teens", locale: :nb)
9
+ TENS = I18n.t("num2words.tens", locale: :nb)
10
+ HUNDREDS = I18n.t("num2words.hundreds", locale: :nb)
11
+ SCALES = I18n.t("num2words.scales", locale: :nb)
12
+
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :nb)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :nb)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :nb)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :nb)
18
+ TIME = I18n.t("num2words.time", locale: :nb)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :nb)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :nb)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :nb)
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 = triple_words(number, feminine: feminine)
34
+ words[0] = "ett" if 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 ? "og" : 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
+ ordinal(day, :nominative)
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, feminine: false)
101
+ integer_value = Integer(number)
102
+ negative = integer_value.negative?
103
+ integer_value = integer_value.abs
104
+
105
+ return (feminine ? ONES_FEM[0] : 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
+ group_words = triple_to_words(group_value, scale_idx, feminine: feminine && scale_idx.zero?)
117
+ group_words.unshift("og") if scale_idx.zero? && words.any? && group_value < 100
118
+ words.concat(group_words)
119
+ end
120
+
121
+ words.unshift(minus_word) if negative
122
+ words.join(" ")
123
+ end
124
+
125
+ def triple_words(number, feminine: false)
126
+ return [] if number.zero?
127
+
128
+ hundreds = number / 100
129
+ rest = number % 100
130
+ words = []
131
+
132
+ words << HUNDREDS[hundreds] if hundreds.positive?
133
+ words << "og" if hundreds.positive? && rest.positive?
134
+ words << under_hundred(rest, feminine: feminine) if rest.positive?
135
+ words
136
+ end
137
+
138
+ def under_hundred(number, feminine: false)
139
+ return TEENS[number - 10] if number.between?(10, 19)
140
+ return TENS[number / 10] if number >= 20 && (number % 10).zero?
141
+ return (feminine ? ONES_FEM[number] : ONES_MASC[number]) if number < 10
142
+
143
+ "#{TENS[number / 10]}#{feminine ? ONES_FEM[number % 10] : ONES_MASC[number % 10]}"
144
+ end
145
+
146
+ def pluralize(number, singular, few, plural)
147
+ number.abs == 1 ? singular : plural
148
+ end
149
+ end
150
+
151
+ register :nb, NB
152
+ end
153
+ end
@@ -10,8 +10,148 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :nl)
11
11
  SCALES = I18n.t("num2words.scales", locale: :nl)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.EUR.name", locale: :nl)
14
- MINOR_UNIT = I18n.t("num2words.currencies.EUR.fractional.name", locale: :nl)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :nl)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :nl)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :nl)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :nl)
18
+ TIME = I18n.t("num2words.time", locale: :nl)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :nl)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :nl)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :nl)
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 << pluralize(number, *SCALES[scale_idx]) 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 ? "en" : 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
+ ordinal(day, :nominative)
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
+ group_words = triple_to_words(group_value, scale_idx)
116
+ group_words.shift if scale_idx == 1 && group_value == 1
117
+ words.concat(group_words)
118
+ end
119
+
120
+ words.unshift(minus_word) if negative
121
+ words.join(" ")
122
+ end
123
+
124
+ def under_thousand(number)
125
+ return under_hundred(number) if number < 100
126
+
127
+ hundreds = number / 100
128
+ rest = number % 100
129
+ words = [HUNDREDS[hundreds]]
130
+ words << under_hundred(rest) if rest.positive?
131
+ words.join(" ")
132
+ end
133
+
134
+ def under_hundred(number)
135
+ return ONES_MASC[number] if number < 10
136
+ return TEENS[number - 10] if number < 20
137
+ return TENS[number / 10] if (number % 10).zero?
138
+
139
+ ones = compound_ones(number % 10)
140
+ tens = TENS[number / 10]
141
+ "#{ones}#{tens}"
142
+ end
143
+
144
+ def compound_ones(number)
145
+ case number
146
+ when 2 then "tweeën"
147
+ when 3 then "drieën"
148
+ else "#{ONES_MASC[number]}en"
149
+ end
150
+ end
151
+
152
+ def pluralize(number, singular, few, plural)
153
+ number.abs == 1 ? singular : plural
154
+ end
15
155
  end
16
156
 
17
157
  register :nl, NL
@@ -10,8 +10,128 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :pa)
11
11
  SCALES = I18n.t("num2words.scales", locale: :pa)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.INR.name", locale: :pa)
14
- MINOR_UNIT = I18n.t("num2words.currencies.INR.fractional.name", locale: :pa)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :pa)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :pa)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :pa)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :pa)
18
+ TIME = I18n.t("num2words.time", locale: :pa)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :pa)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :pa)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :pa)
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
15
135
  end
16
136
 
17
137
  register :pa, PA
@@ -10,8 +10,155 @@ module Num2words
10
10
  HUNDREDS = I18n.t("num2words.hundreds", locale: :pl)
11
11
  SCALES = I18n.t("num2words.scales", locale: :pl)
12
12
 
13
- MAJOR_UNIT = I18n.t("num2words.currencies.PLN.name", locale: :pl)
14
- MINOR_UNIT = I18n.t("num2words.currencies.PLN.fractional.name", locale: :pl)
13
+ FRACTIONS = I18n.t("num2words.fractions", locale: :pl)
14
+ GRAMMAR = I18n.t("num2words.grammar", locale: :pl)
15
+
16
+ DATE = I18n.t("num2words.date", locale: :pl)
17
+ DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :pl)
18
+ TIME = I18n.t("num2words.time", locale: :pl)
19
+ TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :pl)
20
+ DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :pl)
21
+
22
+ ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :pl)
23
+
24
+ FEMININE_CURRENCIES = %i[BDT CZK DKK IDR INR NOK PKR SEK TRY UAH].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
+ words << HUNDREDS[number / 100] if number >= 100
37
+ rest = number % 100
38
+
39
+ if rest.between?(10, 19)
40
+ words << TEENS[rest - 10]
41
+ else
42
+ words << TENS[rest / 10] if rest >= 20
43
+ ones = rest % 10
44
+ words << (feminine ? ONES_FEM[ones] : ONES_MASC[ones]) if ones.positive?
45
+ end
46
+
47
+ words << pluralize(number, *SCALES[scale_idx]) unless scale_idx.zero?
48
+ words.compact
49
+ end
50
+
51
+ def minus_word
52
+ GRAMMAR[:minus]
53
+ end
54
+
55
+ def fraction_joiner(joiner)
56
+ joiner.to_sym == :and ? "i" : 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
+ "przecinek"
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 date_day(day, format:, date_case:)
76
+ ordinal(day, :default)
77
+ end
78
+
79
+ def date_year(year, format:)
80
+ return ordinal(year, :default) if year <= 31
81
+
82
+ thousands = year / 1000
83
+ rest = year % 1000
84
+ words = [cardinal(thousands), pluralize(thousands, *SCALES[1])]
85
+ words << ordinal(rest, :default) if rest.positive?
86
+ words.join(" ")
87
+ end
88
+
89
+ def time_unit_feminine?(_unit)
90
+ true
91
+ end
92
+
93
+ def time_number_words(number, unit:)
94
+ cardinal(number, feminine: true)
95
+ end
96
+
97
+ def currency_major_feminine?(currency)
98
+ FEMININE_CURRENCIES.include?(currency)
99
+ end
100
+
101
+ def currency_minor_feminine?(currency)
102
+ %i[BGN BYN RUB UAH].include?(currency)
103
+ end
104
+
105
+ def currency_number_words(number, currency, unit:)
106
+ feminine = unit == :major ? currency_major_feminine?(currency) : currency_minor_feminine?(currency)
107
+ cardinal(number, feminine: feminine)
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
+ ordinal_compound(value, gender: gender)
117
+ end
118
+
119
+ def cardinal(number, feminine: false)
120
+ integer_value = Integer(number)
121
+ negative = integer_value.negative?
122
+ integer_value = integer_value.abs
123
+
124
+ return (feminine ? ONES_FEM[0] : ONES_MASC[0]) if integer_value.zero?
125
+
126
+ groups = integer_value.to_s
127
+ .chars.reverse.each_slice(3).map(&:reverse)
128
+ .map(&:join).map!(&:to_i).reverse
129
+
130
+ words = []
131
+ groups.each_with_index do |group_value, index|
132
+ next if group_value.zero?
133
+
134
+ scale_idx = groups.size - index - 1
135
+ group_words = triple_to_words(group_value, scale_idx, feminine: feminine && scale_idx.zero?)
136
+ group_words.shift if scale_idx == 1 && group_value == 1
137
+ words.concat(group_words)
138
+ end
139
+
140
+ words.unshift(minus_word) if negative
141
+ words.join(" ")
142
+ end
143
+
144
+ def ordinal_compound(value, gender:)
145
+ base = value - (value % 100)
146
+ rest = value % 100
147
+ return cardinal(value) if rest.zero?
148
+
149
+ [cardinal(base), ordinal(rest, :default, gender: gender)].join(" ")
150
+ end
151
+
152
+ def pluralize(number, singular, few, plural)
153
+ number = number.abs
154
+ return plural if (11..14).include?(number % 100)
155
+
156
+ case number % 10
157
+ when 1 then number == 1 ? singular : plural
158
+ when 2..4 then few
159
+ else plural
160
+ end
161
+ end
15
162
  end
16
163
 
17
164
  register :pl, PL