14 Commits
0.5.1 ... 0.5.2

Author SHA1 Message Date
Virgil Dupras
486f5415af v0.5.2 2015-01-23 12:21:33 -05:00
Virgil Dupras
4b35f533da Merge pull request #14 from frappe/master
Add Indian locale
2015-01-22 15:59:00 -05:00
Virgil Dupras
4c53549959 Merge pull request #13 from cesarizu/master
Updated spanish translations
2015-01-22 15:57:10 -05:00
Pratik Vyas
904c3c7e1b Add Indian locale 2015-01-22 20:05:30 +05:30
César Izurieta
3bc43a190d Updated spanish translations 2015-01-21 13:44:31 -02:00
Virgil Dupras
a1802b59bc Merge pull request #12 from marltu/master
Made lithuanian language more formal
2014-10-22 15:03:35 -04:00
Marius Grigaitis
4b779b830f python3 support for tests 2014-10-22 15:23:53 +03:00
Marius Grigaitis
b4e00ea5b5 Made lithuanian language more formal 2014-10-22 15:03:56 +03:00
Carlos Blanco
567f293aa3 In Spanish, the number 100000 should be "Cien mil" and not "Ceinto mil" 2014-08-12 12:53:34 -04:00
Virgil Dupras
a52b9b7ad5 Reformatted the list of supported languages 2014-06-02 12:48:23 -04:00
Virgil Dupras
fa93e45ce5 Added "lv" to the list of supported languages in the README 2014-06-02 11:41:38 -04:00
Virgil Dupras
b87197e3d9 Added Latvian to the list of supported languages 2014-06-02 11:33:04 -04:00
Artis Avotins
5e0a6b3f5c Added latvian translation 2014-06-02 13:56:20 +03:00
Virgil Dupras
539de2fd6e Added changelog to PyPI description 2014-03-14 10:57:06 -04:00
8 changed files with 446 additions and 50 deletions

View File

