num2words2 0.1.0.dev1__py3-none-any.whl
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.
- num2words2/README.md +69 -0
- num2words2/__init__.py +196 -0
- num2words2/_version.py +3 -0
- num2words2/base.py +377 -0
- num2words2/compat.py +29 -0
- num2words2/currency.py +60 -0
- num2words2/lang_AF.py +202 -0
- num2words2/lang_AM.py +193 -0
- num2words2/lang_AR.py +435 -0
- num2words2/lang_AS.py +119 -0
- num2words2/lang_AZ.py +208 -0
- num2words2/lang_BA.py +119 -0
- num2words2/lang_BE.py +356 -0
- num2words2/lang_BG.py +393 -0
- num2words2/lang_BN.py +242 -0
- num2words2/lang_BO.py +122 -0
- num2words2/lang_BR.py +135 -0
- num2words2/lang_BS.py +189 -0
- num2words2/lang_CA.py +476 -0
- num2words2/lang_CE.py +546 -0
- num2words2/lang_CS.py +260 -0
- num2words2/lang_CY.py +574 -0
- num2words2/lang_DA.py +170 -0
- num2words2/lang_DE.py +180 -0
- num2words2/lang_EL.py +338 -0
- num2words2/lang_EN.py +118 -0
- num2words2/lang_EN_IN.py +26 -0
- num2words2/lang_EN_NG.py +45 -0
- num2words2/lang_EO.py +130 -0
- num2words2/lang_ES.py +399 -0
- num2words2/lang_ES_CO.py +37 -0
- num2words2/lang_ES_CR.py +38 -0
- num2words2/lang_ES_GT.py +37 -0
- num2words2/lang_ES_NI.py +35 -0
- num2words2/lang_ES_VE.py +43 -0
- num2words2/lang_ET.py +393 -0
- num2words2/lang_EU.py +158 -0
- num2words2/lang_EUR.py +104 -0
- num2words2/lang_FA.py +187 -0
- num2words2/lang_FI.py +759 -0
- num2words2/lang_FO.py +136 -0
- num2words2/lang_FR.py +133 -0
- num2words2/lang_FR_BE.py +49 -0
- num2words2/lang_FR_CH.py +48 -0
- num2words2/lang_FR_DZ.py +35 -0
- num2words2/lang_GL.py +135 -0
- num2words2/lang_GU.py +172 -0
- num2words2/lang_HA.py +293 -0
- num2words2/lang_HAW.py +144 -0
- num2words2/lang_HE.py +314 -0
- num2words2/lang_HI.py +243 -0
- num2words2/lang_HR.py +304 -0
- num2words2/lang_HT.py +136 -0
- num2words2/lang_HU.py +189 -0
- num2words2/lang_HY.py +364 -0
- num2words2/lang_ID.py +242 -0
- num2words2/lang_IS.py +208 -0
- num2words2/lang_IT.py +265 -0
- num2words2/lang_JA.py +615 -0
- num2words2/lang_JW.py +136 -0
- num2words2/lang_KA.py +169 -0
- num2words2/lang_KK.py +136 -0
- num2words2/lang_KM.py +173 -0
- num2words2/lang_KN.py +182 -0
- num2words2/lang_KO.py +175 -0
- num2words2/lang_KZ.py +161 -0
- num2words2/lang_LA.py +135 -0
- num2words2/lang_LB.py +135 -0
- num2words2/lang_LN.py +136 -0
- num2words2/lang_LO.py +149 -0
- num2words2/lang_LT.py +283 -0
- num2words2/lang_LV.py +266 -0
- num2words2/lang_MG.py +143 -0
- num2words2/lang_MI.py +151 -0
- num2words2/lang_MK.py +136 -0
- num2words2/lang_ML.py +159 -0
- num2words2/lang_MN.py +319 -0
- num2words2/lang_MR.py +187 -0
- num2words2/lang_MS.py +293 -0
- num2words2/lang_MT.py +159 -0
- num2words2/lang_MY.py +152 -0
- num2words2/lang_NE.py +157 -0
- num2words2/lang_NL.py +204 -0
- num2words2/lang_NN.py +136 -0
- num2words2/lang_NO.py +143 -0
- num2words2/lang_OC.py +135 -0
- num2words2/lang_PA.py +159 -0
- num2words2/lang_PL.py +336 -0
- num2words2/lang_PS.py +136 -0
- num2words2/lang_PT.py +280 -0
- num2words2/lang_PT_BR.py +224 -0
- num2words2/lang_RO.py +183 -0
- num2words2/lang_RU.py +570 -0
- num2words2/lang_SA.py +136 -0
- num2words2/lang_SD.py +136 -0
- num2words2/lang_SI.py +152 -0
- num2words2/lang_SK.py +250 -0
- num2words2/lang_SL.py +306 -0
- num2words2/lang_SN.py +447 -0
- num2words2/lang_SO.py +136 -0
- num2words2/lang_SQ.py +252 -0
- num2words2/lang_SR.py +254 -0
- num2words2/lang_SU.py +136 -0
- num2words2/lang_SV.py +169 -0
- num2words2/lang_SW.py +219 -0
- num2words2/lang_TA.py +303 -0
- num2words2/lang_TE.py +169 -0
- num2words2/lang_TET.py +285 -0
- num2words2/lang_TG.py +149 -0
- num2words2/lang_TH.py +214 -0
- num2words2/lang_TK.py +136 -0
- num2words2/lang_TL.py +145 -0
- num2words2/lang_TR.py +882 -0
- num2words2/lang_TT.py +136 -0
- num2words2/lang_UK.py +1101 -0
- num2words2/lang_UR.py +168 -0
- num2words2/lang_UZ.py +136 -0
- num2words2/lang_VI.py +143 -0
- num2words2/lang_WO.py +136 -0
- num2words2/lang_YI.py +135 -0
- num2words2/lang_YO.py +136 -0
- num2words2/lang_ZH.py +296 -0
- num2words2/lang_ZH_CN.py +85 -0
- num2words2/lang_ZH_HK.py +48 -0
- num2words2/lang_ZH_TW.py +198 -0
- num2words2/utils.py +35 -0
- num2words2-0.1.0.dev1.data/scripts/num2words2 +98 -0
- num2words2-0.1.0.dev1.dist-info/METADATA +244 -0
- num2words2-0.1.0.dev1.dist-info/RECORD +133 -0
- num2words2-0.1.0.dev1.dist-info/WHEEL +5 -0
- num2words2-0.1.0.dev1.dist-info/entry_points.txt +2 -0
- num2words2-0.1.0.dev1.dist-info/licenses/COPYING +145 -0
- num2words2-0.1.0.dev1.dist-info/top_level.txt +1 -0
num2words2/lang_OC.py
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
|
3
|
+
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
+
# Lesser General Public License for more details.
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
16
|
+
# MA 02110-1301 USA
|
|
17
|
+
|
|
18
|
+
from __future__ import unicode_literals
|
|
19
|
+
|
|
20
|
+
from .base import Num2Word_Base
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Occitan language support
|
|
24
|
+
class Num2Word_OC(Num2Word_Base):
|
|
25
|
+
CURRENCY_FORMS = {
|
|
26
|
+
'EUR': (('èuro', 'èuros'), ('centim', 'centims')),
|
|
27
|
+
'USD': (('dollar', 'dollars'), ('cent', 'cents'))
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def setup(self):
|
|
31
|
+
self.negword = "minus "
|
|
32
|
+
self.pointword = "point"
|
|
33
|
+
self.ones = ['', 'un', 'dos', 'tres', 'quatre', 'cinc', 'sièis', 'sèt', 'uèch', 'nòu']
|
|
34
|
+
self.tens = ['', 'dètz', 'vint', 'trenta', 'quaranta', 'cinquanta', 'seissanta', 'setanta', 'ochanta', 'nonanta']
|
|
35
|
+
self.hundred = "cent"
|
|
36
|
+
self.thousand = "mil"
|
|
37
|
+
self.million = "milion"
|
|
38
|
+
|
|
39
|
+
def to_cardinal(self, number):
|
|
40
|
+
"""Convert a number to its word representation in Occitan."""
|
|
41
|
+
n = str(number).strip()
|
|
42
|
+
|
|
43
|
+
if n.startswith('-'):
|
|
44
|
+
n = n[1:]
|
|
45
|
+
ret = self.negword
|
|
46
|
+
else:
|
|
47
|
+
ret = ""
|
|
48
|
+
|
|
49
|
+
if '.' in n:
|
|
50
|
+
left, right = n.split('.', 1)
|
|
51
|
+
ret += self._int_to_word(int(left)) + " " + self.pointword + " "
|
|
52
|
+
for digit in right:
|
|
53
|
+
ret += self._int_to_word(int(digit)) + " "
|
|
54
|
+
return ret.strip()
|
|
55
|
+
else:
|
|
56
|
+
return (ret + self._int_to_word(int(n))).strip()
|
|
57
|
+
|
|
58
|
+
def _int_to_word(self, number):
|
|
59
|
+
"""Convert an integer to its word representation in Occitan."""
|
|
60
|
+
if number == 0:
|
|
61
|
+
return self.ones[0] if self.ones[0] else "zero"
|
|
62
|
+
|
|
63
|
+
if number < 0:
|
|
64
|
+
return self.negword + self._int_to_word(abs(number))
|
|
65
|
+
elif number < 10:
|
|
66
|
+
return self.ones[number]
|
|
67
|
+
elif number < 100:
|
|
68
|
+
tens_val = number // 10
|
|
69
|
+
ones_val = number % 10
|
|
70
|
+
if ones_val == 0:
|
|
71
|
+
return self.tens[tens_val]
|
|
72
|
+
else:
|
|
73
|
+
return self.tens[tens_val] + " " + self.ones[ones_val]
|
|
74
|
+
elif number < 1000:
|
|
75
|
+
hundreds_val = number // 100
|
|
76
|
+
remainder = number % 100
|
|
77
|
+
result = self.ones[hundreds_val] + " " + self.hundred
|
|
78
|
+
if remainder:
|
|
79
|
+
result += " " + self._int_to_word(remainder)
|
|
80
|
+
return result
|
|
81
|
+
elif number < 1000000:
|
|
82
|
+
thousands_val = number // 1000
|
|
83
|
+
remainder = number % 1000
|
|
84
|
+
result = self._int_to_word(thousands_val) + " " + self.thousand
|
|
85
|
+
if remainder:
|
|
86
|
+
result += " " + self._int_to_word(remainder)
|
|
87
|
+
return result
|
|
88
|
+
elif number < 1000000000:
|
|
89
|
+
millions_val = number // 1000000
|
|
90
|
+
remainder = number % 1000000
|
|
91
|
+
result = self._int_to_word(millions_val) + " " + self.million
|
|
92
|
+
if remainder:
|
|
93
|
+
result += " " + self._int_to_word(remainder)
|
|
94
|
+
return result
|
|
95
|
+
else:
|
|
96
|
+
return str(number) # Fallback for very large numbers
|
|
97
|
+
|
|
98
|
+
def to_ordinal(self, number):
|
|
99
|
+
"""Convert to ordinal in Occitan."""
|
|
100
|
+
cardinal = self.to_cardinal(number)
|
|
101
|
+
# Language-specific ordinal suffix
|
|
102
|
+
return cardinal + "-en"
|
|
103
|
+
|
|
104
|
+
def to_ordinal_num(self, number):
|
|
105
|
+
"""Convert to abbreviated ordinal."""
|
|
106
|
+
return str(number) + "."
|
|
107
|
+
|
|
108
|
+
def to_year(self, val, longval=True):
|
|
109
|
+
"""Convert to year in Occitan."""
|
|
110
|
+
return self.to_cardinal(val)
|
|
111
|
+
|
|
112
|
+
def to_currency(self, val, currency='EUR', cents=True, separator=' ', adjective=False):
|
|
113
|
+
"""Convert to currency in Occitan."""
|
|
114
|
+
is_negative = False
|
|
115
|
+
if val < 0:
|
|
116
|
+
is_negative = True
|
|
117
|
+
val = abs(val)
|
|
118
|
+
|
|
119
|
+
parts = str(val).split('.')
|
|
120
|
+
left = int(parts[0]) if parts[0] else 0
|
|
121
|
+
right = int(parts[1][:2].ljust(2, '0')) if len(parts) > 1 and parts[1] else 0
|
|
122
|
+
|
|
123
|
+
cr1, cr2 = self.CURRENCY_FORMS.get(currency, list(self.CURRENCY_FORMS.values())[0])
|
|
124
|
+
|
|
125
|
+
left_str = self._int_to_word(left)
|
|
126
|
+
result = left_str + " " + (cr1[1] if left != 1 else cr1[0])
|
|
127
|
+
|
|
128
|
+
if cents and right:
|
|
129
|
+
cents_str = self._int_to_word(right)
|
|
130
|
+
result += separator + cents_str + " " + (cr2[1] if right != 1 else cr2[0])
|
|
131
|
+
|
|
132
|
+
if is_negative:
|
|
133
|
+
result = self.negword + result
|
|
134
|
+
|
|
135
|
+
return result.strip()
|
num2words2/lang_PA.py
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
|
3
|
+
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
+
# Lesser General Public License for more details.
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
16
|
+
# MA 02110-1301 USA
|
|
17
|
+
|
|
18
|
+
from __future__ import unicode_literals
|
|
19
|
+
|
|
20
|
+
from .base import Num2Word_Base
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Punjabi language support
|
|
24
|
+
class Num2Word_PA(Num2Word_Base):
|
|
25
|
+
CURRENCY_FORMS = {
|
|
26
|
+
'INR': (('ਰੁਪਈਆ', 'ਰੁਪਏ'), ('ਪੈਸਾ', 'ਪੈਸੇ')),
|
|
27
|
+
'USD': (('dollar', 'dollars'), ('cent', 'cents')),
|
|
28
|
+
'EUR': (('euro', 'euros'), ('cent', 'cents')),
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
def setup(self):
|
|
32
|
+
self.negword = "ਮਾਇਨਸ "
|
|
33
|
+
self.pointword = "ਦਸ਼ਮਲਵ"
|
|
34
|
+
self.ones = ['', 'ਇੱਕ', 'ਦੋ', 'ਤਿੰਨ', 'ਚਾਰ', 'ਪੰਜ', 'ਛੇ', 'ਸੱਤ', 'ਅੱਠ', 'ਨੌ']
|
|
35
|
+
self.tens = ['', 'ਦਸ', 'ਵੀਹ', 'ਤੀਹ', 'ਚਾਲੀ', 'ਪੰਜਾਹ', 'ਸੱਠ', 'ਸੱਤਰ', 'ਅੱਸੀ', 'ਨੱਬੇ']
|
|
36
|
+
self.teens = ['ਦਸ', 'ਗਿਆਰਾਂ', 'ਬਾਰਾਂ', 'ਤੇਰਾਂ', 'ਚੌਦਾਂ', 'ਪੰਦਰਾਂ', 'ਸੋਲਾਂ', 'ਸਤਾਰਾਂ', 'ਅਠਾਰਾਂ', 'ਉੱਨੀ']
|
|
37
|
+
self.hundred = "ਸੌ"
|
|
38
|
+
self.thousand = "ਹਜ਼ਾਰ"
|
|
39
|
+
self.lakh = "ਲੱਖ"
|
|
40
|
+
self.crore = "ਕਰੋੜ"
|
|
41
|
+
self.zero = "ਸਿਫਰ"
|
|
42
|
+
|
|
43
|
+
def to_cardinal(self, number):
|
|
44
|
+
"""Convert a number to its word representation in Punjabi."""
|
|
45
|
+
n = str(number).strip()
|
|
46
|
+
|
|
47
|
+
if n.startswith('-'):
|
|
48
|
+
n = n[1:]
|
|
49
|
+
ret = self.negword
|
|
50
|
+
else:
|
|
51
|
+
ret = ""
|
|
52
|
+
|
|
53
|
+
if '.' in n:
|
|
54
|
+
left, right = n.split('.', 1)
|
|
55
|
+
ret += self._int_to_word(int(left)) + " " + self.pointword + " "
|
|
56
|
+
ret += " ".join(self._int_to_word(int(d)) for d in right)
|
|
57
|
+
return ret.strip()
|
|
58
|
+
else:
|
|
59
|
+
return (ret + self._int_to_word(int(n))).strip()
|
|
60
|
+
|
|
61
|
+
def _int_to_word(self, number):
|
|
62
|
+
"""Convert an integer to its word representation in Punjabi."""
|
|
63
|
+
if number == 0:
|
|
64
|
+
return self.zero
|
|
65
|
+
|
|
66
|
+
if number < 0:
|
|
67
|
+
return self.negword + self._int_to_word(abs(number))
|
|
68
|
+
elif number < 10:
|
|
69
|
+
return self.ones[number]
|
|
70
|
+
elif number < 20:
|
|
71
|
+
return self.teens[number - 10]
|
|
72
|
+
elif number < 100:
|
|
73
|
+
result = self.tens[number // 10]
|
|
74
|
+
if number % 10:
|
|
75
|
+
result += " " + self.ones[number % 10]
|
|
76
|
+
return result
|
|
77
|
+
elif number < 1000:
|
|
78
|
+
result = self.ones[number // 100] + " " + self.hundred
|
|
79
|
+
remainder = number % 100
|
|
80
|
+
if remainder:
|
|
81
|
+
result += " " + self._int_to_word(remainder)
|
|
82
|
+
return result
|
|
83
|
+
elif number < 100000: # Lakh
|
|
84
|
+
result = self._int_to_word(number // 1000) + " " + self.thousand
|
|
85
|
+
remainder = number % 1000
|
|
86
|
+
if remainder:
|
|
87
|
+
result += " " + self._int_to_word(remainder)
|
|
88
|
+
return result
|
|
89
|
+
elif number < 10000000: # Crore
|
|
90
|
+
result = self._int_to_word(number // 100000) + " " + self.lakh
|
|
91
|
+
remainder = number % 100000
|
|
92
|
+
if remainder:
|
|
93
|
+
result += " " + self._int_to_word(remainder)
|
|
94
|
+
return result
|
|
95
|
+
elif number < 1000000000:
|
|
96
|
+
result = self._int_to_word(number // 10000000) + " " + self.crore
|
|
97
|
+
remainder = number % 10000000
|
|
98
|
+
if remainder:
|
|
99
|
+
result += " " + self._int_to_word(remainder)
|
|
100
|
+
return result
|
|
101
|
+
else:
|
|
102
|
+
return str(number) # Fallback for very large numbers
|
|
103
|
+
|
|
104
|
+
def to_ordinal(self, number):
|
|
105
|
+
"""Convert to ordinal in Punjabi.
|
|
106
|
+
|
|
107
|
+
Punjabi ordinals use 'ਵਾਂ' suffix for masculine and 'ਵੀਂ' for feminine.
|
|
108
|
+
Special forms exist for first few ordinals.
|
|
109
|
+
"""
|
|
110
|
+
if number == 1:
|
|
111
|
+
return "ਪਹਿਲਾ" # first
|
|
112
|
+
elif number == 2:
|
|
113
|
+
return "ਦੂਜਾ" # second
|
|
114
|
+
elif number == 3:
|
|
115
|
+
return "ਤੀਜਾ" # third
|
|
116
|
+
elif number == 4:
|
|
117
|
+
return "ਚੌਥਾ" # fourth
|
|
118
|
+
elif number == 5:
|
|
119
|
+
return "ਪੰਜਵਾਂ" # fifth
|
|
120
|
+
else:
|
|
121
|
+
# For other numbers, add ਵਾਂ suffix
|
|
122
|
+
cardinal = self.to_cardinal(number)
|
|
123
|
+
return cardinal + "ਵਾਂ"
|
|
124
|
+
|
|
125
|
+
def to_ordinal_num(self, number):
|
|
126
|
+
"""Convert to abbreviated ordinal."""
|
|
127
|
+
return str(number) + "."
|
|
128
|
+
|
|
129
|
+
def to_year(self, val, longval=True):
|
|
130
|
+
"""Convert to year in Punjabi."""
|
|
131
|
+
if val < 0:
|
|
132
|
+
return "BC " + self.to_cardinal(abs(val))
|
|
133
|
+
else:
|
|
134
|
+
return "" + self.to_cardinal(val)
|
|
135
|
+
|
|
136
|
+
def to_currency(self, val, currency='INR', cents=True, separator=' ', adjective=False):
|
|
137
|
+
"""Convert to currency in Punjabi."""
|
|
138
|
+
is_negative = False
|
|
139
|
+
if val < 0:
|
|
140
|
+
is_negative = True
|
|
141
|
+
val = abs(val)
|
|
142
|
+
|
|
143
|
+
parts = str(val).split('.')
|
|
144
|
+
left = int(parts[0]) if parts[0] else 0
|
|
145
|
+
right = int(parts[1][:2].ljust(2, '0')) if len(parts) > 1 and parts[1] else 0
|
|
146
|
+
|
|
147
|
+
cr1, cr2 = self.CURRENCY_FORMS.get(currency, self.CURRENCY_FORMS['INR'])
|
|
148
|
+
|
|
149
|
+
left_str = self._int_to_word(left)
|
|
150
|
+
result = left_str + " " + (cr1[1] if left != 1 else cr1[0])
|
|
151
|
+
|
|
152
|
+
if cents and right:
|
|
153
|
+
cents_str = self._int_to_word(right)
|
|
154
|
+
result += separator + cents_str + " " + (cr2[1] if right != 1 else cr2[0])
|
|
155
|
+
|
|
156
|
+
if is_negative:
|
|
157
|
+
result = self.negword + result
|
|
158
|
+
|
|
159
|
+
return result.strip()
|
num2words2/lang_PL.py
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
|
3
|
+
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
|
4
|
+
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
# This library is distributed in the hope that it will be useful,
|
|
10
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
11
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
12
|
+
# Lesser General Public License for more details.
|
|
13
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
14
|
+
# License along with this library; if not, write to the Free Software
|
|
15
|
+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
16
|
+
# MA 02110-1301 USA
|
|
17
|
+
|
|
18
|
+
from __future__ import unicode_literals
|
|
19
|
+
|
|
20
|
+
import itertools
|
|
21
|
+
|
|
22
|
+
from .base import Num2Word_Base
|
|
23
|
+
from .utils import get_digits, splitbyx
|
|
24
|
+
|
|
25
|
+
ZERO = ('zero',)
|
|
26
|
+
|
|
27
|
+
ONES = {
|
|
28
|
+
1: ('jeden',),
|
|
29
|
+
2: ('dwa',),
|
|
30
|
+
3: ('trzy',),
|
|
31
|
+
4: ('cztery',),
|
|
32
|
+
5: ('pięć',),
|
|
33
|
+
6: ('sześć',),
|
|
34
|
+
7: ('siedem',),
|
|
35
|
+
8: ('osiem',),
|
|
36
|
+
9: ('dziewięć',),
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
ONES_ORDINALS = {
|
|
40
|
+
1: ('pierwszy', "pierwszo"),
|
|
41
|
+
2: ('drugi', "dwu"),
|
|
42
|
+
3: ('trzeci', "trzy"),
|
|
43
|
+
4: ('czwarty', "cztero"),
|
|
44
|
+
5: ('piąty', "pięcio"),
|
|
45
|
+
6: ('szósty', "sześcio"),
|
|
46
|
+
7: ('siódmy', "siedmio"),
|
|
47
|
+
8: ('ósmy', "ośmio"),
|
|
48
|
+
9: ('dziewiąty', "dziewięcio"),
|
|
49
|
+
10: ('dziesiąty', "dziesięcio"),
|
|
50
|
+
11: ('jedenasty', "jedenasto"),
|
|
51
|
+
12: ('dwunasty', "dwunasto"),
|
|
52
|
+
13: ('trzynasty', "trzynasto"),
|
|
53
|
+
14: ('czternasty', "czternasto"),
|
|
54
|
+
15: ('piętnasty', "piętnasto"),
|
|
55
|
+
16: ('szesnasty', "szesnasto"),
|
|
56
|
+
17: ('siedemnasty', "siedemnasto"),
|
|
57
|
+
18: ('osiemnasty', "osiemnasto"),
|
|
58
|
+
19: ('dziewiętnasty', "dziewiętnasto"),
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
TENS = {
|
|
62
|
+
0: ('dziesięć',),
|
|
63
|
+
1: ('jedenaście',),
|
|
64
|
+
2: ('dwanaście',),
|
|
65
|
+
3: ('trzynaście',),
|
|
66
|
+
4: ('czternaście',),
|
|
67
|
+
5: ('piętnaście',),
|
|
68
|
+
6: ('szesnaście',),
|
|
69
|
+
7: ('siedemnaście',),
|
|
70
|
+
8: ('osiemnaście',),
|
|
71
|
+
9: ('dziewiętnaście',),
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
TWENTIES = {
|
|
76
|
+
2: ('dwadzieścia',),
|
|
77
|
+
3: ('trzydzieści',),
|
|
78
|
+
4: ('czterdzieści',),
|
|
79
|
+
5: ('pięćdziesiąt',),
|
|
80
|
+
6: ('sześćdziesiąt',),
|
|
81
|
+
7: ('siedemdziesiąt',),
|
|
82
|
+
8: ('osiemdziesiąt',),
|
|
83
|
+
9: ('dziewięćdziesiąt',),
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
TWENTIES_ORDINALS = {
|
|
87
|
+
2: ('dwudziesty', "dwudziesto"),
|
|
88
|
+
3: ('trzydziesty', "trzydiesto"),
|
|
89
|
+
4: ('czterdziesty', "czterdziesto"),
|
|
90
|
+
5: ('pięćdziesiąty', "pięćdziesięcio"),
|
|
91
|
+
6: ('sześćdziesiąty', "sześćdziesięcio"),
|
|
92
|
+
7: ('siedemdziesiąty', "siedemdziesięcio"),
|
|
93
|
+
8: ('osiemdziesiąty', "osiemdziesięcio"),
|
|
94
|
+
9: ('dziewięćdziesiąty', "dziewięćdziesięcio"),
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
HUNDREDS = {
|
|
98
|
+
1: ('sto',),
|
|
99
|
+
2: ('dwieście',),
|
|
100
|
+
3: ('trzysta',),
|
|
101
|
+
4: ('czterysta',),
|
|
102
|
+
5: ('pięćset',),
|
|
103
|
+
6: ('sześćset',),
|
|
104
|
+
7: ('siedemset',),
|
|
105
|
+
8: ('osiemset',),
|
|
106
|
+
9: ('dziewięćset',),
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
HUNDREDS_ORDINALS = {
|
|
110
|
+
1: ('setny', "stu"),
|
|
111
|
+
2: ('dwusetny', "dwustu"),
|
|
112
|
+
3: ('trzysetny', "trzystu"),
|
|
113
|
+
4: ('czterysetny', "czterystu"),
|
|
114
|
+
5: ('pięćsetny', "pięcset"),
|
|
115
|
+
6: ('sześćsetny', "sześćset"),
|
|
116
|
+
7: ('siedemsetny', "siedemset"),
|
|
117
|
+
8: ('osiemsetny', "ośiemset"),
|
|
118
|
+
9: ('dziewięćsetny', "dziewięćset"),
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
THOUSANDS = {
|
|
122
|
+
1: ('tysiąc', 'tysiące', 'tysięcy'), # 10^3
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
prefixes_ordinal = {
|
|
126
|
+
1: "tysięczny",
|
|
127
|
+
2: "milionowy",
|
|
128
|
+
3: "milairdowy"
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
prefixes = ( # 10^(6*x)
|
|
132
|
+
"mi", # 10^6
|
|
133
|
+
"bi", # 10^12
|
|
134
|
+
"try", # 10^18
|
|
135
|
+
"kwadry", # 10^24
|
|
136
|
+
"kwinty", # 10^30
|
|
137
|
+
"seksty", # 10^36
|
|
138
|
+
"septy", # 10^42
|
|
139
|
+
"okty", # 10^48
|
|
140
|
+
"nony", # 10^54
|
|
141
|
+
"decy" # 10^60
|
|
142
|
+
)
|
|
143
|
+
suffixes = ("lion", "liard") # 10^x or 10^(x+3)
|
|
144
|
+
|
|
145
|
+
for idx, (p, s) in enumerate(itertools.product(prefixes, suffixes)):
|
|
146
|
+
name = p + s
|
|
147
|
+
THOUSANDS[idx + 2] = (name, name + 'y', name + 'ów')
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class Num2Word_PL(Num2Word_Base):
|
|
151
|
+
CURRENCY_FORMS = {
|
|
152
|
+
'PLN': (
|
|
153
|
+
('złoty', 'złote', 'złotych'), ('grosz', 'grosze', 'groszy')
|
|
154
|
+
),
|
|
155
|
+
'EUR': (
|
|
156
|
+
('euro', 'euro', 'euro'), ('cent', 'centy', 'centów')
|
|
157
|
+
),
|
|
158
|
+
'USD': (
|
|
159
|
+
(
|
|
160
|
+
'dolar amerykański',
|
|
161
|
+
'dolary amerykańskie',
|
|
162
|
+
'dolarów amerykańskich'
|
|
163
|
+
),
|
|
164
|
+
(
|
|
165
|
+
'cent',
|
|
166
|
+
'centy',
|
|
167
|
+
'centów'
|
|
168
|
+
)
|
|
169
|
+
),
|
|
170
|
+
'GBP': (
|
|
171
|
+
(
|
|
172
|
+
'funt brytyjski',
|
|
173
|
+
'funty brytyjskie',
|
|
174
|
+
'funtów brytyjskich'
|
|
175
|
+
),
|
|
176
|
+
(
|
|
177
|
+
'pens',
|
|
178
|
+
'pensy',
|
|
179
|
+
'pensów'
|
|
180
|
+
)
|
|
181
|
+
),
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
def setup(self):
|
|
185
|
+
self.negword = "minus"
|
|
186
|
+
self.pointword = "przecinek"
|
|
187
|
+
|
|
188
|
+
def to_cardinal(self, number):
|
|
189
|
+
n = str(number).replace(',', '.')
|
|
190
|
+
if '.' in n:
|
|
191
|
+
is_negative = n.startswith('-')
|
|
192
|
+
abs_n = n[1:] if is_negative else n
|
|
193
|
+
left, right = abs_n.split('.')
|
|
194
|
+
|
|
195
|
+
# Say each decimal digit individually
|
|
196
|
+
decimal_parts = []
|
|
197
|
+
for digit in right:
|
|
198
|
+
if digit == '0':
|
|
199
|
+
decimal_parts.append(ZERO[0])
|
|
200
|
+
else:
|
|
201
|
+
decimal_parts.append(ONES[int(digit)][0])
|
|
202
|
+
decimal_part = ' '.join(decimal_parts)
|
|
203
|
+
|
|
204
|
+
result = u'%s %s %s' % (
|
|
205
|
+
self._int2word(int(left)),
|
|
206
|
+
self.pointword,
|
|
207
|
+
decimal_part
|
|
208
|
+
)
|
|
209
|
+
if is_negative:
|
|
210
|
+
result = self.negword + ' ' + result
|
|
211
|
+
return result
|
|
212
|
+
else:
|
|
213
|
+
# Handle negative integers
|
|
214
|
+
is_negative = n.startswith('-')
|
|
215
|
+
if is_negative:
|
|
216
|
+
abs_n = n[1:]
|
|
217
|
+
result = self._int2word(int(abs_n))
|
|
218
|
+
return self.negword + ' ' + result
|
|
219
|
+
else:
|
|
220
|
+
return self._int2word(int(n))
|
|
221
|
+
|
|
222
|
+
def pluralize(self, n, forms):
|
|
223
|
+
if n == 1:
|
|
224
|
+
form = 0
|
|
225
|
+
elif 5 > n % 10 > 1 and (n % 100 < 10 or n % 100 > 20):
|
|
226
|
+
form = 1
|
|
227
|
+
else:
|
|
228
|
+
form = 2
|
|
229
|
+
return forms[form]
|
|
230
|
+
|
|
231
|
+
def last_fragment_to_ordinal(self, last, words, level):
|
|
232
|
+
n1, n2, n3 = get_digits(last)
|
|
233
|
+
last_two = n2 * 10 + n1
|
|
234
|
+
if last_two == 0:
|
|
235
|
+
words.append(HUNDREDS_ORDINALS[n3][level])
|
|
236
|
+
elif level == 1 and last == 1:
|
|
237
|
+
return
|
|
238
|
+
elif last_two < 20:
|
|
239
|
+
if n3 > 0:
|
|
240
|
+
words.append(HUNDREDS[n3][level])
|
|
241
|
+
words.append(ONES_ORDINALS[last_two][level])
|
|
242
|
+
elif last_two % 10 == 0:
|
|
243
|
+
if n3 > 0:
|
|
244
|
+
words.append(HUNDREDS[n3][level])
|
|
245
|
+
words.append(TWENTIES_ORDINALS[n2][level])
|
|
246
|
+
else:
|
|
247
|
+
if n3 > 0:
|
|
248
|
+
words.append(HUNDREDS[n3][0])
|
|
249
|
+
words.append(TWENTIES_ORDINALS[n2][0])
|
|
250
|
+
words.append(ONES_ORDINALS[n1][0])
|
|
251
|
+
|
|
252
|
+
def to_currency(self, val, currency='EUR', cents=True, separator=',',
|
|
253
|
+
adjective=False):
|
|
254
|
+
# Handle integers specially - just add currency name without cents
|
|
255
|
+
if isinstance(val, int):
|
|
256
|
+
try:
|
|
257
|
+
cr1, cr2 = self.CURRENCY_FORMS[currency]
|
|
258
|
+
except (KeyError, AttributeError):
|
|
259
|
+
# Fallback to base implementation for unknown currency
|
|
260
|
+
return super(Num2Word_PL, self).to_currency(
|
|
261
|
+
val, currency=currency, cents=cents, separator=separator,
|
|
262
|
+
adjective=adjective)
|
|
263
|
+
|
|
264
|
+
minus_str = self.negword if val < 0 else ""
|
|
265
|
+
abs_val = abs(val)
|
|
266
|
+
money_str = self.to_cardinal(abs_val)
|
|
267
|
+
|
|
268
|
+
# For Polish, check if number ends with "jeden" (one)
|
|
269
|
+
# Numbers ending in compound "jeden" (like 21, 121, 10121) get special treatment
|
|
270
|
+
# They use the second form (nominative plural for 2-4)
|
|
271
|
+
if abs_val > 1 and money_str.endswith("jeden"):
|
|
272
|
+
# Use nominative plural form (2-4) for compound numbers ending with "jeden"
|
|
273
|
+
currency_str = cr1[1] if len(cr1) > 1 else cr1[0]
|
|
274
|
+
else:
|
|
275
|
+
# Use the pluralize method for proper currency form selection
|
|
276
|
+
currency_str = self.pluralize(abs_val, cr1)
|
|
277
|
+
|
|
278
|
+
return (u'%s %s %s' % (minus_str, money_str, currency_str)).strip()
|
|
279
|
+
|
|
280
|
+
# For floats, use the parent class implementation
|
|
281
|
+
return super(Num2Word_PL, self).to_currency(
|
|
282
|
+
val, currency=currency, cents=cents, separator=separator,
|
|
283
|
+
adjective=adjective)
|
|
284
|
+
|
|
285
|
+
def to_ordinal(self, number):
|
|
286
|
+
if number % 1 != 0:
|
|
287
|
+
raise NotImplementedError()
|
|
288
|
+
words = []
|
|
289
|
+
fragments = list(splitbyx(str(number), 3))
|
|
290
|
+
level = 0
|
|
291
|
+
last = fragments[-1]
|
|
292
|
+
while last == 0:
|
|
293
|
+
level = level + 1
|
|
294
|
+
fragments.pop()
|
|
295
|
+
last = fragments[-1]
|
|
296
|
+
if len(fragments) > 1:
|
|
297
|
+
pre_part = self._int2word(number - (last * 1000**level))
|
|
298
|
+
words.append(pre_part)
|
|
299
|
+
self.last_fragment_to_ordinal(last, words, 0 if level == 0 else 1)
|
|
300
|
+
output = " ".join(words)
|
|
301
|
+
if last == 1 and level > 0 and output != "":
|
|
302
|
+
output = output + " "
|
|
303
|
+
if level > 0:
|
|
304
|
+
output = output + prefixes_ordinal[level]
|
|
305
|
+
return output
|
|
306
|
+
|
|
307
|
+
def _int2word(self, n):
|
|
308
|
+
if n == 0:
|
|
309
|
+
return ZERO[0]
|
|
310
|
+
|
|
311
|
+
words = []
|
|
312
|
+
chunks = list(splitbyx(str(n), 3))
|
|
313
|
+
i = len(chunks)
|
|
314
|
+
for x in chunks:
|
|
315
|
+
i -= 1
|
|
316
|
+
|
|
317
|
+
if x == 0:
|
|
318
|
+
continue
|
|
319
|
+
|
|
320
|
+
n1, n2, n3 = get_digits(x)
|
|
321
|
+
|
|
322
|
+
if n3 > 0:
|
|
323
|
+
words.append(HUNDREDS[n3][0])
|
|
324
|
+
|
|
325
|
+
if n2 > 1:
|
|
326
|
+
words.append(TWENTIES[n2][0])
|
|
327
|
+
|
|
328
|
+
if n2 == 1:
|
|
329
|
+
words.append(TENS[n1][0])
|
|
330
|
+
elif n1 > 0 and not (i > 0 and x == 1):
|
|
331
|
+
words.append(ONES[n1][0])
|
|
332
|
+
|
|
333
|
+
if i > 0:
|
|
334
|
+
words.append(self.pluralize(x, THOUSANDS[i]))
|
|
335
|
+
|
|
336
|
+
return ' '.join(words)
|