Skip to content

Commit

Permalink
Add gender and morphological cases support for Ukrainian
Browse files Browse the repository at this point in the history
Added two parameters: gender and case
gender can accept either 'masculine' (default)  or 'feminine'
case can accept either 'nominative' (default) or
'genitive','dative','accusative','instrumetnal','locative' and
'vocative'.

This parameters now working only for to='cardinal'
  • Loading branch information
kant2002 committed Jul 28, 2023
1 parent 872510d commit 5635a41
Show file tree
Hide file tree
Showing 2 changed files with 698 additions and 66 deletions.
155 changes: 89 additions & 66 deletions num2words/lang_UK.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,27 @@
ZERO = ('нуль',)

ONES_FEMININE = {
1: ('одна',),
2: ('дві',),
3: ('три',),
4: ('чотири',),
5: ('п\'ять',),
6: ('шість',),
7: ('сім',),
8: ('вісім',),
9: ('дев\'ять',),
1: ('одна', "однієї", "одній", "одну", "однією", "одній"),
2: ('дві', "двох", "двом", "дві", "двома", "двох"),
3: ('три', "трьох", "трьом", "три", "трьома", "трьох"),
4: ('чотири', "чотирьох", "чотирьом", "чотири", "чотирма", "чотирьох"),
5: ('п\'ять', "п'яти", "п'яти", "п'ять", "п'ятьма", "п'яти"),
6: ('шість', "шести", "шести", "шість", "шістьма", "шести"),
7: ('сім', "семи", "семи", "сім", "сьома", "семи"),
8: ('вісім', "восьми", "восьми", "вісім", "вісьма", "восьми"),
9: ("дев'ять", "дев'яти", "дев'яти", "дев'ять", "дев'ятьма","дев'яти"),
}

ONES = {
1: ('один',),
2: ('два',),
3: ('три',),
4: ('чотири',),
5: ('п\'ять',),
6: ('шість',),
7: ('сім',),
8: ('вісім',),
9: ('дев\'ять',),
1: ('один', 'одного', "одному", "один", "одним", "одному"),
2: ('два', 'двох', "двом", "два", "двома", "двох"),
3: ('три', 'трьох', "трьом", "три", "трьома", "трьох"),
4: ('чотири', 'чотирьох', "чотирьом", "чотири", "чотирма", "чотирьох"),
5: ('п\'ять', "п'яти", "п'яти", "п'ять", "п'ятьма", "п'яти"),
6: ('шість', 'шести', "шести", "шість", "шістьма", "шести"),
7: ('сім', 'семи', "семи", "сім", "сьома", "семи"),
8: ('вісім', 'восьми', "восьми", "вісім", "вісьма", "восьми"),
9: ('дев\'ять', "дев'яти", "дев'яти", "дев'ять", "дев'ятьма","дев'яти"),
}

ONES_ORDINALS = {
Expand All @@ -69,27 +69,27 @@
}

TENS = {
0: ('десять',),
1: ('одинадцять',),
2: ('дванадцять',),
3: ('тринадцять',),
4: ('чотирнадцять',),
5: ('п\'ятнадцять',),
6: ('шістнадцять',),
7: ('сімнадцять',),
8: ('вісімнадцять',),
9: ('дев\'ятнадцять',),
0: ('десять', 'десяти', "десяти", "десять", "десятьма", "десяти"),
1: ('одинадцять', 'одинадцяти', "одинадцяти", "одинадцять", "одинадцятьма", "одинадцяти"),
2: ('дванадцять', 'дванадцяти', "дванадцяти", "дванадцять", "дванадцятьма", "дванадцяти"),
3: ('тринадцять', 'тринадцяти', "тринадцяти", "тринадцять", "тринадцятьма", "тринадцяти"),
4: ('чотирнадцять', 'чотирнадцяти', "чотирнадцяти", "чотирнадцять", "чотирнадцятьма", "чотирнадцяти"),
5: ("п'ятнадцять", "п'ятнадцяти", "п'ятнадцяти", "п'ятнадцять", "п'ятнадцятьма", "п'ятнадцяти"),
6: ('шістнадцять', 'шістнадцяти', "шістнадцяти", "шістнадцять", "шістнадцятьма", "шістнадцяти"),
7: ('сімнадцять', 'сімнадцяти', "сімнадцяти", "сімнадцять", "сімнадцятьма", "сімнадцяти"),
8: ('вісімнадцять', 'вісімнадцяти', "вісімнадцяти", "вісімнадцять", "вісімнадцятьма", "вісімнадцяти"),
9: ("дев'ятнадцять","дев'ятнадцяти","дев'ятнадцяти","дев'ятнадцять","дев'ятнадцятьма", "дев'ятнадцяти"),
}

