# -*- coding: 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 from __future__ import unicode_literals from .base import Num2Word_Base from .currency import parse_currency_parts, prefix_currency from .utils import get_digits, splitbyx ZERO = ('nula',) ONES = { 1: ('jedan', 'jedna'), 2: ('dva', 'dve'), 3: ('tri', 'tri'), 4: ('četiri', 'četiri'), 5: ('pet', 'pet'), 6: ('šest', 'šest'), 7: ('sedam', 'sedam'), 8: ('osam', 'osam'), 9: ('devet', 'devet'), } TENS = { 0: ('deset',), 1: ('jedanaest',), 2: ('dvanaest',), 3: ('trinaest',), 4: ('četrnaest',), 5: ('petnaest',), 6: ('šesnaest',), 7: ('sedamnaest',), 8: ('osamnaest',), 9: ('devetnaest',), } TWENTIES = { 2: ('dvadeset',), 3: ('trideset',), 4: ('četrdeset',), 5: ('pedeset',), 6: ('šezdeset',), 7: ('sedamdeset',), 8: ('osamdeset',), 9: ('devedeset',), } HUNDREDS = { 1: ('sto',), 2: ('dvesta',), 3: ('trista',), 4: ('četristo',), 5: ('petsto',), 6: ('šesto',), 7: ('sedamsto',), 8: ('osamsto',), 9: ('devetsto',), } SCALE = { 0: ('', '', '', False), 1: ('hiljada', 'hiljade', 'hiljada', True), # 10^3 2: ('milion', 'miliona', 'miliona', False), # 10^6 3: ('bilion', 'biliona', 'biliona', False), # 10^9 4: ('trilion', 'triliona', 'triliona', False), # 10^12 5: ('kvadrilion', 'kvadriliona', 'kvadriliona', False), # 10^15 6: ('kvintilion', 'kvintiliona', 'kvintiliona', False), # 10^18 7: ('sekstilion', 'sekstiliona', 'sekstiliona', False), # 10^21 8: ('septilion', 'septiliona', 'septiliona', False), # 10^24 9: ('oktilion', 'oktiliona', 'oktiliona', False), # 10^27 10: ('nonilion', 'noniliona', 'noniliona', False), # 10^30 } class Num2Word_SR(Num2Word_Base): CURRENCY_FORMS = { 'RUB': ( ('rublja', 'rublje', 'rublji', True), ('kopejka', 'kopejke', 'kopejki', True) ), 'EUR': ( ('evro', 'evra', 'evra', False), ('cent', 'centa', 'centi', False) ), 'RSD': ( ('dinar', 'dinara', 'dinara', False), ('para', 'pare', 'para', True) ), } def setup(self): self.negword = "minus" self.pointword = "zapeta" def to_cardinal(self, number, feminine=False): n = str(number).replace(',', '.') if '.' in n: left, right = n.split('.') leading_zero_count = len(right) - len(right.lstrip('0')) decimal_part = ((ZERO[0] + ' ') * leading_zero_count + self._int2word(int(right), feminine)) return u'%s %s %s' % ( self._int2word(int(left), feminine), self.pointword, decimal_part ) else: return self._int2word(int(n), feminine) def pluralize(self, number, forms): if number % 100 < 10 or number % 100 > 20: if number % 10 == 1: form = 0 elif 1 < number % 10 < 5: form = 1 else: form = 2 else: form = 2 return forms[form] def to_ordinal(self, number): raise NotImplementedError() def _cents_verbose(self, number, currency): return self._int2word( number, self.CURRENCY_FORMS[currency][1][-1] ) def _int2word(self, number, feminine=False): if number < 0: return ' '.join([self.negword, self._int2word(abs(number))]) if number == 0: return ZERO[0] words = [] chunks = list(splitbyx(str(number), 3)) chunk_len = len(chunks) for chunk in chunks: chunk_len -= 1 digit_right, digit_mid, digit_left = get_digits(chunk) if digit_left > 0: words.append(HUNDREDS[digit_left][0]) if digit_mid > 1: words.append(TWENTIES[digit_mid][0]) if digit_mid == 1: words.append(TENS[digit_right][0]) elif digit_right > 0: is_feminine = feminine or SCALE[chunk_len][-1] gender_idx = int(is_feminine) words.append( ONES[digit_right][gender_idx] ) if chunk_len > 0 and chunk != 0: words.append(self.pluralize(chunk, SCALE[chunk_len])) return ' '.join(words) def to_currency(self, val, currency='EUR', cents=True, separator=',', adjective=False): """ Args: val: Numeric value currency (str): Currency code cents (bool): Verbose cents separator (str): Cent separator adjective (bool): Prefix currency name with adjective Returns: str: Formatted string """ left, right, is_negative = parse_currency_parts(val) try: cr1, cr2 = self.CURRENCY_FORMS[currency] except KeyError: raise NotImplementedError( 'Currency code "%s" not implemented for "%s"' % (currency, self.__class__.__name__)) if adjective and currency in self.CURRENCY_ADJECTIVES: cr1 = prefix_currency( self.CURRENCY_ADJECTIVES[currency], cr1 ) minus_str = "%s " % self.negword if is_negative else "" cents_str = self._cents_verbose(right, currency) \ if cents else self._cents_terse(right, currency) return u'%s%s %s%s %s %s' % ( minus_str, self.to_cardinal(left, feminine=cr1[-1]), self.pluralize(left, cr1), separator, cents_str, self.pluralize(right, cr2) )