Skip to content

Commit

Permalink
Add gender support for ordinal numbers in Ukrainian
Browse files Browse the repository at this point in the history
  • Loading branch information
kant2002 committed Dec 11, 2023
1 parent 974f7a8 commit 8cf971b
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 64 deletions.
134 changes: 70 additions & 64 deletions num2words/lang_UK.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,25 +47,25 @@
}

ONES_ORDINALS = {
1: ("перший", "одно"),
2: ("другий", "двох"),
3: ("третій", "трьох"),
4: ("четвертий", "чотирьох"),
5: ("п'ятий", "п'яти"),
6: ("шостий", "шести"),
7: ("сьомий", "семи"),
8: ("восьмий", "восьми"),
9: ("дев'ятий", "дев'яти"),
10: ("десятий", "десяти"),
11: ("одинадцятий", "одинадцяти"),
12: ("дванадцятий", "дванадцяти"),
13: ("тринадцятий", "тринадцяти"),
14: ("чотирнадцятий", "чотирнадцяти"),
15: ("п'ятнадцятий", "п'ятнадцяти"),
16: ("шістнадцятий", "шістнадцяти"),
17: ("сімнадцятий", "сімнадцяти"),
18: ("вісімнадцятий", "вісімнадцяти"),
19: ("дев'ятнадцятий", "дев'ятнадцяти"),
1: ("перший", "перша", "одно"),
2: ("другий", "друга", "двох"),
3: ("третій", "третя", "трьох"),
4: ("четвертий", "четверта", "чотирьох"),
5: ("п'ятий", "п'ята", "п'яти"),
6: ("шостий", "шоста", "шести"),
7: ("сьомий", "сьома", "семи"),
8: ("восьмий", "восьма", "восьми"),
9: ("дев'ятий", "дев'ята", "дев'яти"),
10: ("десятий", "десята", "десяти"),
11: ("одинадцятий", "одинадцята", "одинадцяти"),
12: ("дванадцятий", "дванадцята", "дванадцяти"),
13: ("тринадцятий", "тринадцята", "тринадцяти"),
14: ("чотирнадцятий", "чотирнадцята", "чотирнадцяти"),
15: ("п'ятнадцятий", "п'ятнадцята", "п'ятнадцяти"),
16: ("шістнадцятий", "шістнадцята", "шістнадцяти"),
17: ("сімнадцятий", "сімнадцята", "сімнадцяти"),
18: ("вісімнадцятий", "вісімнадцята", "вісімнадцяти"),
19: ("дев'ятнадцятий", "дев'ятнадцята", "дев'ятнадцяти"),
}
TENS = {
0: ('десять',
Expand Down Expand Up @@ -182,14 +182,14 @@
}

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

HUNDREDS = {
Expand Down Expand Up @@ -250,15 +250,15 @@
}

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

THOUSANDS = {
Expand Down Expand Up @@ -335,16 +335,16 @@
}

prefixes_ordinal = {
1: "тисячний",
2: "мільйонний",
3: "мільярдний",
4: "трильйонний",
5: "квадрильйонний",
6: "квінтильйонний",
7: "секстильйонний",
8: "септильйонний",
9: "октильйонний",
10: "нонільйонний",
1: ("тисячний","тисячна"),
2: ("мільйонний","мільйонна"),
3: ("мільярдний","мільярдна"),
4: ("трильйонний","трильйонна"),
5: ("квадрильйонний","квадрильйонна"),
6: ("квінтильйонний","квінтильйонна"),
7: ("секстильйонний","секстильйонна"),
8: ("септильйонний","септильйонна"),
9: ("октильйонний","октильйонна"),
10: ("нонільйонний","нонільйонна"),
}

FEMININE_MONEY = ('AOA', 'BAM', 'BDT', 'BWP', 'CZK', 'DKK',
Expand Down Expand Up @@ -997,52 +997,57 @@ def _cents_verbose(self, number, currency):
return self._int2word(number, currency in FEMININE_CENTS)

@staticmethod
def last_fragment_to_ordinal(last, words, level):
def last_fragment_to_ordinal(last, words, level, gender_index):
n1, n2, n3 = get_digits(last)
last_two = n2*10+n1
if last_two == 0:
words.append(HUNDREDS_ORDINALS[n3][level])
elif level == 1 and last == 1:
elif level == 2 and last == 1:
return
elif last_two < 20:
if level == 0:
if level != 2:
if n3 > 0:
words.append(HUNDREDS[n3][0])
words.append(ONES_ORDINALS[last_two][0])
words.append(ONES_ORDINALS[last_two][gender_index])
else:
last_fragment_string = ''
if n3 > 0:
last_fragment_string += HUNDREDS_ORDINALS[n3][1]
last_fragment_string += ONES_ORDINALS[last_two][1]
last_fragment_string += HUNDREDS_ORDINALS[n3][2]
last_fragment_string += ONES_ORDINALS[last_two][2]
words.append(last_fragment_string)
elif last_two % 10 == 0:
if level == 0:
if level != 2:
if n3 > 0:
words.append(HUNDREDS[n3][0])
words.append(TWENTIES_ORDINALS[n2][0])
words.append(TWENTIES_ORDINALS[n2][gender_index])
else:
last_fragment_string = ''
if n3 > 0:
last_fragment_string += HUNDREDS_ORDINALS[n3][1]
last_fragment_string += TWENTIES_ORDINALS[n2][1]
last_fragment_string += HUNDREDS_ORDINALS[n3][2]
last_fragment_string += TWENTIES_ORDINALS[n2][2]
words.append(last_fragment_string)
else:
if level == 0:
if level != 2:
if n3 > 0:
words.append(HUNDREDS[n3][0])
words.append(TWENTIES[n2][0])
words.append(ONES_ORDINALS[n1][0])
words.append(ONES_ORDINALS[n1][gender_index])
else:
last_fragment_string = ''
if n3 > 0:
last_fragment_string += HUNDREDS_ORDINALS[n3][1]
last_fragment_string += TWENTIES_ORDINALS[n2][1]
last_fragment_string += ONES_ORDINALS[n1][1]
last_fragment_string += HUNDREDS_ORDINALS[n3][2]
last_fragment_string += TWENTIES_ORDINALS[n2][2]
last_fragment_string += ONES_ORDINALS[n1][2]
words.append(last_fragment_string)

def to_ordinal(self, number):
def to_ordinal(self, number, **kwargs):
self.verify_ordinal(number)

if 'gender' in kwargs:
gender = kwargs['gender'] == 'feminine'
else:
gender = False

words = []
fragments = list(splitbyx(str(number), 3))
level = 0
Expand All @@ -1057,11 +1062,12 @@ def to_ordinal(self, number):
Num2Word_UK.last_fragment_to_ordinal(
last,
words,
0 if level == 0 else 1
(1 if gender else 0) if level == 0 else 2,
1 if gender else 0
)
output = " ".join(words)
if last == 1 and level > 0 and output != "":
output = output + " "
if level > 0:
output = output + prefixes_ordinal[level]
output = output + prefixes_ordinal[level][1 if gender else 0]
return output
85 changes: 85 additions & 0 deletions tests/test_uk.py
Original file line number Diff line number Diff line change
Expand Up @@ -779,6 +779,86 @@
"дев'ятсотп'ятдесятишестинонільйонний"),
)