TWENTIES = {
2: ('двадцять',),
3: ('тридцять',),
4: ('сорок',),
5: ('п\'ятдесят',),
6: ('шістдесят',),
7: ('сімдесят',),
8: ('вісімдесят',),
9: ('дев\'яносто',),
2: ('двадцять', "двадцяти", "двадцяти", "двадцять", "двадцятьма", "двадцяти"),
3: ('тридцять', "тридцяти", "тридцяти", "тридцять", "тридцятьма", "тридцяти"),
4: ('сорок', "сорока", "сорока", "сорок", "сорока", "сорока"),
5: ('п\'ятдесят', "п'ятдесяти", "п'ятдесяти", "п'ятдесят", "п'ятдесятьма", "п'ятдесяти"),
6: ('шістдесят', "шістдесяти", "шістдесяти", "шістдесят", "шістдесятьма", "шістдесяти"),
7: ('сімдесят', "сімдесяти", "сімдесяти", "сімдесят", "сімдесятьма", "сімдесяти"),
8: ('вісімдесят', "вісімдесяти", "вісімдесяти", "вісімдесят", "вісімдесятьма","вісімдесяти"),
9: ('дев\'яносто', "дев'яноста", "дев'яноста", "дев'яносто", "дев'яностами", "дев'яноста"),
}

TWENTIES_ORDINALS = {
Expand All @@ -104,15 +104,15 @@
}

HUNDREDS = {
1: ('сто',),
2: ('двісті',),
3: ('триста',),
4: ('чотириста',),
5: ('п\'ятсот',),
6: ('шістсот',),
7: ('сімсот',),
8: ('вісімсот',),
9: ('дев\'ятсот',),
1: ('сто', "ста", "ста", "сто", "стами", "стах"),
2: ('двісті', "двохста", "двомстам", "двісті", "двомастами", "двохстах"),
3: ('триста', "трьохста", "трьомстам", "триста", "трьомастами", "трьохстах"),
4: ('чотириста',"чотирьохста", "чотирьомстам", "чотириста","чотирмастами", "чотирьохстах"),
5: ('п\'ятсот', "п'ятиста", "п'ятистам", "п'ятсот", "п'ятьмастами", "п'ятистах"),
6: ('шістсот', "шестиста", "шестистам", "шістсот", "шістьмастами", "шестистах"),
7: ('сімсот', "семиста", "семистам", "сімсот", "сьомастами", "семистах"),
8: ('вісімсот', "восьмиста", "восьмистам", "вісімсот", "восьмастами", "восьмистах"),
9: ("дев'ятсот","дев'ятиста", "дев'ятистам", "дев'ятсот","дев'ятьмастами","дев'ятистах"),
}

