mirror of
https://github.com/bblaz/num2words.git
synced 2025-12-06 06:42:25 +00:00
Merge branch 'master' into add-tajik-lang
This commit is contained in:
45
.github/workflows/ci.yml
vendored
Normal file
45
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: [3.6, 3.7, 3.8, 3.9, '3.10']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install tox tox-gh-actions coveralls
|
||||||
|
pip install -r requirements-test.txt
|
||||||
|
- name: Test with tox
|
||||||
|
run: |
|
||||||
|
tox
|
||||||
|
- name: Upload coverage data to coveralls.io
|
||||||
|
run: coveralls --service=github
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
COVERALLS_FLAG_NAME: ${{ matrix.python-version }}
|
||||||
|
COVERALLS_PARALLEL: true
|
||||||
|
|
||||||
|
coveralls:
|
||||||
|
name: Indicate completion to coveralls.io
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container: python:3-slim
|
||||||
|
steps:
|
||||||
|
- name: Finished
|
||||||
|
run: |
|
||||||
|
pip3 install --upgrade coveralls
|
||||||
|
coveralls --service=github --finish
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
20
.travis.yml
20
.travis.yml
@@ -1,20 +0,0 @@
|
|||||||
sudo: false
|
|
||||||
language: python
|
|
||||||
python:
|
|
||||||
- "2.7"
|
|
||||||
- "3.4"
|
|
||||||
- "3.5"
|
|
||||||
- "3.6"
|
|
||||||
matrix:
|
|
||||||
include:
|
|
||||||
- { python: 3.6, env: TOXENV=flake8 }
|
|
||||||
- { python: 3.6, env: TOXENV=isort }
|
|
||||||
# Py37 requires xenial distrubution and sudo
|
|
||||||
# See travis-ci/travis-ci#9069
|
|
||||||
- { python: 3.7, dist: xenial, sudo: true }
|
|
||||||
|
|
||||||
install:
|
|
||||||
- pip install tox-travis
|
|
||||||
- pip install coveralls
|
|
||||||
script: tox
|
|
||||||
after_success: if [ -e .coverage ]; then coveralls; fi
|
|
||||||
28
CHANGES.rst
28
CHANGES.rst
@@ -1,6 +1,34 @@
|
|||||||
Changelog
|
Changelog
|
||||||
=========
|
=========
|
||||||
|
|
||||||
|
Version 0.5.11 -- 2022/08/03
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
* Add KZT and UAH currencies to lang RU (#264)
|
||||||
|
* Add es_NI currency (#276)
|
||||||
|
* Update .gitignore to add .eggs/ directory (#280)
|
||||||
|
* Fix Hebrew support (#289)
|
||||||
|
* Update test_tr.py to increase coverage (#298)
|
||||||
|
* Add ordinal 12,345 to ES test suite to increase coverage (#287)
|
||||||
|
* Add simple tests for lang_DK.py (#286)
|
||||||
|
* Add testcase for lang_EN.py (#288)
|
||||||
|
* Add more tests to base.py (#283)
|
||||||
|
* Fixed misspelling of 21 (cardinal and ordinal number) in IT language (#270)
|
||||||
|
* Romanian issues 259 (#260)
|
||||||
|
* Adding Language Support for Telugu / Bug Fix in Kannada (#263)
|
||||||
|
* Add support of Kazakh language (KZ) (#306)
|
||||||
|
* Update README.rst (#307)
|
||||||
|
* Added support for Hungarian language (#310)
|
||||||
|
* [UPD] Readme file (#363)
|
||||||
|
* [ADD] num2words: add traslation to spanish of several currencies (#356)
|
||||||
|
* added swedish language including test cases (#352)
|
||||||
|
* Remove dupplicated line in lang_PT_BR (#355)
|
||||||
|
* Fix ordinal_num output for Dutch (NL) (#369)
|
||||||
|
* Polishordinals (#367)
|
||||||
|
* [tr] return Turkish 0 ordinal and cardinal (#347)
|
||||||
|
* Improve Ukrainian support and minor fixes in CZ, KZ, LT, LV, PL, RU, SR languages (#400)
|
||||||
|
* feat: ci: replace travis by github workflows (#448)
|
||||||
|
* [ES] Added missing accents ("dieciséis", "dólar", "dólares", "veintiún"), improved currency gender handling, fixed pound cent names (#443)
|
||||||
|
|
||||||
Version 0.5.10 -- 2019/05/12
|
Version 0.5.10 -- 2019/05/12
|
||||||
----------------------------
|
----------------------------
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
num2words library - Convert numbers to words in multiple languages
|
num2words library - Convert numbers to words in multiple languages
|
||||||
==========================================================
|
==================================================================
|
||||||
|
|
||||||
.. image:: https://img.shields.io/pypi/v/num2words.svg
|
.. image:: https://img.shields.io/pypi/v/num2words.svg
|
||||||
:target: https://pypi.python.org/pypi/num2words
|
:target: https://pypi.python.org/pypi/num2words
|
||||||
@@ -51,7 +51,7 @@ Command line::
|
|||||||
$ num2words 24,120.10 -l es
|
$ num2words 24,120.10 -l es
|
||||||
veinticuatro mil ciento veinte punto uno
|
veinticuatro mil ciento veinte punto uno
|
||||||
$num2words 2.14 -l es --to currency
|
$num2words 2.14 -l es --to currency
|
||||||
dos euros con catorce centimos
|
dos euros con catorce céntimos
|
||||||
|
|
||||||
In code there's only one function to use::
|
In code there's only one function to use::
|
||||||
|
|
||||||
@@ -86,6 +86,7 @@ Besides the numerical argument, there are two main optional arguments.
|
|||||||
* ``es_CO`` (Spanish - Colombia)
|
* ``es_CO`` (Spanish - Colombia)
|
||||||
* ``es_VE`` (Spanish - Venezuela)
|
* ``es_VE`` (Spanish - Venezuela)
|
||||||
* ``eu`` (EURO)
|
* ``eu`` (EURO)
|
||||||
|
* ``fa`` (Farsi)
|
||||||
* ``fi`` (Finnish)
|
* ``fi`` (Finnish)
|
||||||
* ``fr`` (French)
|
* ``fr`` (French)
|
||||||
* ``fr_CH`` (French - Switzerland)
|
* ``fr_CH`` (French - Switzerland)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ Examples:
|
|||||||
veinticuatro mil ciento veinte punto uno
|
veinticuatro mil ciento veinte punto uno
|
||||||
|
|
||||||
$num2words 2.14 -l es --to currency
|
$num2words 2.14 -l es --to currency
|
||||||
dos euros con catorce centimos
|
dos euros con catorce céntimos
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
@@ -55,7 +55,7 @@ import sys
|
|||||||
from docopt import docopt
|
from docopt import docopt
|
||||||
import num2words
|
import num2words
|
||||||
|
|
||||||
__version__ = "0.5.10"
|
__version__ = "0.5.11"
|
||||||
__license__ = "LGPL"
|
__license__ = "LGPL"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -18,18 +18,19 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from . import (lang_AR, lang_CZ, lang_DE, lang_DK, lang_EN, lang_EN_IN,
|
from . import (lang_AR, lang_CZ, lang_DE, lang_DK, lang_EN, lang_EN_IN,
|
||||||
lang_ES, lang_ES_CO, lang_ES_NI, lang_ES_VE, lang_FI, lang_FR,
|
lang_ES, lang_ES_CO, lang_ES_NI, lang_ES_VE, lang_FA, lang_FI,
|
||||||
lang_FR_BE, lang_FR_CH, lang_FR_DZ, lang_HE, lang_HU, lang_ID,
|
lang_FR, lang_FR_BE, lang_FR_CH, lang_FR_DZ, lang_HE, lang_HU,
|
||||||
lang_IT, lang_JA, lang_KN, lang_KO, lang_KZ, lang_LT, lang_LV,
|
lang_ID, lang_IT, lang_JA, lang_KN, lang_KO, lang_KZ, lang_LT,
|
||||||
lang_NL, lang_NO, lang_PL, lang_PT, lang_PT_BR, lang_RO,
|
lang_LV, lang_NL, lang_NO, lang_PL, lang_PT, lang_PT_BR,
|
||||||
lang_RU, lang_SL, lang_SR, lang_SV, lang_TE, lang_TG, lang_TH,
|
lang_RO, lang_RU, lang_SL, lang_SR, lang_SV, lang_TE, lang_TG,
|
||||||
lang_TR, lang_UK, lang_VI)
|
lang_TH, lang_TR, lang_UK, lang_VI)
|
||||||
|
|
||||||
CONVERTER_CLASSES = {
|
CONVERTER_CLASSES = {
|
||||||
'ar': lang_AR.Num2Word_AR(),
|
'ar': lang_AR.Num2Word_AR(),
|
||||||
'cz': lang_CZ.Num2Word_CZ(),
|
'cz': lang_CZ.Num2Word_CZ(),
|
||||||
'en': lang_EN.Num2Word_EN(),
|
'en': lang_EN.Num2Word_EN(),
|
||||||
'en_IN': lang_EN_IN.Num2Word_EN_IN(),
|
'en_IN': lang_EN_IN.Num2Word_EN_IN(),
|
||||||
|
'fa': lang_FA.Num2Word_FA(),
|
||||||
'fr': lang_FR.Num2Word_FR(),
|
'fr': lang_FR.Num2Word_FR(),
|
||||||
'fr_CH': lang_FR_CH.Num2Word_FR_CH(),
|
'fr_CH': lang_FR_CH.Num2Word_FR_CH(),
|
||||||
'fr_BE': lang_FR_BE.Num2Word_FR_BE(),
|
'fr_BE': lang_FR_BE.Num2Word_FR_BE(),
|
||||||
|
|||||||
@@ -21,13 +21,14 @@ import math
|
|||||||
|
|
||||||
from .lang_EU import Num2Word_EU
|
from .lang_EU import Num2Word_EU
|
||||||
|
|
||||||
GENERIC_DOLLARS = ('dolar', 'dólares')
|
GENERIC_DOLLARS = ('dólar', 'dólares')
|
||||||
GENERIC_CENTS = ('centavo', 'centavos')
|
GENERIC_CENTS = ('centavo', 'centavos')
|
||||||
CURRENCIES_UNA = ('SLL', 'SEK', 'NOK', 'CZK', 'DKK', 'ISK',
|
CURRENCIES_UNA = ('SLL', 'SEK', 'NOK', 'CZK', 'DKK', 'ISK',
|
||||||
'SKK', 'GBP', 'CYP', 'EGP', 'FKP', 'GIP',
|
'SKK', 'GBP', 'CYP', 'EGP', 'FKP', 'GIP',
|
||||||
'LBP', 'SDG', 'SHP', 'SSP', 'SYP', 'INR',
|
'LBP', 'SDG', 'SHP', 'SSP', 'SYP', 'INR',
|
||||||
'IDR', 'LKR', 'MUR', 'NPR', 'PKR', 'SCR',
|
'IDR', 'LKR', 'MUR', 'NPR', 'PKR', 'SCR',
|
||||||
'ESP')
|
'ESP', 'TRY', 'ITL')
|
||||||
|
CENTS_UNA = ('EGP', 'JOD', 'LBP', 'SDG', 'SSP', 'SYP')
|
||||||
|
|
||||||
|
|
||||||
class Num2Word_ES(Num2Word_EU):
|
class Num2Word_ES(Num2Word_EU):
|
||||||
@@ -39,7 +40,7 @@ class Num2Word_ES(Num2Word_EU):
|
|||||||
'CRC': (('colón', 'colones'), GENERIC_CENTS),
|
'CRC': (('colón', 'colones'), GENERIC_CENTS),
|
||||||
'AUD': (GENERIC_DOLLARS, GENERIC_CENTS),
|
'AUD': (GENERIC_DOLLARS, GENERIC_CENTS),
|
||||||
'CAD': (GENERIC_DOLLARS, GENERIC_CENTS),
|
'CAD': (GENERIC_DOLLARS, GENERIC_CENTS),
|
||||||
'GBP': (('libra', 'libras'), ('penny', 'pence')),
|
'GBP': (('libra', 'libras'), ('penique', 'peniques')),
|
||||||
'RUB': (('rublo', 'rublos'), ('kopeyka', 'kopeykas')),
|
'RUB': (('rublo', 'rublos'), ('kopeyka', 'kopeykas')),
|
||||||
'SEK': (('corona', 'coronas'), ('öre', 'öre')),
|
'SEK': (('corona', 'coronas'), ('öre', 'öre')),
|
||||||
'NOK': (('corona', 'coronas'), ('øre', 'øre')),
|
'NOK': (('corona', 'coronas'), ('øre', 'øre')),
|
||||||
@@ -101,7 +102,7 @@ class Num2Word_ES(Num2Word_EU):
|
|||||||
'ERN': (('nakfa', 'nakfas'), ('céntimo', 'céntimos')),
|
'ERN': (('nakfa', 'nakfas'), ('céntimo', 'céntimos')),
|
||||||
'ETB': (('birr', 'birrs'), ('céntimo', 'céntimos')),
|
'ETB': (('birr', 'birrs'), ('céntimo', 'céntimos')),
|
||||||
'FJD': (GENERIC_DOLLARS, GENERIC_CENTS),
|
'FJD': (GENERIC_DOLLARS, GENERIC_CENTS),
|
||||||
'FKP': (('libra', 'libras'), ('penny', 'peniques')),
|
'FKP': (('libra', 'libras'), ('penique', 'peniques')),
|
||||||
'GEL': (('lari', 'laris'), ('tetri', 'tetris')),
|
'GEL': (('lari', 'laris'), ('tetri', 'tetris')),
|
||||||
'GHS': (('cedi', 'cedis'), ('pesewa', 'pesewas')),
|
'GHS': (('cedi', 'cedis'), ('pesewa', 'pesewas')),
|
||||||
'GIP': (('libra', 'libras'), ('penique', 'peniques')),
|
'GIP': (('libra', 'libras'), ('penique', 'peniques')),
|
||||||
@@ -170,7 +171,7 @@ class Num2Word_ES(Num2Word_EU):
|
|||||||
'SCR': (('rupia', 'rupias'), ('céntimo', 'céntimos')),
|
'SCR': (('rupia', 'rupias'), ('céntimo', 'céntimos')),
|
||||||
'SDG': (('libra', 'libras'), ('piastra', 'piastras')),
|
'SDG': (('libra', 'libras'), ('piastra', 'piastras')),
|
||||||
'SGD': (GENERIC_DOLLARS, ('céntimo', 'céntimos')),
|
'SGD': (GENERIC_DOLLARS, ('céntimo', 'céntimos')),
|
||||||
'SHP': (('libra', 'libras'), ('penny', 'peniques')),
|
'SHP': (('libra', 'libras'), ('penique', 'peniques')),
|
||||||
'SKK': (('corona', 'coronas'), ('halier', 'haliers')),
|
'SKK': (('corona', 'coronas'), ('halier', 'haliers')),
|
||||||
'SLL': (('leona', 'leonas'), ('céntimo', 'céntimos')),
|
'SLL': (('leona', 'leonas'), ('céntimo', 'céntimos')),
|
||||||
'SRD': (GENERIC_DOLLARS, ('céntimo', 'céntimos')),
|
'SRD': (GENERIC_DOLLARS, ('céntimo', 'céntimos')),
|
||||||
@@ -184,7 +185,7 @@ class Num2Word_ES(Num2Word_EU):
|
|||||||
'TND': (('dinar', 'dinares'), ('milésimo', 'milésimos')),
|
'TND': (('dinar', 'dinares'), ('milésimo', 'milésimos')),
|
||||||
'TOP': (('paanga', 'paangas'), ('céntimo', 'céntimos')),
|
'TOP': (('paanga', 'paangas'), ('céntimo', 'céntimos')),
|
||||||
'TTD': (GENERIC_DOLLARS, ('céntimo', 'céntimos')),
|
'TTD': (GENERIC_DOLLARS, ('céntimo', 'céntimos')),
|
||||||
'TWD': (('nuevo dólar', 'nuevos dolares'), ('céntimo', 'céntimos')),
|
'TWD': (('nuevo dólar', 'nuevos dólares'), ('céntimo', 'céntimos')),
|
||||||
'TZS': (('chelín', 'chelines'), ('céntimo', 'céntimos')),
|
'TZS': (('chelín', 'chelines'), ('céntimo', 'céntimos')),
|
||||||
'UAG': (('hryvnia', 'hryvnias'), ('kopiyka', 'kopiykas')),
|
'UAG': (('hryvnia', 'hryvnias'), ('kopiyka', 'kopiykas')),
|
||||||
'UGX': (('chelín', 'chelines'), ('céntimo', 'céntimos')),
|
'UGX': (('chelín', 'chelines'), ('céntimo', 'céntimos')),
|
||||||
@@ -216,9 +217,13 @@ class Num2Word_ES(Num2Word_EU):
|
|||||||
self.high_numwords = self.gen_high_numwords([], [], lows)
|
self.high_numwords = self.gen_high_numwords([], [], lows)
|
||||||
self.negword = "menos "
|
self.negword = "menos "
|
||||||
self.pointword = "punto"
|
self.pointword = "punto"
|
||||||
self.errmsg_nonnum = "Solo números pueden ser convertidos a palabras."
|
self.errmsg_nonnum = "type(%s) no es [long, int, float]"
|
||||||
|
self.errmsg_floatord = "El float %s no puede ser tratado como un" \
|
||||||
|
" ordinal."
|
||||||
|
self.errmsg_negord = "El número negativo %s no puede ser tratado" \
|
||||||
|
" como un ordinal."
|
||||||
self.errmsg_toobig = (
|
self.errmsg_toobig = (
|
||||||
"Numero muy grande para ser convertido a palabras."
|
"abs(%s) deber ser inferior a %s."
|
||||||
)
|
)
|
||||||
self.gender_stem = "o"
|
self.gender_stem = "o"
|
||||||
self.exclude_title = ["y", "menos", "punto"]
|
self.exclude_title = ["y", "menos", "punto"]
|
||||||
@@ -230,7 +235,7 @@ class Num2Word_ES(Num2Word_EU):
|
|||||||
"veintiséis", "veinticinco", "veinticuatro",
|
"veintiséis", "veinticinco", "veinticuatro",
|
||||||
"veintitrés", "veintidós", "veintiuno",
|
"veintitrés", "veintidós", "veintiuno",
|
||||||
"veinte", "diecinueve", "dieciocho", "diecisiete",
|
"veinte", "diecinueve", "dieciocho", "diecisiete",
|
||||||
"dieciseis", "quince", "catorce", "trece", "doce",
|
"dieciséis", "quince", "catorce", "trece", "doce",
|
||||||
"once", "diez", "nueve", "ocho", "siete", "seis",
|
"once", "diez", "nueve", "ocho", "siete", "seis",
|
||||||
"cinco", "cuatro", "tres", "dos", "uno", "cero"]
|
"cinco", "cuatro", "tres", "dos", "uno", "cero"]
|
||||||
self.ords = {1: "primer",
|
self.ords = {1: "primer",
|
||||||
@@ -352,15 +357,52 @@ class Num2Word_ES(Num2Word_EU):
|
|||||||
result = super(Num2Word_ES, self).to_currency(
|
result = super(Num2Word_ES, self).to_currency(
|
||||||
val, currency=currency, cents=cents, separator=separator,
|
val, currency=currency, cents=cents, separator=separator,
|
||||||
adjective=adjective)
|
adjective=adjective)
|
||||||
# Handle exception, in spanish is "un euro" and not "uno euro"
|
# Handle exception: In Spanish it's "un euro" and not "uno euro",
|
||||||
# except in this currencies: leona, corona,
|
# except in these currencies, where it's "una": leona, corona,
|
||||||
# libra, rupia, lempira, peseta, is 'una'
|
# libra, lira, rupia, lempira, peseta.
|
||||||
# but only when it's first word, otherwise
|
# The same goes for "veintiuna", "treinta y una"...
|
||||||
# it's replaced in others words like 'veintiun'
|
# Also, this needs to be handled separately for "dollars" and
|
||||||
|
# "cents".
|
||||||
|
# All "cents" are masculine except for: piastra.
|
||||||
|
# Source: https://www.rae.es/dpd/una (section 2.2)
|
||||||
|
|
||||||
|
# split "dollars" part from "cents" part
|
||||||
|
list_result = result.split(separator + " ")
|
||||||
|
|
||||||
|
# "DOLLARS" PART (list_result[0])
|
||||||
|
|
||||||
|
# Feminine currencies ("una libra", "trescientas libras"...)
|
||||||
if currency in CURRENCIES_UNA:
|
if currency in CURRENCIES_UNA:
|
||||||
list_result = result.split(" ")
|
|
||||||
if list_result[0] == "uno":
|
# "una libra", "veintiuna libras", "treinta y una libras"...
|
||||||
list_result[0] = list_result[0].replace("uno", "una")
|
list_result[0] = list_result[0].replace("uno", "una")
|
||||||
result = " ".join(list_result)
|
|
||||||
result = result.replace("uno", "un")
|
# "doscientas libras", "trescientas libras"...
|
||||||
|
list_result[0] = list_result[0].replace("cientos", "cientas")
|
||||||
|
|
||||||
|
# Masc.: Correct orthography for the specific case of "veintiún":
|
||||||
|
list_result[0] = list_result[0].replace("veintiuno", "veintiún")
|
||||||
|
|
||||||
|
# Masculine currencies: general case ("un euro", "treinta y un
|
||||||
|
# euros"...):
|
||||||
|
list_result[0] = list_result[0].replace("uno", "un")
|
||||||
|
|
||||||
|
# "CENTS" PART (list_result[1])
|
||||||
|
|
||||||
|
# Feminine "cents" ("una piastra", "veintiuna piastras"...)
|
||||||
|
if currency in CENTS_UNA:
|
||||||
|
|
||||||
|
# "una piastra", "veintiuna piastras", "treinta y una piastras"...
|
||||||
|
list_result[1] = list_result[1].replace("uno", "una")
|
||||||
|
|
||||||
|
# Masc.: Correct orthography for the specific case of "veintiún":
|
||||||
|
list_result[1] = list_result[1].replace("veintiuno", "veintiún")
|
||||||
|
|
||||||
|
# Masculine "cents": general case ("un centavo", "treinta y un
|
||||||
|
# centavos"...):
|
||||||
|
list_result[1] = list_result[1].replace("uno", "un")
|
||||||
|
|
||||||
|
# join back "dollars" part with "cents" part
|
||||||
|
result = (separator + " ").join(list_result)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|||||||
165
num2words/lang_FA.py
Normal file
165
num2words/lang_FA.py
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||||
|
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||||
|
# Copyright (c) 2018, Abdullah Alhazmy, Alhazmy13. All Rights Reserved.
|
||||||
|
# Copyright (c) 2020, Hamidreza Kalbasi. 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 decimal import Decimal
|
||||||
|
from math import floor
|
||||||
|
|
||||||
|
farsiOnes = [
|
||||||
|
"", "یک", "دو", "سه", "چهار", "پنج", "شش", "هفت", "هشت",
|
||||||
|
"نه",
|
||||||
|
"ده",
|
||||||
|
"یازده",
|
||||||
|
"دوازده",
|
||||||
|
"سیزده",
|
||||||
|
"چهارده",
|
||||||
|
"پونزده",
|
||||||
|
"شونزده",
|
||||||
|
"هیفده",
|
||||||
|
"هیجده",
|
||||||
|
"نوزده",
|
||||||
|
]
|
||||||
|
|
||||||
|
farsiTens = [
|
||||||
|
"",
|
||||||
|
"ده",
|
||||||
|
"بیست",
|
||||||
|
"سی",
|
||||||
|
"چهل",
|
||||||
|
"پنجاه",
|
||||||
|
"شصت",
|
||||||
|
"هفتاد",
|
||||||
|
"هشتاد",
|
||||||
|
"نود",
|
||||||
|
]
|
||||||
|
|
||||||
|
farsiHundreds = [
|
||||||
|
"",
|
||||||
|
"صد",
|
||||||
|
"دویست",
|
||||||
|
"سیصد",
|
||||||
|
"چهارصد",
|
||||||
|
"پانصد",
|
||||||
|
"ششصد",
|
||||||
|
"هفتصد",
|
||||||
|
"هشتصد",
|
||||||
|
"نهصد",
|
||||||
|
]
|
||||||
|
|
||||||
|
farsiBig = [
|
||||||
|
'',
|
||||||
|
' هزار',
|
||||||
|
' میلیون',
|
||||||
|
" میلیارد",
|
||||||
|
' تریلیون',
|
||||||
|
" تریلیارد",
|
||||||
|
]
|
||||||
|
|
||||||
|
farsiFrac = ["", "دهم", "صدم"]
|
||||||
|
farsiFracBig = ["", "هزارم", "میلیونیم", "میلیاردیم"]
|
||||||
|
|
||||||
|
farsiSeperator = ' و '
|
||||||
|
|
||||||
|
|
||||||
|
class Num2Word_FA(object):
|
||||||
|
errmsg_too_big = "Too large"
|
||||||
|
max_num = 10 ** 36
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.number = 0
|
||||||
|
|
||||||
|
def float2tuple(self, value):
|
||||||
|
pre = int(value)
|
||||||
|
|
||||||
|
# Simple way of finding decimal places to update the precision
|
||||||
|
self.precision = abs(Decimal(str(value)).as_tuple().exponent)
|
||||||
|
|
||||||
|
post = abs(value - pre) * 10**self.precision
|
||||||
|
if abs(round(post) - post) < 0.01:
|
||||||
|
# We generally floor all values beyond our precision (rather than
|
||||||
|
# rounding), but in cases where we have something like 1.239999999,
|
||||||
|
# which is probably due to python's handling of floats, we actually
|
||||||
|
# want to consider it as 1.24 instead of 1.23
|
||||||
|
post = int(round(post))
|
||||||
|
else:
|
||||||
|
post = int(floor(post))
|
||||||
|
return pre, post, self.precision
|
||||||
|
|
||||||
|
def cardinal3(self, number):
|
||||||
|
if (number < 19):
|
||||||
|
return farsiOnes[number]
|
||||||
|
if (number < 100):
|
||||||
|
x, y = divmod(number, 10)
|
||||||
|
if y == 0:
|
||||||
|
return farsiTens[x]
|
||||||
|
return farsiTens[x] + farsiSeperator + farsiOnes[y]
|
||||||
|
x, y = divmod(number, 100)
|
||||||
|
if y == 0:
|
||||||
|
return farsiHundreds[x]
|
||||||
|
return farsiHundreds[x] + farsiSeperator + self.cardinal3(y)
|
||||||
|
|
||||||
|
def cardinalPos(self, number):
|
||||||
|
x = number
|
||||||
|
res = ''
|
||||||
|
for b in farsiBig:
|
||||||
|
x, y = divmod(x, 1000)
|
||||||
|
if (y == 0):
|
||||||
|
continue
|
||||||
|
yx = self.cardinal3(y) + b
|
||||||
|
if b == ' هزار' and y == 1:
|
||||||
|
yx = 'هزار'
|
||||||
|
if (res == ''):
|
||||||
|
res = yx
|
||||||
|
else:
|
||||||
|
res = yx + farsiSeperator + res
|
||||||
|
return res
|
||||||
|
|
||||||
|
def fractional(self, number, level):
|
||||||
|
if (number == 5):
|
||||||
|
return "نیم"
|
||||||
|
x = self.cardinalPos(number)
|
||||||
|
ld3, lm3 = divmod(level, 3)
|
||||||
|
ltext = (farsiFrac[lm3] + " " + farsiFracBig[ld3]).strip()
|
||||||
|
return x + " " + ltext
|
||||||
|
|
||||||
|
def to_currency(self, value):
|
||||||
|
return self.to_cardinal(value) + " تومان"
|
||||||
|
|
||||||
|
def to_ordinal(self, number):
|
||||||
|
r = self.to_cardinal(number)
|
||||||
|
if (r[-1] == 'ه' and r[-2] == 'س'):
|
||||||
|
return r[:-1] + 'وم'
|
||||||
|
return r + 'م'
|
||||||
|
|
||||||
|
def to_year(self, value):
|
||||||
|
return self.to_cardinal(value)
|
||||||
|
|
||||||
|
def to_ordinal_num(self, value):
|
||||||
|
return str(value)+"م"
|
||||||
|
|
||||||
|
def to_cardinal(self, number):
|
||||||
|
if number < 0:
|
||||||
|
return "منفی " + self.to_cardinal(-number)
|
||||||
|
if (number == 0):
|
||||||
|
return "صفر"
|
||||||
|
x, y, level = self.float2tuple(number)
|
||||||
|
if y == 0:
|
||||||
|
return self.cardinalPos(x)
|
||||||
|
if x == 0:
|
||||||
|
return self.fractional(y, level)
|
||||||
|
return self.cardinalPos(x) + farsiSeperator + self.fractional(y, level)
|
||||||
@@ -335,6 +335,7 @@ ERA_START = [
|
|||||||
(1912, ("大正", "たいしょう")),
|
(1912, ("大正", "たいしょう")),
|
||||||
(1926, ("昭和", "しょうわ")),
|
(1926, ("昭和", "しょうわ")),
|
||||||
(1989, ("平成", "へいせい")),
|
(1989, ("平成", "へいせい")),
|
||||||
|
(2019, ("令和", "れいわ")),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ class Num2Word_KO(Num2Word_Base):
|
|||||||
|
|
||||||
def to_ordinal(self, value):
|
def to_ordinal(self, value):
|
||||||
self.verify_ordinal(value)
|
self.verify_ordinal(value)
|
||||||
if(value == 1):
|
if value == 1:
|
||||||
return "첫 번째"
|
return "첫 번째"
|
||||||
outwords = self.to_cardinal(value).split(" ")
|
outwords = self.to_cardinal(value).split(" ")
|
||||||
lastwords = outwords[-1].split("백")
|
lastwords = outwords[-1].split("백")
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
tox
|
||||||
flake8
|
flake8
|
||||||
flake8-copyright
|
flake8-copyright
|
||||||
isort
|
isort
|
||||||
|
|||||||
10
setup.py
10
setup.py
@@ -27,8 +27,11 @@ CLASSIFIERS = [
|
|||||||
'Intended Audience :: Developers',
|
'Intended Audience :: Developers',
|
||||||
'License :: OSI Approved :: GNU Library or Lesser General Public License '
|
'License :: OSI Approved :: GNU Library or Lesser General Public License '
|
||||||
'(LGPL)',
|
'(LGPL)',
|
||||||
'Programming Language :: Python :: 2.7',
|
'Programming Language :: Python :: 3.6',
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: 3.9',
|
||||||
|
'Programming Language :: Python :: 3.10',
|
||||||
'Topic :: Software Development :: Internationalization',
|
'Topic :: Software Development :: Internationalization',
|
||||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
'Topic :: Software Development :: Localization',
|
'Topic :: Software Development :: Localization',
|
||||||
@@ -61,11 +64,12 @@ setup(
|
|||||||
version=find_version("bin/num2words"),
|
version=find_version("bin/num2words"),
|
||||||
description='Modules to convert numbers to words. Easily extensible.',
|
description='Modules to convert numbers to words. Easily extensible.',
|
||||||
long_description=LONG_DESC,
|
long_description=LONG_DESC,
|
||||||
|
long_description_content_type="text/markdown",
|
||||||
license='LGPL',
|
license='LGPL',
|
||||||
author='Taro Ogawa <tso at users sourceforge net>',
|
author='Taro Ogawa <tso at users sourceforge net>',
|
||||||
author_email='tos@users.sourceforge.net',
|
author_email='tos@users.sourceforge.net',
|
||||||
maintainer='Savoir-faire Linux inc.',
|
maintainer='Savoir-faire Linux inc.',
|
||||||
maintainer_email='istvan.szalai@savoirfairelinux.com',
|
maintainer_email='support@savoirfairelinux.com',
|
||||||
keywords=' number word numbers words convert conversion i18n '
|
keywords=' number word numbers words convert conversion i18n '
|
||||||
'localisation localization internationalisation '
|
'localisation localization internationalisation '
|
||||||
'internationalization',
|
'internationalization',
|
||||||
|
|||||||
@@ -58,3 +58,8 @@ class Num2WordBaseTest(TestCase):
|
|||||||
self.base.title("one"),
|
self.base.title("one"),
|
||||||
"One"
|
"One"
|
||||||
)
|
)
|
||||||
|
self.base.exclude_title.append('one')
|
||||||
|
self.assertEqual(
|
||||||
|
self.base.title("one"),
|
||||||
|
"one"
|
||||||
|
)
|
||||||
|
|||||||
390
tests/test_es.py
390
tests/test_es.py
File diff suppressed because it is too large
Load Diff
109
tests/test_fa.py
Normal file
109
tests/test_fa.py
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Copyright (c) 2003, Taro Ogawa. All Rights Reserved.
|
||||||
|
# Copyright (c) 2013, Savoir-faire Linux inc. All Rights Reserved.
|
||||||
|
# Copyright (c) 2020, Hamidreza Kalbasi. 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 unittest import TestCase
|
||||||
|
|
||||||
|
from num2words import num2words
|
||||||
|
|
||||||
|
|
||||||
|
class Num2WordsFATest(TestCase):
|
||||||
|
def test_and_join_199(self):
|
||||||
|
self.assertEqual(num2words(199, lang='fa'), "صد و نود و نه")
|
||||||
|
|
||||||
|
def test_ordinal(self):
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(0, lang='fa', to='ordinal'),
|
||||||
|
'صفرم'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(1, lang='fa', to='ordinal'),
|
||||||
|
'یکم'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(13, lang='fa', to='ordinal'),
|
||||||
|
'سیزدهم'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(23, lang='fa', to='ordinal'),
|
||||||
|
'بیست و سوم'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(12, lang='fa', to='ordinal'),
|
||||||
|
'دوازدهم'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(113, lang='fa', to='ordinal'),
|
||||||
|
'صد و سیزدهم'
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(103, lang='fa', to='ordinal'),
|
||||||
|
'صد و سوم'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_cardinal(self):
|
||||||
|
self.assertEqual(num2words(130000, lang='fa'), "صد و سی هزار")
|
||||||
|
self.assertEqual(num2words(242, lang='fa'), "دویست و چهل و دو")
|
||||||
|
self.assertEqual(num2words(800, lang='fa'), "هشتصد")
|
||||||
|
self.assertEqual(num2words(-203, lang='fa'), "منفی دویست و سه")
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(1234567890, lang='fa'),
|
||||||
|
"یک میلیارد و دویست و سی و چهار میلیون و"
|
||||||
|
" پانصد و شصت و هفت هزار و هشتصد و نود"
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_year(self):
|
||||||
|
self.assertEqual(num2words(1398, lang='fa', to='year'),
|
||||||
|
"هزار و سیصد و نود و هشت")
|
||||||
|
self.assertEqual(num2words(1399, lang='fa', to='year'),
|
||||||
|
"هزار و سیصد و نود و نه")
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(1400, lang='fa', to='year'), "هزار و چهارصد")
|
||||||
|
|
||||||
|
def test_currency(self):
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(1000, lang='fa', to='currency'), 'هزار تومان')
|
||||||
|
self.assertEqual(
|
||||||
|
num2words(1500000, lang='fa', to='currency'),
|
||||||
|
'یک میلیون و پانصد هزار تومان'
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_ordinal_num(self):
|
||||||
|
self.assertEqual(num2words(10, lang='fa', to='ordinal_num'), '10م')
|
||||||
|
self.assertEqual(num2words(21, lang='fa', to='ordinal_num'), '21م')
|
||||||
|
self.assertEqual(num2words(102, lang='fa', to='ordinal_num'), '102م')
|
||||||
|
self.assertEqual(num2words(73, lang='fa', to='ordinal_num'), '73م')
|
||||||
|
|
||||||
|
def test_cardinal_for_float_number(self):
|
||||||
|
self.assertEqual(num2words(12.5, lang='fa'), "دوازده و نیم")
|
||||||
|
self.assertEqual(num2words(0.75, lang='fa'), "هفتاد و پنج صدم")
|
||||||
|
self.assertEqual(num2words(12.51, lang='fa'),
|
||||||
|
"دوازده و پنجاه و یک صدم")
|
||||||
|
self.assertEqual(num2words(12.53, lang='fa'),
|
||||||
|
"دوازده و پنجاه و سه صدم")
|
||||||
|
self.assertEqual(num2words(12.59, lang='fa'),
|
||||||
|
"دوازده و پنجاه و نه صدم")
|
||||||
|
self.assertEqual(num2words(0.000001, lang='fa'), "یک میلیونیم")
|
||||||
|
|
||||||
|
def test_overflow(self):
|
||||||
|
with self.assertRaises(OverflowError):
|
||||||
|
num2words("1000000000000000000000000000000000000000000000000000000"
|
||||||
|
"0000000000000000000000000000000000000000000000000000000"
|
||||||
|
"0000000000000000000000000000000000000000000000000000000"
|
||||||
|
"0000000000000000000000000000000000000000000000000000000"
|
||||||
|
"0000000000000000000000000000000000000000000000000000000"
|
||||||
|
"00000000000000000000000000000000")
|
||||||
@@ -163,6 +163,21 @@ class Num2WordsJATest(TestCase):
|
|||||||
"はちじゅうきゅうえん")
|
"はちじゅうきゅうえん")
|
||||||
|
|
||||||
def test_year(self):
|
def test_year(self):
|
||||||
|
self.assertEqual(n2j(2021, to="year"), "令和三年")
|
||||||
|
self.assertEqual(n2j(2021, to="year", reading=True),
|
||||||
|
"れいわさんねん")
|
||||||
|
self.assertEqual(n2j(2021, to="year", reading="arabic"),
|
||||||
|
"令和3年")
|
||||||
|
self.assertEqual(n2j(2019, to="year"), "令和元年")
|
||||||
|
self.assertEqual(n2j(2019, to="year", reading=True),
|
||||||
|
"れいわがんねん")
|
||||||
|
self.assertEqual(n2j(2019, to="year", reading="arabic"),
|
||||||
|
"令和1年")
|
||||||
|
self.assertEqual(n2j(2018, to="year"), "平成三十年")
|
||||||
|
self.assertEqual(n2j(2018, to="year", reading=True),
|
||||||
|
"へいせいさんじゅうねん")
|
||||||
|
self.assertEqual(n2j(2018, to="year", reading="arabic"),
|
||||||
|
"平成30年")
|
||||||
self.assertEqual(n2j(2017, to="year"), "平成二十九年")
|
self.assertEqual(n2j(2017, to="year"), "平成二十九年")
|
||||||
self.assertEqual(n2j(2017, to="year", reading=True),
|
self.assertEqual(n2j(2017, to="year", reading=True),
|
||||||
"へいせいにじゅうくねん")
|
"へいせいにじゅうくねん")
|
||||||
@@ -176,8 +191,6 @@ class Num2WordsJATest(TestCase):
|
|||||||
"にせんねん")
|
"にせんねん")
|
||||||
self.assertEqual(n2j(645, to="year"), "大化元年")
|
self.assertEqual(n2j(645, to="year"), "大化元年")
|
||||||
self.assertEqual(n2j(645, to="year", reading=True), "たいかがんねん")
|
self.assertEqual(n2j(645, to="year", reading=True), "たいかがんねん")
|
||||||
self.assertEqual(n2j(645, to="year"), "大化元年")
|
|
||||||
self.assertEqual(n2j(645, to="year", reading=True), "たいかがんねん")
|
|
||||||
self.assertEqual(n2j(-99, to="year", era=False), "紀元前九十九年")
|
self.assertEqual(n2j(-99, to="year", era=False), "紀元前九十九年")
|
||||||
self.assertEqual(n2j(-99, to="year", era=False, reading=True),
|
self.assertEqual(n2j(-99, to="year", era=False, reading=True),
|
||||||
"きげんぜんきゅうじゅうくねん")
|
"きげんぜんきゅうじゅうくねん")
|
||||||
|
|||||||
19
tox.ini
19
tox.ini
@@ -1,8 +1,17 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = flake8,isort,py27,py34,py35,py36,py37
|
envlist = py36,py37,py38,py39,py310,flake8,isort
|
||||||
|
|
||||||
|
[gh-actions]
|
||||||
|
python =
|
||||||
|
3.6: py36
|
||||||
|
3.7: py37
|
||||||
|
3.8: py38
|
||||||
|
3.9: py39
|
||||||
|
3.10: isort, flake8, py310
|
||||||
|
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
passenv = TRAVIS TRAVIS_*
|
passenv = GITHUB_*
|
||||||
deps =
|
deps =
|
||||||
coverage
|
coverage
|
||||||
delegator.py
|
delegator.py
|
||||||
@@ -25,8 +34,4 @@ deps =
|
|||||||
isort
|
isort
|
||||||
delegator.py
|
delegator.py
|
||||||
commands =
|
commands =
|
||||||
isort --check-only --recursive --diff num2words tests
|
isort --check-only --float-to-top --diff num2words tests
|
||||||
|
|
||||||
[testenv:py27]
|
|
||||||
setenv =
|
|
||||||
PYTHONIOENCODING = UTF-8
|
|
||||||
|
|||||||
Reference in New Issue
Block a user