@@ -1,6 +1,13 @@
Changelog
=========
Version 0.5.2 -- 2015/01/23
---------------------------
* Added Latvian localization. (#9)
* Improved Spanish localization. (#10, #13, #14)
* Improved Lithuanian localization. (#12)
Version 0.5.1 -- 2014/03/14
---------------------------

View File

@@ -35,8 +35,18 @@ Besides the numerical argument, there's two optional arguments.
**ordinal:** A boolean flag indicating to return an ordinal number instead of a cardinal one.
**lang:** The language in which to convert the number. Supported languages are ``en``, ``fr``,
``de``, ``es``, ``lt`` and ``en_GB``. You can supply values like ``fr_FR``, the code will be
**lang:** The language in which to convert the number. Supported values are:
* ``en`` (English, default)
* ``fr`` (French)
* ``de`` (German)
* ``es`` (Spanish)
* ``lt`` (Lithuanian)
* ``lv`` (Latvian)
* ``en_GB`` (British English)
* ``en_IN`` (Indian English)
You can supply values like ``fr_FR``, the code will be
correctly interpreted. If you supply an unsupported language, ``NotImplementedError`` is raised.
Therefore, if you want to call ``num2words`` with a fallback, you can do::

View File

@@ -18,18 +18,22 @@ from __future__ import unicode_literals
from . import lang_EN
from . import lang_EN_GB
from . import lang_EN_IN
from . import lang_FR
from . import lang_DE
from . import lang_ES
from . import lang_LT
from . import lang_LV
CONVERTER_CLASSES = {
'en': lang_EN.Num2Word_EN(),
'en_GB': lang_EN_GB.Num2Word_EN_GB(),
'en_IN': lang_EN_IN.Num2Word_EN_IN(),
'fr': lang_FR.Num2Word_FR(),
'de': lang_DE.Num2Word_DE(),
'es': lang_ES.Num2Word_ES(),
'lt': lang_LT.Num2Word_LT(),
'lv': lang_LV.Num2Word_LV(),
}
def num2words(number, ordinal=False, lang='en'):

42
num2words/lang_EN_IN.py Normal file
View File

@@ -0,0 +1,42 @@
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
from __future__ import unicode_literals
from .lang_EN import Num2Word_EN
class Num2Word_EN_IN(Num2Word_EN):
def set_high_numwords(self, high):
self.cards[10**7] = "crore"
self.cards[10**5] = "lakh"
n2w = Num2Word_EN_IN()
to_card = n2w.to_cardinal
to_ord = n2w.to_ordinal
to_ordnum = n2w.to_ordinal_num
def main():
for val in (15000,
15*10**5,
15*10**6,
15*10**7,
15*10**8,
15*10**9,
15*10**10):
n2w.test(val)
if __name__ == "__main__":
main()

View File

@@ -1,3 +1,5 @@
#encoding: UTF-8
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
@@ -17,9 +19,6 @@
from __future__ import unicode_literals
from .lang_EU import Num2Word_EU
#//TODO: correct orthographics
#//TODO: error messages
class Num2Word_ES(Num2Word_EU):
#//CHECK: Is this sufficient??
@@ -27,7 +26,7 @@ class Num2Word_ES(Num2Word_EU):
max = 3 + 6*len(high)
for word, n in zip(high, range(max, 3, -6)):
self.cards[10**(n-3)] = word + "ill\xf2n"
self.cards[10**(n-3)] = word + "illón"
def setup(self):
@@ -35,30 +34,52 @@ class Num2Word_ES(Num2Word_EU):
self.high_numwords = self.gen_high_numwords([], [], lows)
self.negword = "menos "
self.pointword = "punto"
self.errmsg_nonnum = "Only numbers may be converted to words."
self.errmsg_toobig = "Number is too large to convert to words."
self.errmsg_nonnum = "Solo números pueden ser convertidos a palabras."
self.errmsg_toobig = "Numero muy grande para ser convertido a palabras."
self.gender_stem = "o"
self.exclude_title = ["y", "menos", "punto"]
self.mid_numwords = [(1000, "mil"), (100, "cien"), (90, "noventa"),
(80, "ochenta"), (70, "setenta"), (60, "sesenta"),
(50,"cincuenta"), (40,"cuarenta"), (30,"treinta")]
self.low_numwords = ["vientinueve", "vientiocho", "vientisiete",
"vientis\xE8is", "vienticinco", "vienticuatro",
"vientitr\xE8s", "vientid\xF2s", "vientiuno",
"viente", "diecinueve", "dieciocho", "diecisiete",
(50, "cincuenta"), (40, "cuarenta"), (30, "treinta")]
self.low_numwords = ["veintinueve", "veintiocho", "veintisiete",
"veintiséis", "veinticinco", "veinticuatro",
"veintitrés", "veintidós", "veintiuno",
"veinte", "diecinueve", "dieciocho", "diecisiete",
"dieciseis", "quince", "catorce", "trece", "doce",
"once", "diez", "nueve", "ocho", "siete", "seis",
"cinco", "cuatro", "tres", "dos", "uno", "cero"]
self.ords = { 1 : "primer",
2 : "segund",
3 : "tercer",
4 : "cuart",
5 : "quint",
6 : "sext",
7 : "s\xE8ptim",
8 : "octav",
9 : "noven",
10 : "d\xE8cim" }
self.ords = { 1 : "primer",
2 : "segund",
3 : "tercer",
4 : "cuart",
5 : "quint",
6 : "sext",
7 : "séptim",
8 : "octav",
9 : "noven",
10 : "décim",
20 : "vigésim",
30 : "trigésim",
40 : "quadragésim",
50 : "quincuagésim",
60 : "sexagésim",
70 : "septuagésim",
80 : "octogésim",
90 : "nonagésim",
100 : "centésim",
200 : "ducentésim",
300 : "tricentésim",
400 : "cuadrigentésim",
500 : "quingentésim",
600 : "sexcentésim",
700 : "septigentésim",
800 : "octigentésim",
900 : "noningentésim",
1e3 : "milésim",
1e6 : "millonésim",
1e9 : "billonésim",
1e12 : "trillonésim",
1e15 : "cuadrillonésim" }
def merge(self, curr, next):
@@ -68,7 +89,7 @@ class Num2Word_ES(Num2Word_EU):
if nnum < 1000000:
return next
ctext = "un"
elif cnum == 100:
elif cnum == 100 and not nnum == 1000:
ctext += "t" + self.gender_stem
if nnum < cnum:
@@ -95,15 +116,40 @@ class Num2Word_ES(Num2Word_EU):
def to_ordinal(self, value):
self.verify_ordinal(value)
text = ""
try:
return self.ords[value] + self.gender_stem
if value == 0:
text = ""
elif value <= 10:
text = "%s%s" % (self.ords[value], self.gender_stem)
elif value <= 12:
text = "%s%s%s" % (self.ords[10], self.gender_stem, self.to_ordinal(value - 10))
elif value <= 100:
dec = (value / 10) * 10
text = "%s%s %s" % (self.ords[dec], self.gender_stem, self.to_ordinal(value - dec))
elif value <= 1e3:
cen = (value / 100) * 100
text = "%s%s %s" % (self.ords[cen], self.gender_stem, self.to_ordinal(value - cen))
elif value < 1e18:
# dec contains the following:
# [ 1e3, 1e6): 1e3
# [ 1e6, 1e9): 1e6
# [ 1e9, 1e12): 1e9
# [1e12, 1e15): 1e12
# [1e15, 1e18): 1e15
dec = 10 ** ((((len(str(int(value))) - 1) / 3 - 1) + 1) * 3)
part = int(float(value / dec) * dec)
cardinal = self.to_cardinal(part / dec) if part / dec != 1 else ""
text = "%s%s%s %s" % (cardinal, self.ords[dec], self.gender_stem, self.to_ordinal(value - part))
else:
text = self.to_cardinal(value)
except KeyError:
return self.to_cardinal(value)
text = self.to_cardinal(value)
return text.strip()
def to_ordinal_num(self, value):
self.verify_ordinal(value)
# Correct for fem?
return "%s\xB0"%value
return "%s%s" % (value, "º" if self.gender_stem == 'o' else "ª")
def to_currency(self, val, longval=True, old=False):

View File

@@ -17,12 +17,12 @@
u"""
>>> from textwrap import fill
>>> ' '.join([str(i) for i in splitby3('1')])
'1'
>>> ' '.join([str(i) for i in splitby3('1123')])
'1 123'
>>> ' '.join([str(i) for i in splitby3('1234567890')])
'1 234 567 890'
>>> print(' '.join([str(i) for i in splitby3('1')]))
1
>>> print(' '.join([str(i) for i in splitby3('1123')]))
1 123
>>> print(' '.join([str(i) for i in splitby3('1234567890')]))
1 234 567 890
>>> print(' '.join([n2w(i) for i in range(10)]))
nulis vienas du trys keturi penki šeši septyni aštuoni devyni
@@ -36,34 +36,34 @@ nulis dešimt dvidešimt trisdešimt keturiasdešimt penkiasdešimt
šešiasdešimt septyniasdešimt aštuoniasdešimt devyniasdešimt
>>> print(n2w(100))
šimtas
vienas šimtas
>>> print(n2w(101))
šimtas vienas
vienas šimtas vienas
>>> print(n2w(110))
šimtas dešimt
vienas šimtas dešimt
>>> print(n2w(115))
šimtas penkiolika
vienas šimtas penkiolika
>>> print(n2w(123))
šimtas dvidešimt trys
vienas šimtas dvidešimt trys
>>> print(n2w(1000))
tūkstantis
vienas tūkstantis
>>> print(n2w(1001))
tūkstantis vienas
vienas tūkstantis vienas
>>> print(n2w(2012))
du tūkstančiai dvylika
>>> print(fill(n2w(1234567890)))
milijardas du šimtai trisdešimt keturi milijonai penki šimtai
vienas milijardas du šimtai trisdešimt keturi milijonai penki šimtai
šešiasdešimt septyni tūkstančiai aštuoni šimtai devyniasdešimt
>>> print(fill(n2w(215461407892039002157189883901676)))
du šimtai penkiolika naintilijonų keturi šimtai šešiasdešimt vienas
oktilijonas keturi šimtai septyni septilijonai aštuoni šimtai
devyniasdešimt du sikstilijonai trisdešimt devyni kvintilijonai du
kvadrilijonai šimtas penkiasdešimt septyni trilijonai šimtas
aštuoniasdešimt devyni milijardai aštuoni šimtai aštuoniasdešimt trys
milijonai devyni šimtai vienas tūkstantis šeši šimtai septyniasdešimt
šeši
kvadrilijonai vienas šimtas penkiasdešimt septyni trilijonai vienas
šimtas aštuoniasdešimt devyni milijardai aštuoni šimtai
aštuoniasdešimt trys milijonai devyni šimtai vienas tūkstantis šeši
šimtai septyniasdešimt šeši
>>> print(fill(n2w(719094234693663034822824384220291)))
septyni šimtai devyniolika naintilijonų devyniasdešimt keturi
@@ -82,7 +82,7 @@ naintilijonas
vienas litas, nulis centų
>>> print(to_currency(1234.56, 'LTL'))
tūkstantis du šimtai trisdešimt keturi litai, penkiasdešimt šeši centai
vienas tūkstantis du šimtai trisdešimt keturi litai, penkiasdešimt šeši centai
>>> print(to_currency(-1251985, cents = False))
minus dvylika tūkstančių penki šimtai devyniolika litų, 85 centai
@@ -177,13 +177,14 @@ def int2word(n):
words = []
chunks = list(splitby3(str(n)))
i = len(chunks)
for x in chunks:
i -= 1
n1, n2, n3 = get_digits(x)
if n3 > 0:
words.append(ONES[n3][0])
if n3 > 1:
words.append(ONES[n3][0])
words.append(HUNDRED[1])
else:
words.append(HUNDRED[0])
@@ -193,7 +194,7 @@ def int2word(n):
if n2 == 1:
words.append(TENS[n1][0])
elif n1 > 0 and not (i > 0 and x == 1):
elif n1 > 0:
words.append(ONES[n1][0])
if i > 0:

285
num2words/lang_LV.py Normal file
View File

@@ -0,0 +1,285 @@
# -*- encoding: utf-8 -*-
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA
u"""
>>> from textwrap import fill
>>> ' '.join([str(i) for i in splitby3('1')])
u'1'
>>> ' '.join([str(i) for i in splitby3('1123')])
u'1 123'
>>> ' '.join([str(i) for i in splitby3('1234567890')])
u'1 234 567 890'
>>> print(' '.join([n2w(i) for i in range(10)]))
nulle viens divi trīs četri pieci seši septiņi astoņi deviņi
>>> print(fill(' '.join([n2w(i+10) for i in range(10)])))
desmit vienpadsmit divpadsmit trīspadsmit četrpadsmit piecpadsmit
sešpadsmit septiņpadsmit astoņpadsmit deviņpadsmit
>>> print(fill(' '.join([n2w(i*10) for i in range(10)])))
nulle desmit divdesmit trīsdesmit četrdesmit piecdesmit sešdesmit
septiņdesmit astoņdesmit deviņdesmit
>>> print(n2w(100))
simts
>>> print(n2w(101))
simtu viens
>>> print(n2w(110))
simts desmit
>>> print(n2w(115))
simts piecpadsmit
>>> print(n2w(123))
simts divdesmit trīs
>>> print(n2w(1000))
tūkstotis
>>> print(n2w(1001))
tūkstotis viens
>>> print(n2w(2012))
divi tūkstoši divpadsmit
>>> print(fill(n2w(1234567890)))
miljards divi simti trīsdesmit četri miljoni pieci simti sešdesmit
septiņi tūkstoši astoņi simti deviņdesmit
>>> print(fill(n2w(215461407892039002157189883901676)))
divi simti piecpadsmit nontiljoni četri simti sešdesmit viens
oktiljons četri simti septiņi septiljoni astoņi simti deviņdesmit divi
sikstiljoni trīsdesmit deviņi kvintiljoni divi kvadriljoni simts
piecdesmit septiņi triljoni simts astoņdesmit deviņi miljardi astoņi
simti astoņdesmit trīs miljoni deviņi simti viens tūkstotis seši simti
septiņdesmit seši
>>> print(fill(n2w(719094234693663034822824384220291)))
septiņi simti deviņpadsmit nontiljoni deviņdesmit četri oktiljoni divi
simti trīsdesmit četri septiljoni seši simti deviņdesmit trīs
sikstiljoni seši simti sešdesmit trīs kvintiljoni trīsdesmit četri
kvadriljoni astoņi simti divdesmit divi triljoni astoņi simti
divdesmit četri miljardi trīs simti astoņdesmit četri miljoni divi
simti divdesmit tūkstoši divi simti deviņdesmit viens
# TODO: fix this:
# >>> print(fill(n2w(1000000000000000000000000000000)))
# nontiljons
>>> print(to_currency(1.0, 'EUR'))
viens eiro, nulle centu
>>> print(to_currency(1.0, 'LVL'))
viens lats, nulle santīmu
>>> print(to_currency(1234.56, 'EUR'))
tūkstotis divi simti trīsdesmit četri eiro, piecdesmit seši centi
>>> print(to_currency(1234.56, 'LVL'))
tūkstotis divi simti trīsdesmit četri lati, piecdesmit seši santīmi
>>> print(to_currency(10111, 'EUR', seperator=' un'))
simtu viens eiro un vienpadsmit centi
>>> print(to_currency(10121, 'LVL', seperator=' un'))
simtu viens lats un divdesmit viens santīms
>>> print(to_currency(-1251985, cents = False))
mīnus divpadsmit tūkstoši pieci simti deviņpadsmit eiro, 85 centi
"""
from __future__ import unicode_literals
ZERO = (u'nulle',)
ONES = {
1: (u'viens',),
2: (u'divi',),
3: (u'trīs',),
4: (u'četri',),
5: (u'pieci',),
6: (u'seši',),
7: (u'septiņi',),
8: (u'astoņi',),
9: (u'deviņi',),
}
TENS = {
0: (u'desmit',),
1: (u'vienpadsmit',),
2: (u'divpadsmit',),
3: (u'trīspadsmit',),
4: (u'četrpadsmit',),
5: (u'piecpadsmit',),
6: (u'sešpadsmit',),
7: (u'septiņpadsmit',),
8: (u'astoņpadsmit',),
9: (u'deviņpadsmit',),
}
TWENTIES = {
2: (u'divdesmit',),
3: (u'trīsdesmit',),
4: (u'četrdesmit',),
5: (u'piecdesmit',),
6: (u'sešdesmit',),
7: (u'septiņdesmit',),
8: (u'astoņdesmit',),
9: (u'deviņdesmit',),
}
HUNDRED = (u'simts', u'simti', u'simtu')
THOUSANDS = {
1: (u'tūkstotis', u'tūkstoši', u'tūkstošu'),
2: (u'miljons', u'miljoni', u'miljonu'),
3: (u'miljards', u'miljardi', u'miljardu'),
4: (u'triljons', u'triljoni', u'triljonu'),
5: (u'kvadriljons', u'kvadriljoni', u'kvadriljonu'),
6: (u'kvintiljons', u'kvintiljoni', u'kvintiljonu'),
7: (u'sikstiljons', u'sikstiljoni', u'sikstiljonu'),
8: (u'septiljons', u'septiljoni', u'septiljonu'),
9: (u'oktiljons', u'oktiljoni', u'oktiljonu'),
10: (u'nontiljons', u'nontiljoni', u'nontiljonu'),
}
CURRENCIES = {
'LVL': (
(u'lats', u'lati', u'latu'), (u'santīms', u'santīmi', u'santīmu')
),
'EUR': (
(u'eiro', u'eiro', u'eiro'), (u'cents', u'centi', u'centu')
),
}
def splitby3(n):
length = len(n)
if length > 3:
start = length % 3
if start > 0:
yield int(n[:start])
for i in range(start, length, 3):
yield int(n[i:i+3])
else:
yield int(n)
def get_digits(n):
return [int(x) for x in reversed(list(('%03d' % n)[-3:]))]
def pluralize(n, forms):
# gettext implementation:
# (n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2)
form = 0 if (n % 10 == 1 and n % 100 != 11) else 1 if n != 0 else 2
return forms[form]
def int2word(n):
if n == 0:
return ZERO[0]
words = []
chunks = list(splitby3(str(n)))
i = len(chunks)
for x in chunks:
i -= 1
n1, n2, n3 = get_digits(x)
# print str(n3) + str(n2) + str(n1)
if n3 > 0:
if n3 == 1 and n2 == 0 and n1 > 0:
words.append(HUNDRED[2])
elif n3 > 1:
words.append(ONES[n3][0])
words.append(HUNDRED[1])
else:
words.append(HUNDRED[0])
if n2 > 1:
words.append(TWENTIES[n2][0])
if n2 == 1:
words.append(TENS[n1][0])
elif n1 > 0 and not (i > 0 and x == 1):
words.append(ONES[n1][0])
if i > 0:
words.append(pluralize(x, THOUSANDS[i]))
return ' '.join(words)
def n2w(n):
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
return u'%s kablelis %s' % (int2word(int(left)), int2word(int(right)))
else:
return int2word(int(n))
def to_currency(n, currency='EUR', cents=True, seperator=','):
if type(n) == int:
if n < 0:
minus = True
else:
minus = False
n = abs(n)
left = n / 100
right = n % 100
else:
n = str(n).replace(',', '.')
if '.' in n:
left, right = n.split('.')
else:
left, right = n, 0
left, right = int(left), int(right)
minus = False
cr1, cr2 = CURRENCIES[currency]
if minus:
minus_str = "mīnus "
else:
minus_str = ""
if cents:
cents_str = int2word(right)
else:
cents_str = "%02d" % right
return u'%s%s %s%s %s %s' % (
minus_str,
int2word(left),
pluralize(left, cr1),
seperator,
cents_str,
pluralize(right, cr2)
)
class Num2Word_LV(object):
def to_cardinal(self, number):
return n2w(number)
def to_ordinal(self, number):
raise NotImplementedError()
if __name__ == '__main__':
import doctest
doctest.testmod()

View File

@@ -17,8 +17,9 @@ LONG_DESC = open('README.rst', 'rt').read() + '\n\n' + open('CHANGES.rst', 'rt')
setup(
name='num2words',
version='0.5.1',
version='0.5.2',
description='Modules to convert numbers to words. Easily extensible.',
long_description=LONG_DESC,
license='LGPL',
author='Taro Ogawa <tso at users sourceforge net>',
author_email='tos@users.sourceforge.net',