# Copyright (c) 2003, Taro Ogawa. All Rights Reserved. # Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved. # Copyright (c) 2022, Sergei Ruzki. 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 .utils import get_digits, splitbyx ZERO = "нуль" ONES_FEMININE = { 1: "адна", 2: "дзве", 3: "тры", 4: "чатыры", 5: "пяць", 6: "шэсць", 7: "сем", 8: "восем", 9: "дзевяць", } ONES = { "f": { 1: "адна", 2: "дзве", 3: "тры", 4: "чатыры", 5: "пяць", 6: "шэсць", 7: "сем", 8: "восем", 9: "дзевяць", }, "m": { 1: "адзін", 2: "два", 3: "тры", 4: "чатыры", 5: "пяць", 6: "шэсць", 7: "сем", 8: "восем", 9: "дзевяць", }, "n": { 1: "адно", 2: "два", 3: "тры", 4: "чатыры", 5: "пяць", 6: "шэсць", 7: "сем", 8: "восем", 9: "дзевяць", }, } TENS = { 0: "дзесяць", 1: "адзінаццаць", 2: "дванаццаць", 3: "трынаццаць", 4: "чатырнаццаць", 5: "пятнаццаць", 6: "шаснаццаць", 7: "сямнаццаць", 8: "васямнаццаць", 9: "дзевятнаццаць", } TWENTIES = { 2: "дваццаць", 3: "трыццаць", 4: "сорак", 5: "пяцьдзясят", 6: "шэсцьдзясят", 7: "семдзесят", 8: "восемдзесят", 9: "дзевяноста", } TWENTIES_ORD = ( ("дваццаць", "дваццаці"), ("трыццаць", "трыццаці"), ("сорак", "сарака"), ("пяцьдзясят", "пяцідзясяці"), ("шэсцьдзясят", "шaсцідзясяці"), ("семдзесят", "сямідзесяці"), ("восемдзесят", "васьмідзесяці"), ("дзевяноста", "дзевяноста"), ) HUNDREDS = { 1: "сто", 2: "дзвесце", 3: "трыста", 4: "чатырыста", 5: "пяцьсот", 6: "шэсцьсот", 7: "семсот", 8: "восемсот", 9: "дзевяцьсот", } THOUSANDS = { 1: ("тысяча", "тысячы", "тысяч"), # 10^3 2: ("мільён", "мільёны", "мільёнаў"), # 10^6 3: ("мільярд", "мільярды", "мільярдаў"), # 10^9 4: ("трыльён", "трыльёны", "трыльёнаў"), # 10^12 5: ("квадрыльён", "квадрыльёны", "квадрыльёнаў"), # 10^15 6: ("квінтыльён", "квінтыльёны", "квінтыльёнаў"), # 10^18 7: ("секстыльён", "секстыльёны", "секстыльёнаў"), # 10^21 8: ("сэптыльён", "сэптыльёны", "сэптыльёнаў"), # 10^24 9: ("актыльён", "актыльёны", "актыльёнаў"), # 10^27 10: ("нанільён", "нанільёны", "нанільёнаў"), # 10^30 } class Num2Word_BE(Num2Word_Base): CURRENCY_FORMS = { "RUB": ( ("расійскі рубель", "расійскія рублі", "расійскіх рублёў"), ("капейка", "капейкі", "капеек"), ), "EUR": (("еўра", "еўра", "еўра"), ("цэнт", "цэнты", "цэнтаў")), "USD": (("долар", "долары", "долараў"), ("цэнт", "цэнты", "цэнтаў")), "UAH": ( ("грыўна", "грыўны", "грыўнаў"), ("капейка", "капейкі", "капеек"), ), "KZT": (("тэнге", "тэнге", "тэнге"), ("тыйін", "тыйіны", "тыйінаў")), "BYN": ( ("беларускі рубель", "беларускія рублі", "беларускіх рублёў"), ("капейка", "капейкі", "капеек"), ), "UZS": (("сум", "сумы", "сумаў"), ("тыйін", "тыйіны", "тыйінаў")), "PLN": (("злоты", "злотых", "злотых"), ("грош", "грошы", "грошаў")), } def setup(self): self.negword = "мінус" self.pointword = "коска" self.ords = { "нуль": "нулявы", "адзін": "першы", "два": "другі", "тры": "трэці", "чатыры": "чацвёрты", "пяць": "пяты", "шэсць": "шосты", "сем": "сёмы", "восем": "восьмы", "дзевяць": "дзявяты", "сто": "соты", "тысяча": "тысячны", } self.ords_adjective = { "адзін": "адна", "адна": "адна", "дзве": "двух", "тры": "трох", "чатыры": "чатырох", "пяць": "пяці", "шэсць": "шасці", "сем": "сямі", "восем": "васьмі", "дзевяць": "дзевяцi", "сто": "ста", } def to_cardinal(self, number, gender="m"): n = str(number).replace(",", ".") if "." in n: left, right = n.split(".") if set(right) == {"0"}: leading_zero_count = 0 else: leading_zero_count = len(right) - len(right.lstrip("0")) decimal_part = (ZERO + " ") * leading_zero_count + self._int2word( int(right), gender ) return "{} {} {}".format( self._int2word(int(left), gender), self.pointword, decimal_part ) else: return self._int2word(int(n), gender) def pluralize(self, n, forms): if n % 100 < 10 or n % 100 > 20: if n % 10 == 1: form = 0 elif 5 > n % 10 > 1: form = 1 else: form = 2 else: form = 2 return forms[form] def to_ordinal(self, number, gender="m"): self.verify_ordinal(number) if isinstance(gender, bool) and gender: gender = "f" outwords = self.to_cardinal(number, gender).split(" ") lastword = outwords[-1].lower() try: if len(outwords) > 1: if outwords[-2] in self.ords_adjective: outwords[-2] = self.ords_adjective.get( outwords[-2], outwords[-2] ) elif outwords[-2] == "дзесяць": outwords[-2] = outwords[-2][:-1] + "і" if len(outwords) == 3: if outwords[-3] in ["адзін", "адна"]: outwords[-3] = "" lastword = self.ords[lastword] except KeyError: if lastword[:-3] in self.ords_adjective: lastword = ( self.ords_adjective.get(lastword[:-3], lastword) + "соты" ) elif lastword[-7:] == "дзесяць": lastword = "дзясяты" elif lastword[-9:] == "семдзесят": lastword = "сямідзясяты" elif lastword[-1] == "ь" or lastword[-2] == "ц": lastword = lastword[:-2] + "ты" elif lastword[-1] == "к": lastword = lastword.replace("о", "а") + "авы" elif lastword[-2] == "ч" or lastword[-1] == "ч": if lastword[-2] == "ч": lastword = lastword[:-1] + "ны" if lastword[-1] == "ч": lastword = lastword + "ны" elif lastword[-1] == "н" or lastword[-2] == "н": lastword = lastword[: lastword.rfind("н") + 1] + "ны" elif lastword[-3:] == "наў": lastword = lastword[: lastword.rfind("н") + 1] + "ны" elif lastword[-1] == "д" or lastword[-2] == "д": lastword = lastword[: lastword.rfind("д") + 1] + "ны" if gender == "f": if lastword[-2:] in [ "ці", ]: lastword = lastword[:-2] + "цяя" else: lastword = lastword[:-1] + "ая" if gender == "n": if lastword[-2:] in ["ці", "ца"]: lastword = lastword[:-2] + "цяе" else: lastword = lastword[:-1] + "ае" outwords[-1] = self.title(lastword) if len(outwords) == 2 and "адна" in outwords[-2]: outwords[-2] = outwords[-1] del outwords[-1] if len(outwords) > 1 and ( (any(x[0] in outwords[-1] for x in THOUSANDS.values())) or "тысяч" in outwords[-1] ): new_outwords = [] for _w in outwords: replacement = next( (x for x in TWENTIES_ORD if x[0] in _w), None ) if replacement: _w = _w.replace(replacement[0], replacement[1]) new_outwords.append(_w) outwords = ["".join(new_outwords)] return " ".join(outwords).strip() def _money_verbose(self, number, currency): gender = "m" if currency == "UAH": gender = "f" return self._int2word(number, gender) def _cents_verbose(self, number, currency): if currency in ("UAH", "RUB", "BYN"): gender = "f" else: gender = "m" return self._int2word(number, gender) def _int2word(self, n, gender="m"): if n < 0: return " ".join([self.negword, self._int2word(abs(n), gender)]) if n == 0: return ZERO words = [] chunks = list(splitbyx(str(n), 3)) i = len(chunks) for x in chunks: i -= 1 if x == 0: continue n1, n2, n3 = get_digits(x) if n3 > 0: words.append(HUNDREDS[n3]) if n2 > 1: words.append(TWENTIES[n2]) if n2 == 1: words.append(TENS[n1]) elif n1 > 0: if i == 0: ones = ONES[gender] elif i == 1: ones = ONES["f"] # Thousands are feminine else: ones = ONES["m"] words.append(ones[n1]) if i > 0: words.append(self.pluralize(x, THOUSANDS[i])) return " ".join(words)