[FIX] Amount to text conversions made better

lp bug: https://launchpad.net/bugs/453269 fixed

bzr revid: jvo@tinyerp.com-20091125094031-oh9p5uxhx9ov99f7
This commit is contained in:
VRA(OpenERP) 2009-11-25 15:10:31 +05:30 committed by Jay (Open ERP)
parent 3fd8dfcd79
commit 6e6202a0f6
2 changed files with 166 additions and 204 deletions

View File

@ -24,147 +24,128 @@
# French
#-------------------------------------------------------------
unites = {
0: '', 1:'un', 2:'deux', 3:'trois', 4:'quatre', 5:'cinq', 6:'six', 7:'sept', 8:'huit', 9:'neuf',
10:'dix', 11:'onze', 12:'douze', 13:'treize', 14:'quatorze', 15:'quinze', 16:'seize',
21:'vingt et un', 31:'trente et un', 41:'quarante et un', 51:'cinquante et un', 61:'soixante et un',
71:'septante et un', 91:'nonante et un', 80:'quatre-vingts'
}
dizaine = {
1: 'dix', 2:'vingt', 3:'trente',4:'quarante', 5:'cinquante', 6:'soixante', 7:'septante', 8:'quatre-vingt', 9:'nonante'
}
to_19_fr = ( 'zéro', 'un', 'deux', 'trois', 'quatre', 'cinq', 'six',
'sept', 'huit', 'neuf', 'dix', 'onze', 'douze', 'treize',
'quatorze', 'quinze', 'seize', 'dix-sept', 'dix-huit', 'dix-neuf' )
tens_fr = ( 'vingt', 'trente', 'quarante', 'Cinquante', 'Soixante', 'Soixante-dix', 'Quatre-vingts', 'Quatre-vingt Dix')
denom_fr = ( '',
'Mille', 'Millions', 'Milliards', 'Billions', 'Quadrillions',
'Quintillion', 'Sextillion', 'Septillion', 'Octillion', 'Nonillion',
'Décillion', 'Undecillion', 'Duodecillion', 'Tredecillion', 'Quattuordecillion',
'Sexdecillion', 'Septendecillion', 'Octodecillion', 'Icosillion', 'Vigintillion' )
centaine = {
0:'', 1: 'cent', 2:'deux cent', 3:'trois cent',4:'quatre cent', 5:'cinq cent', 6:'six cent', 7:'sept cent', 8:'huit cent', 9:'neuf cent'
}
# convert a value < 100 to French.
def _convert_nn_fr(val):
if val < 20:
return to_19_fr[val]
for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens_fr)):
if dval + 10 > val:
if val % 10:
return dcap + '-' + to_19_fr[val % 10]
return dcap
mille = {
0:'', 1:'mille'
}
# convert a value < 1000 to french, special cased because it is the level that kicks
# off the < 100 special case. The rest are more general. This also allows you to
# get strings in the form of 'forty-five hundred' if called directly.
def _convert_nnn_fr(val):
word = ''
(mod, rem) = (val % 100, val // 100)
if rem > 0:
word = to_19_fr[rem] + ' Cent'
if mod > 0:
word = word + ' '
if mod > 0:
word = word + _convert_nn_fr(mod)
return word
def _100_to_text_fr(chiffre):
if chiffre in unites:
return unites[chiffre]
else:
if chiffre%10>0:
return dizaine[chiffre / 10]+'-'+unites[chiffre % 10]
else:
return dizaine[chiffre / 10]
def french_number(val):
if val < 100:
return _convert_nn_fr(val)
if val < 1000:
return _convert_nnn_fr(val)
for (didx, dval) in ((v - 1, 1000 ** v) for v in range(len(denom_fr))):
if dval > val:
mod = 1000 ** didx
l = val // mod
r = val - (l * mod)
ret = _convert_nnn_fr(l) + ' ' + denom_fr[didx]
if r > 0:
ret = ret + ', ' + french_number(r)
return ret
def _1000_to_text_fr(chiffre):
d = _100_to_text_fr(chiffre % 100)
d2 = chiffre/100
if d2>0 and d:
return centaine[d2]+' '+d
elif d2>1 and not(d):
return centaine[d2]+'s'
else:
return centaine[d2] or d
def _10000_to_text_fr(chiffre):
if chiffre==0:
return 'zero'
part1 = _1000_to_text_fr(chiffre % 1000)
part2 = mille.get(chiffre / 1000, _1000_to_text_fr(chiffre / 1000)+' mille')
if part2 and part1:
part1 = ' '+part1
return part2+part1
def amount_to_text_fr(number, currency):
units_number = int(number)
units_name = currency
if units_number > 1:
units_name += 's'
units = _10000_to_text_fr(units_number)
units = units_number and '%s %s' % (units, units_name) or ''
cents_number = int(number * 100) % 100
cents_name = (cents_number > 1) and 'cents' or 'cent'
cents = _100_to_text_fr(cents_number)
cents = cents_number and '%s %s' % (cents, cents_name) or ''
if units and cents:
cents = ' '+cents
return units + cents
list = str(number).split('.')
start_word = french_number(abs(int(list[0])))
end_word = french_number(int(list[1]))
cents_number = int(list[1])
cents_name = (cents_number > 1) and ' Cents' or ' Cent'
final_result = start_word +' '+units_name+' '+ end_word +' '+cents_name
return final_result
#-------------------------------------------------------------
# Dutch
#-------------------------------------------------------------
units_nl = {
0:'', 1:'een', 2:'twee', 3:'drie', 4:'vier', 5:'vijf', 6:'zes', 7:'zeven', 8:'acht', 9:'negen',
10:'tien', 11:'elf', 12:'twaalf', 13:'dertien', 14:'veertien'
}
to_19_nl = ( 'Nul', 'Een', 'Twee', 'Drie', 'Vier', 'Vijf', 'Zes',
'Zeven', 'Acht', 'Negen', 'Tien', 'Elf', 'Twaalf', 'Dertien',
'Veertien', 'Vijftien', 'Zestien', 'Zeventien', 'Achttien', 'Negentien' )
tens_nl = ( 'Twintig', 'Dertig', 'Veertig', 'Vijftig', 'Zestig', 'Zeventig', 'Tachtig', 'Negentig')
denom_nl = ( '',
'Duizend', 'Miljoen', 'Miljard', 'Triljoen', 'Quadriljoen',
'Quintillion', 'Sextiljoen', 'Septillion', 'Octillion', 'Nonillion',
'Decillion', 'Undecillion', 'Duodecillion', 'Tredecillion', 'Quattuordecillion',
'Sexdecillion', 'Septendecillion', 'Octodecillion', 'Novemdecillion', 'Vigintillion' )
tens_nl = {
1: 'tien', 2:'twintig', 3:'dertig',4:'veertig', 5:'vijftig', 6:'zestig', 7:'zeventig', 8:'tachtig', 9:'negentig'
}
# convert a value < 100 to Dutch.
def _convert_nn_nl(val):
if val < 20:
return to_19_nl[val]
for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens_nl)):
if dval + 10 > val:
if val % 10:
return dcap + '-' + to_19_nl[val % 10]
return dcap
hundreds_nl = {
0:'', 1: 'honderd',
}
# convert a value < 1000 to Dutch, special cased because it is the level that kicks
# off the < 100 special case. The rest are more general. This also allows you to
# get strings in the form of 'forty-five hundred' if called directly.
def _convert_nnn_nl(val):
word = ''
(mod, rem) = (val % 100, val // 100)
if rem > 0:
word = to_19_nl[rem] + ' Honderd'
if mod > 0:
word = word + ' '
if mod > 0:
word = word + _convert_nn_nl(mod)
return word
thousands_nl = {
0:'', 1:'duizend'
}
def dutch_number(val):
if val < 100:
return _convert_nn_nl(val)
if val < 1000:
return _convert_nnn_nl(val)
for (didx, dval) in ((v - 1, 1000 ** v) for v in range(len(denom_nl))):
if dval > val:
mod = 1000 ** didx
l = val // mod
r = val - (l * mod)
ret = _convert_nnn_nl(l) + ' ' + denom_nl[didx]
if r > 0:
ret = ret + ', ' + dutch_number(r)
return ret
def _100_to_text_nl(number):
if number in units_nl:
return units_nl[number]
else:
if number%10 > 0:
if number>10 and number<20:
return units_nl[number % 10]+tens_nl[number / 10]
else:
units = units_nl[number % 10]
if units[-1] == 'e':
joinword = 'ën'
else:
joinword = 'en'
return units+joinword+tens_nl[number / 10]
else:
return tens_nl[number / 10]
def _1000_to_text_nl(number):
part1 = _100_to_text_nl(number % 100)
part2 = hundreds_nl.get(number / 100, units_nl[number/100] + hundreds_nl[1])
if part2 and part1:
part1 = ' ' + part1
return part2 + part1
def _10000_to_text_nl(number):
if number==0:
return 'nul'
part1 = _1000_to_text_nl(number % 1000)
if thousands_nl.has_key(number / 1000):
part2 = thousands_nl[number / 1000]
else:
if (number / 1000 % 100 > 0) and (number / 1000 > 100):
space = ' '
else:
space = ''
part2 = _1000_to_text_nl(number / 1000) + space + thousands_nl[1]
if part2 and part1:
part1 = ' ' + part1
return part2 + part1
def amount_to_text_nl(number, currency):
units_number = int(number)
units_name = currency
units = _10000_to_text_nl(units_number)
units = units_number and '%s %s' % (units, units_name) or ''
cents_number = int(number * 100) % 100
cents_name = 'cent'
cents = _100_to_text_nl(cents_number)
cents = cents_number and '%s %s' % (cents, cents_name) or ''
if units and cents:
cents = ' ' + cents
return units + cents
list = str(number).split('.')
start_word = dutch_number(int(list[0]))
end_word = dutch_number(int(list[1]))
cents_number = int(list[1])
cents_name = (cents_number > 1) and 'cent' or 'cent'
final_result = start_word +' '+units_name+' '+ end_word +' '+cents_name
return final_result
#-------------------------------------------------------------
# Generic functions
@ -183,17 +164,17 @@ def amount_to_text(nbr, lang='fr', currency='euro'):
Example:
1654: mille six cent cinquante-quatre.
"""
if nbr > 1000000:
#TODO: use logger
print "WARNING: number too large '%d', can't translate it!" % (nbr,)
return str(nbr)
# if nbr > 1000000:
##TODO: use logger
# print "WARNING: number too large '%d', can't translate it!" % (nbr,)
# return str(nbr)
if not _translate_funcs.has_key(lang):
#TODO: use logger
print "WARNING: no translation function found for lang: '%s'" % (lang,)
#TODO: (default should be en) same as above
lang = 'fr'
return _translate_funcs[lang](nbr, currency)
return _translate_funcs[lang](abs(nbr), currency)
if __name__=='__main__':
from sys import argv

View File

@ -23,85 +23,66 @@
#-------------------------------------------------------------
#ENGLISH
#-------------------------------------------------------------
from tools.translate import _
ones = {
0: '', 1:'One', 2:'Two', 3:'Three', 4:'Four', 5:'Five', 6:'Six', 7:'Seven', 8:'Eight', 9:'Nine',
10:'Ten', 11:'Eleven', 12:'Twelve', 13:'Thirteen', 14:'Forteen', 15:'Fifteen', 16:'Sixteen', 17:"Seventeen",18:"Eighteen",19:"Nineteen",
}
to_19 = ( 'Zero', 'One', 'Two', 'Three', 'Four', 'Five', 'Six',
'Seven', 'Eight', 'Nine', 'Ten', 'Eleven', 'Twelve', 'Thirteen',
'Fourteen', 'Fifteen', 'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen' )
tens = ( 'Twenty', 'Thirty', 'Forty', 'Fifty', 'Sixty', 'Seventy', 'Eighty', 'Ninety')
denom = ( '',
'Thousand', 'Million', 'Billion', 'Trillion', 'Quadrillion',
'Quintillion', 'Sextillion', 'Septillion', 'Octillion', 'Nonillion',
'Decillion', 'Undecillion', 'Duodecillion', 'Tredecillion', 'Quattuordecillion',
'Sexdecillion', 'Septendecillion', 'Octodecillion', 'Novemdecillion', 'Vigintillion' )
tens = {
1: 'Ten', 2: 'Twenty ', 3:'Thirty', 4:'Forty', 5:'Fifty', 6: 'Sixty', 7 : 'Seventy', 8:'Eighty' ,9: 'Ninety'}
# convert a value < 100 to English.
def _convert_nn(val):
if val < 20:
return to_19[val]
for (dcap, dval) in ((k, 20 + (10 * v)) for (v, k) in enumerate(tens)):
if dval + 10 > val:
if val % 10:
return dcap + '-' + to_19[val % 10]
return dcap
hundred = {
0:'',1: 'One Hundred', 2: 'Two Hundred', 3: 'Three Hundred', 4 :'Four Hundred', 5: 'Five Hundred', 6: 'Six Hundred', 7 :'Seven Hundred', 8:' Eight Hundred ', 9:'Nine Hundred '
}
thousands ={
0:'',1: 'One Thousand'
}
lacs = {
0:'',1: 'Lac'
}
def _100_to_text(number):
if number in ones:
return ones[number]
else:
if number%10>0:
return tens[number / 10]+'-'+ones[number % 10]
else:
return tens[number / 10]
def _1000_to_text(number):
d = _100_to_text(number % 100)
d2 = number/100
if d2>0 and d:
return hundred[d2]+' '+d
elif d2>1 and not(d):
return hundred[d2]+'s'
else:
return hundred[d2] or d
def _10000_to_text(number):
if number==0:
return 'zero'
part1 = _1000_to_text(number % 1000)
part2 = thousands.get(number / 1000, _1000_to_text(number / 1000)+' Thousands')
if part2 and part1:
part1 = ' '+part1
return part2+part1
def _1000000_to_text(number):
if number==0:
return 'zero'
part1 = _10000_to_text(number % 100000)
part2 = lacs.get(number / 100000, _10000_to_text(number / 100000)+' Lacs')
if part2 and part1:
part1 = ' '+part1
return part2+part1
# convert a value < 1000 to english, special cased because it is the level that kicks
# off the < 100 special case. The rest are more general. This also allows you to
# get strings in the form of 'forty-five hundred' if called directly.
def _convert_nnn(val):
word = ''
(mod, rem) = (val % 100, val // 100)
if rem > 0:
word = to_19[rem] + ' Hundred'
if mod > 0:
word = word + ' '
if mod > 0:
word = word + _convert_nn(mod)
return word
def english_number(val):
if val < 100:
return _convert_nn(val)
if val < 1000:
return _convert_nnn(val)
for (didx, dval) in ((v - 1, 1000 ** v) for v in range(len(denom))):
if dval > val:
mod = 1000 ** didx
l = val // mod
r = val - (l * mod)
ret = _convert_nnn(l) + ' ' + denom[didx]
if r > 0:
ret = ret + ', ' + english_number(r)
return ret
def amount_to_text(number, currency):
lacs_number = int(number)
units_name = currency
if lacs_number > 1:
units_name += 's'
lacs = _1000000_to_text(lacs_number)
lacs = lacs_number and '%s %s' % (lacs, units_name) or ''
units_number = int(number * 10000) % 10000
units = _10000_to_text(units_number)
units = units_number and '%s %s' % (units, units_name) or ''
cents_number = int(number * 100) % 100
cents_name = (cents_number > 1) and 'cents' or 'cent'
cents = _100_to_text(cents_number)
cents = cents_number and '%s %s' % (cents.lower(), cents_name) or ''
if cents:
lacs += ' and %s' % (cents, )
return lacs
list = str(number).split('.')
start_word = english_number(int(list[0]))
end_word = english_number(int(list[1]))
cents_number = int(list[1])
cents_name = (cents_number > 1) and 'Cents' or 'Cent'
final_result = start_word +' '+units_name+' and ' + end_word +' '+cents_name
return final_result
#-------------------------------------------------------------
@ -119,15 +100,15 @@ def amount_to_text(nbr, lang='en', currency='euro'):
1654: thousands six cent cinquante-quatre.
"""
import netsvc
if nbr > 10000000:
netsvc.Logger().notifyChannel('translate', netsvc.LOG_WARNING, _("Number too large '%d', can not translate it"))
return str(nbr)
# if nbr > 10000000:
# netsvc.Logger().notifyChannel('translate', netsvc.LOG_WARNING, _("Number too large '%d', can not translate it"))
# return str(nbr)
if not _translate_funcs.has_key(lang):
netsvc.Logger().notifyChannel('translate', netsvc.LOG_WARNING, _("no translation function found for lang: '%s'" % (lang,)))
#TODO: (default should be en) same as above
lang = 'en'
return _translate_funcs[lang](nbr, currency)
return _translate_funcs[lang](abs(nbr), currency)
if __name__=='__main__':
from sys import argv