num2words 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/README.md +113 -144
- data/config/locales/ar.yml +5 -1
- data/config/locales/be.yml +4 -0
- data/config/locales/bg.yml +4 -0
- data/config/locales/bn.yml +4 -0
- data/config/locales/cs.yml +6 -2
- data/config/locales/da.yml +4 -0
- data/config/locales/de.yml +8 -4
- data/config/locales/el.yml +4 -0
- data/config/locales/en.yml +4 -0
- data/config/locales/es.yml +4 -0
- data/config/locales/et.yml +9 -5
- data/config/locales/fa.yml +15 -11
- data/config/locales/fi.yml +8 -4
- data/config/locales/fr.yml +4 -0
- data/config/locales/gu.yml +4 -0
- data/config/locales/he.yml +6 -2
- data/config/locales/hi.yml +4 -0
- data/config/locales/hr.yml +8 -4
- data/config/locales/hu.yml +6 -2
- data/config/locales/id.yml +4 -0
- data/config/locales/it.yml +4 -0
- data/config/locales/ja.yml +10 -5
- data/config/locales/kn.yml +186 -10
- data/config/locales/ko.yml +184 -13
- data/config/locales/kz.yml +183 -17
- data/config/locales/lt.yml +184 -8
- data/config/locales/lv.yml +188 -12
- data/config/locales/ml.yml +189 -13
- data/config/locales/mr.yml +184 -8
- data/config/locales/ms.yml +184 -8
- data/config/locales/nb.yml +183 -17
- data/config/locales/nl.yml +184 -13
- data/config/locales/pa.yml +189 -13
- data/config/locales/pl.yml +184 -13
- data/config/locales/pt.yml +184 -13
- data/config/locales/ro.yml +183 -12
- data/config/locales/ru.yml +4 -0
- data/config/locales/sk.yml +184 -8
- data/config/locales/sl.yml +185 -9
- data/config/locales/sr.yml +186 -15
- data/config/locales/sv.yml +182 -13
- data/config/locales/sw.yml +184 -8
- data/config/locales/ta.yml +184 -8
- data/config/locales/te.yml +185 -9
- data/config/locales/th.yml +183 -12
- data/config/locales/tr.yml +183 -12
- data/config/locales/uk.yml +189 -18
- data/config/locales/ur.yml +187 -11
- data/config/locales/vi.yml +183 -12
- data/config/locales/zh.yml +191 -9
- data/lib/num2words/converter.rb +144 -35
- data/lib/num2words/locales/ar.rb +130 -0
- data/lib/num2words/locales/be.rb +101 -0
- data/lib/num2words/locales/bg.rb +127 -0
- data/lib/num2words/locales/bn.rb +112 -0
- data/lib/num2words/locales/cs.rb +106 -0
- data/lib/num2words/locales/da.rb +97 -0
- data/lib/num2words/locales/de.rb +119 -0
- data/lib/num2words/locales/el.rb +143 -0
- data/lib/num2words/locales/en.rb +90 -0
- data/lib/num2words/locales/es.rb +185 -0
- data/lib/num2words/locales/et.rb +104 -0
- data/lib/num2words/locales/fa.rb +104 -0
- data/lib/num2words/locales/fi.rb +104 -0
- data/lib/num2words/locales/fr.rb +121 -0
- data/lib/num2words/locales/gu.rb +112 -0
- data/lib/num2words/locales/he.rb +130 -0
- data/lib/num2words/locales/hi.rb +112 -0
- data/lib/num2words/locales/hr.rb +117 -0
- data/lib/num2words/locales/hu.rb +111 -0
- data/lib/num2words/locales/id.rb +104 -0
- data/lib/num2words/locales/it.rb +142 -0
- data/lib/num2words/locales/ja.rb +126 -0
- data/lib/num2words/locales/kn.rb +122 -2
- data/lib/num2words/locales/ko.rb +158 -2
- data/lib/num2words/locales/kz.rb +137 -2
- data/lib/num2words/locales/lt.rb +146 -2
- data/lib/num2words/locales/lv.rb +148 -2
- data/lib/num2words/locales/ml.rb +142 -2
- data/lib/num2words/locales/mr.rb +142 -2
- data/lib/num2words/locales/ms.rb +134 -2
- data/lib/num2words/locales/nb.rb +153 -0
- data/lib/num2words/locales/nl.rb +142 -2
- data/lib/num2words/locales/pa.rb +122 -2
- data/lib/num2words/locales/pl.rb +149 -2
- data/lib/num2words/locales/pt.rb +164 -2
- data/lib/num2words/locales/ro.rb +165 -2
- data/lib/num2words/locales/ru.rb +100 -0
- data/lib/num2words/locales/sk.rb +124 -2
- data/lib/num2words/locales/sl.rb +154 -2
- data/lib/num2words/locales/sr.rb +141 -3
- data/lib/num2words/locales/sv.rb +141 -2
- data/lib/num2words/locales/sw.rb +133 -2
- data/lib/num2words/locales/ta.rb +142 -2
- data/lib/num2words/locales/te.rb +142 -2
- data/lib/num2words/locales/th.rb +133 -2
- data/lib/num2words/locales/tr.rb +141 -2
- data/lib/num2words/locales/uk.rb +134 -2
- data/lib/num2words/locales/ur.rb +130 -2
- data/lib/num2words/locales/vi.rb +142 -2
- data/lib/num2words/locales/zh.rb +172 -2
- data/lib/num2words/version.rb +1 -1
- data/num2words.gemspec +2 -2
- metadata +6 -6
- data/lib/num2words/locales/no.rb +0 -19
data/lib/num2words/locales/zh.rb
CHANGED
|
@@ -10,8 +10,178 @@ module Num2words
|
|
|
10
10
|
HUNDREDS = I18n.t("num2words.hundreds", locale: :zh)
|
|
11
11
|
SCALES = I18n.t("num2words.scales", locale: :zh)
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
FRACTIONS = I18n.t("num2words.fractions", locale: :zh)
|
|
14
|
+
GRAMMAR = I18n.t("num2words.grammar", locale: :zh)
|
|
15
|
+
|
|
16
|
+
DATE = I18n.t("num2words.date", locale: :zh)
|
|
17
|
+
DATE_TEMPLATE = I18n.t("num2words.date.template", locale: :zh)
|
|
18
|
+
TIME = I18n.t("num2words.time", locale: :zh)
|
|
19
|
+
TIME_TEMPLATE = I18n.t("num2words.time.template", locale: :zh)
|
|
20
|
+
DATETIME_TEMPLATE = I18n.t("num2words.datetime.template", locale: :zh)
|
|
21
|
+
|
|
22
|
+
ORDINALS = I18n.t("num2words.numbers.ordinals", locale: :zh)
|
|
23
|
+
|
|
24
|
+
LARGE_SCALES = ["", "万", "亿", "兆", "京"].freeze
|
|
25
|
+
SMALL_UNITS = ["", "十", "百", "千"].freeze
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
def integer_to_words(number, feminine: false)
|
|
30
|
+
cardinal(number)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def triple_to_words(number, scale_idx, feminine: false)
|
|
34
|
+
return [] if number.zero?
|
|
35
|
+
|
|
36
|
+
["#{under_ten_thousand(number)}#{LARGE_SCALES[scale_idx]}"]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def minus_word
|
|
40
|
+
GRAMMAR[:minus]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def fraction_joiner(joiner)
|
|
44
|
+
joiner.to_sym == :and ? "又" : 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[:decimal_separator] || "点"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def decimal_fraction_words(fraction_string)
|
|
60
|
+
fraction_string.chars.map { |digit| ONES_MASC[digit.to_i] }.join
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def join_decimal_words(words)
|
|
64
|
+
words.compact.reject(&:empty?).join
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def join_fraction_words(words)
|
|
68
|
+
sign_word, integer_words, conjunction_word, numerator_words, denominator_words = words
|
|
69
|
+
numerator_words = "" if denominator_words.to_s.end_with?(numerator_words.to_s)
|
|
70
|
+
|
|
71
|
+
[sign_word, integer_words, conjunction_word, denominator_words, numerator_words].compact.reject(&:empty?).join
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def date_day(day, format:, date_case:)
|
|
75
|
+
cardinal(day)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def date_year(year, format:)
|
|
79
|
+
cardinal(year)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def time_unit_feminine?(_unit)
|
|
83
|
+
false
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def time_number_words(number, unit:)
|
|
87
|
+
cardinal(number)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def join_time_words(number_words, unit_words)
|
|
91
|
+
"#{number_words}#{unit_words}"
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def currency_major_feminine?(_currency)
|
|
95
|
+
false
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def currency_minor_feminine?(_currency)
|
|
99
|
+
false
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def currency_number_words(number, _currency, unit:)
|
|
103
|
+
cardinal(number)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def join_currency_parts(parts)
|
|
107
|
+
parts.join
|
|
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 ONES_MASC[0] if integer_value.zero?
|
|
125
|
+
|
|
126
|
+
groups = integer_value.to_s
|
|
127
|
+
.chars.reverse.each_slice(4).map(&:reverse)
|
|
128
|
+
.map(&:join).map!(&:to_i).reverse
|
|
129
|
+
|
|
130
|
+
words = []
|
|
131
|
+
zero_between = false
|
|
132
|
+
|
|
133
|
+
groups.each_with_index do |group_value, index|
|
|
134
|
+
scale_idx = groups.size - index - 1
|
|
135
|
+
|
|
136
|
+
if group_value.zero?
|
|
137
|
+
zero_between = words.any?
|
|
138
|
+
next
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
words << ONES_MASC[0] if words.any? && (zero_between || group_value < 1000) && words.last != ONES_MASC[0]
|
|
142
|
+
words << "#{under_ten_thousand(group_value)}#{LARGE_SCALES.fetch(scale_idx, '')}"
|
|
143
|
+
zero_between = false
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
words.unshift(minus_word) if negative
|
|
147
|
+
words.join
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def under_ten_thousand(number)
|
|
151
|
+
digits = number.digits
|
|
152
|
+
words = []
|
|
153
|
+
zero_needed = false
|
|
154
|
+
|
|
155
|
+
(3).downto(0) do |position|
|
|
156
|
+
digit = digits[position].to_i
|
|
157
|
+
|
|
158
|
+
if digit.zero?
|
|
159
|
+
zero_needed = words.any? && lower_nonzero?(digits, position)
|
|
160
|
+
next
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
words << ONES_MASC[0] if zero_needed
|
|
164
|
+
words << unit_words(digit, position, words.empty?)
|
|
165
|
+
zero_needed = false
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
words.join
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def unit_words(digit, position, group_start)
|
|
172
|
+
return ONES_MASC[digit] if position.zero?
|
|
173
|
+
return SMALL_UNITS[position] if position == 1 && digit == 1 && group_start
|
|
174
|
+
|
|
175
|
+
"#{ONES_MASC[digit]}#{SMALL_UNITS[position]}"
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def lower_nonzero?(digits, position)
|
|
179
|
+
(0...position).any? { |lower_position| digits[lower_position].to_i.positive? }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def pluralize(number, singular, few, _plural)
|
|
183
|
+
number == 1 ? singular : few
|
|
184
|
+
end
|
|
15
185
|
end
|
|
16
186
|
|
|
17
187
|
register :zh, ZH
|
data/lib/num2words/version.rb
CHANGED
data/num2words.gemspec
CHANGED
|
@@ -6,8 +6,8 @@ Gem::Specification.new do |spec|
|
|
|
6
6
|
spec.authors = ["Ruslan Fedotov"]
|
|
7
7
|
spec.email = ["progruson@gmail.com"]
|
|
8
8
|
|
|
9
|
-
spec.summary = %q{
|
|
10
|
-
spec.description = %q{Converts
|
|
9
|
+
spec.summary = %q{Convert numbers, amounts, dates, and times to words}
|
|
10
|
+
spec.description = %q{Converts numbers, currency amounts, dates, and times to words with locale-aware grammar across supported locales.}
|
|
11
11
|
spec.homepage = "https://github.com/skyrusx/num2words"
|
|
12
12
|
spec.license = "MIT"
|
|
13
13
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: num2words
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ruslan Fedotov
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-06-27 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: i18n
|
|
@@ -24,8 +24,8 @@ dependencies:
|
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '1.8'
|
|
27
|
-
description: Converts
|
|
28
|
-
|
|
27
|
+
description: Converts numbers, currency amounts, dates, and times to words with locale-aware
|
|
28
|
+
grammar across supported locales.
|
|
29
29
|
email:
|
|
30
30
|
- progruson@gmail.com
|
|
31
31
|
executables:
|
|
@@ -129,8 +129,8 @@ files:
|
|
|
129
129
|
- lib/num2words/locales/ml.rb
|
|
130
130
|
- lib/num2words/locales/mr.rb
|
|
131
131
|
- lib/num2words/locales/ms.rb
|
|
132
|
+
- lib/num2words/locales/nb.rb
|
|
132
133
|
- lib/num2words/locales/nl.rb
|
|
133
|
-
- lib/num2words/locales/no.rb
|
|
134
134
|
- lib/num2words/locales/pa.rb
|
|
135
135
|
- lib/num2words/locales/pl.rb
|
|
136
136
|
- lib/num2words/locales/pt.rb
|
|
@@ -176,5 +176,5 @@ requirements: []
|
|
|
176
176
|
rubygems_version: 3.1.2
|
|
177
177
|
signing_key:
|
|
178
178
|
specification_version: 4
|
|
179
|
-
summary:
|
|
179
|
+
summary: Convert numbers, amounts, dates, and times to words
|
|
180
180
|
test_files: []
|
data/lib/num2words/locales/no.rb
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
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
|
-
MAJOR_UNIT = I18n.t("num2words.currencies.NOK.name", locale: :nb)
|
|
14
|
-
MINOR_UNIT = I18n.t("num2words.currencies.NOK.fractional.name", locale: :nb)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
register :nb, NB
|
|
18
|
-
end
|
|
19
|
-
end
|