TEST_CASES_ORDINAL_FEMININE = (
(1, "перша"),
(2, "друга"),
(3, "третя"),
(4, "четверта"),
(5, "п'ята"),
(6, "шоста"),
(7, "сьома"),
(8, "восьма"),
(9, "дев'ята"),
(10, "десята"),
(11, "одинадцята"),
(12, "дванадцята"),
(13, "тринадцята"),
(14, "чотирнадцята"),
(15, "п'ятнадцята"),
(16, "шістнадцята"),
(17, "сімнадцята"),
(18, "вісімнадцята"),
(19, "дев'ятнадцята"),
(20, "двадцята"),
(21, "двадцять перша"),
(30, "тридцята"),
(32, "тридцять друга"),
(40, "сорокова"),
(43, "сорок третя"),
(50, "п'ятдесята"),
(54, "п'ятдесят четверта"),
(60, "шістдесята"),
(65, "шістдесят п'ята"),
(70, "сімдесята"),
(76, "сімдесят шоста"),
(80, "вісімдесята"),
(87, "вісімдесят сьома"),
(90, "дев'яноста"),
(98, "дев'яносто восьма"),
(100, "сота"),
(101, "сто перша"),
(199, "сто дев'яносто дев'ята"),
(200, "двохсота"),
(203, "двісті третя"),
(300, "трьохсота"),
(356, "триста п'ятдесят шоста"),
(400, "чотирьохсота"),
(434, "чотириста тридцять четверта"),
(500, "п'ятисота"),
(578, "п'ятсот сімдесят восьма"),
(600, "шестисота"),
(690, "шістсот дев'яноста"),
(700, "семисота"),
(729, "сімсот двадцять дев'ята"),
(800, "восьмисота"),
(894, "вісімсот дев'яносто четверта"),
(900, "дев'ятисота"),
(999, "дев'ятсот дев'яносто дев'ята"),
(1000, "тисячна"),
(1001, "одна тисяча перша"),
(2000, "двохтисячна"),
(2312, "дві тисячі триста дванадцята"),
(12000, "дванадцятитисячна"),
(25000, "двадцятип'ятитисячна"),
(213000, "двохсоттринадцятитисячна"),
(256000, "двохсотп'ятдесятишеститисячна"),
(260000, "двохсотшістдесятитисячна"),
(1000000, "мільйонна"),
(589000000, "п'ятсотвісімдесятидев'ятимільйонна"),
(1000000000, "мільярдна"),
(1234567890, "один мільярд двісті тридцять чотири мільйони "
"п'ятсот шістдесят сім тисяч вісімсот дев'яноста"),
(1000000000000, "трильйонна"),
(1000000000000000, "квадрильйонна"),
(1000000000000000000, "квінтильйонна"),
(1000000000000000000000, "секстильйонна"),
(1000000000000000000000000, "септильйонна"),
(1000000000000000000000000000, "октильйонна"),
(1000000000000000000000000000000, "нонільйонна"),
(956000000000000000000000000000000,
"дев'ятсотп'ятдесятишестинонільйонна"),
)

TEST_CASES_TO_CURRENCY_AED = (
(0.00, "нуль дирхамів, нуль філсів"),
(1.00, "один дирхам, нуль філсів"),
Expand Down Expand Up @@ -3082,6 +3162,11 @@ def test_to_ordinal(self):
test[1]
)

def test_to_ordinal_feminine(self):
for test in TEST_CASES_ORDINAL_FEMININE:
word = num2words(test[0], lang='uk', to='ordinal', gender='feminine')
self.assertEqual(word, test[1])

def test_to_currency(self):
for test in TEST_CASES_TO_CURRENCY_AED:
self.assertEqual(
Expand Down

0 comments on commit 8cf971b

Please sign in to comment.