HUNDREDS_ORDINALS = {
Expand All @@ -128,16 +128,28 @@
}

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
# Nominative Genitive Dative Accusative Instrumental Locative
# ----------------------------------------------------- --------------------------------------------------- --------------------------------------------------- --------------------------------------------------- ------------------------------------------------------- --------------------------------------------------------
# 10^3
1: (('тисяча', 'тисячі', 'тисяч'), ('тисячи', 'тисяч', 'тисяч'), ('тисячі', 'тисячам', 'тисячам'), ('тисячу', 'тисячі', 'тисяч'), ('тисячею', 'тисячами', 'тисячами'), ('тисячі', 'тисячах', 'тисячах'),),
# 10^6
2: (('мільйон', 'мільйони', 'мільйонів'), ('мільйона', 'мільйонів', 'мільйонів'), ('мільйону', 'мільйонам', 'мільйонам'), ('мільйон', 'мільйони', 'мільйонів'), ('мільйоном', 'мільйонами', 'мільйонів'), ('мільйоні', 'мільйонах', 'мільйонах'),),
# 10^9
3: (('мільярд', 'мільярди', 'мільярдів'), ('мільярда', 'мільярдів', 'мільярдів'), ('мільярду', 'мільярдам', 'мільярдам'), ('мільярд', 'мільярди', 'мільярдів'), ('мільярдом', 'мільярдами', 'мільярдів'), ('мільярді', 'мільярдах', 'мільярдах'),),
# 10^12
4: (('трильйон', 'трильйони', 'трильйонів'), ('трильйона', 'трильйонів', 'трильйонів'), ('трильйону', 'трильйонам', 'трильйонам'), ('трильйон', 'трильйони', 'трильйонів'), ('трильйоном', 'трильйонами', 'трильйонів'), ('трильйоні', 'трильйонах', 'трильйонах'),),
# 10^15
5: (('квадрильйон', 'квадрильйони', 'квадрильйонів'), ('квадрильйона', 'квадрильйонів', 'квадрильйонів'), ('квадрильйону', 'квадрильйонам', 'квадрильйонам'), ('квадрильйон', 'квадрильйони', 'квадрильйонів'), ('квадрильйоном', 'квадрильйонами', 'квадрильйонів'), ('квадрильйоні', 'квадрильйонах', 'квадрильйонах'),),
# 10^18
6: (('квінтильйон', 'квінтильйони', 'квінтильйонів'), ('квінтильйона', 'квінтильйонів', 'квінтильйонів'), ('квінтильйону', 'квінтильйонам', 'квінтильйонам'), ('квінтильйон', 'квінтильйони', 'квінтильйонів'), ('квінтильйоном', 'квінтильйонами', 'квінтильйонів'), ('квінтильйоні', 'квінтильйонах', 'квінтильйонах'),),
# 10^21
7: (('секстильйон', 'секстильйони', 'секстильйонів'), ('секстильйона', 'секстильйонів', 'секстильйонів'), ('секстильйону', 'секстильйонам', 'секстильйонам'), ('секстильйон', 'секстильйони', 'секстильйонів'), ('секстильйоном', 'секстильйонами', 'секстильйонів'), ('секстильйоні', 'секстильйонах', 'секстильйонах'),),
# 10^24
8: (('септильйон', 'септильйони', 'септильйонів'), ('септильйона', 'септильйонів', 'септильйонів'), ('септильйону', 'септильйонам', 'септильйонам'), ('септильйон', 'септильйони', 'септильйонів'), ('септильйоном', 'септильйонами', 'септильйонів'), ('септильйоні', 'септильйонах', 'септильйонах'),),
# 10^27
9: (('октильйон', 'октильйони', 'октильйонів'), ('октильйона', 'октильйонів', 'октильйонів'), ('октильйону', 'октильйонам', 'октильйонам'), ('октильйон', 'октильйони', 'октильйонів'), ('октильйоном', 'октильйонами', 'октильйонів'), ('октильйоні', 'октильйонах', 'октильйонах'),),
# 10^30
10: (('нонільйон', 'нонільйони', 'нонільйонів'), ('нонільйона', 'нонільйонів', 'нонільйонів'), ('нонільйону', 'нонільйонам', 'нонільйонам'), ('нонільйон', 'нонільйони', 'нонільйонів'), ('нонільйоном', 'нонільйонами', 'нонільйонів'), ('нонільйоні', 'нонільйонах', 'нонільйонах'),),
}

prefixes_ordinal = {
Expand Down Expand Up @@ -711,20 +723,31 @@ def setup(self):
self.negword = "мінус"
self.pointword = "кома"

def to_cardinal(self, number):
def to_cardinal(self, number, **kwargs):
if 'case' in kwargs:
case = kwargs['case']
morphological_case = ["nominative", "genitive", "dative", "accusative", "instrumental", "locative"].index(case)
else:
morphological_case = 0

if 'gender' in kwargs:
gender = kwargs['gender'] == 'feminine'
else:
gender = 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)))
self._int2word(int(right), gender, morphological_case))
return u'%s %s %s' % (
self._int2word(int(left)),
self._int2word(int(left), gender, morphological_case),
self.pointword,
decimal_part
)
else:
return self._int2word(int(n))
return self._int2word(int(n), gender, morphological_case)

def pluralize(self, n, forms):
if n % 100 < 10 or n % 100 > 20:
Expand All @@ -739,9 +762,9 @@ def pluralize(self, n, forms):

return forms[form]

def _int2word(self, n, feminine=False):
def _int2word(self, n, feminine=False, morphological_case = 0):
if n < 0:
return ' '.join([self.negword, self._int2word(abs(n))])
return ' '.join([self.negword, self._int2word(abs(n), feminine, morphological_case)])

if n == 0:
return ZERO[0]
Expand All @@ -758,20 +781,20 @@ def _int2word(self, n, feminine=False):
n1, n2, n3 = get_digits(x)

if n3 > 0:
words.append(HUNDREDS[n3][0])
words.append(HUNDREDS[n3][morphological_case])

if n2 > 1:
words.append(TWENTIES[n2][0])
words.append(TWENTIES[n2][morphological_case])

if n2 == 1:
words.append(TENS[n1][0])
words.append(TENS[n1][morphological_case])
# elif n1 > 0 and not (i > 0 and x == 1):
elif n1 > 0:
ones = ONES_FEMININE if i == 1 or feminine and i == 0 else ONES
words.append(ones[n1][0])
words.append(ones[n1][morphological_case])

if i > 0:
words.append(self.pluralize(x, THOUSANDS[i]))
words.append(self.pluralize(x, THOUSANDS[i][morphological_case]))

return ' '.join(words)

Expand Down
Loading

0 comments on commit 5635a41

Please sign in to comment.