Skip to main content

spellmoney

Convierte montos numéricos a letras, con el formato exacto que exigen los documentos legales y financieros — cheques, facturas, recibos y contratos: CIENTO VEINTICINCO DÓLARES CON 50/100.

PyPI Python Tests License Dependencies Idiomas

▶ Probalo en el navegador · Read this in English

Existe también el puerto a TypeScript/JavaScript — misma lógica, mismos datos de moneda, mismo resultado exacto.

Instalación

pip install spellmoney

Uso

from spellmoney import a_letras

a_letras(125.50)
# 'CIENTO VEINTICINCO DÓLARES CON 50/100'

a_letras("125.50")
# 'CIENTO VEINTICINCO DÓLARES CON 50/100'  (lectura decimal exacta)

a_letras(1, moneda="GTQ")
# 'UN QUETZAL CON 00/100'

a_letras(21000000, moneda="EUR")
# 'VEINTIÚN MILLONES DE EUROS CON 00/100'

a_letras(2, moneda="GBP", mayusculas=False)
# 'dos libras esterlinas con 00/100'

a_letras(10.50, centavos="palabras")
# 'DIEZ DÓLARES CON CINCUENTA CENTAVOS'

Otros idiomas

a_letras(125.50, idioma="en")
# 'ONE HUNDRED TWENTY-FIVE DOLLARS AND 50/100'

a_letras(125.50, idioma="pt", moneda="BRL")
# 'CENTO E VINTE E CINCO REAIS E 50/100'

a_letras(125.50, idioma="fr", moneda="EUR")
# 'CENT VINGT-CINQ EUROS ET 50/100'

Desde la terminal

spellmoney 125.50
spellmoney 125.50 --moneda GTQ
spellmoney 1000000 --moneda EUR --idioma fr
spellmoney --monedas quetzal

Solo el número, sin moneda

from spellmoney import (
    numero_a_letras,
    numero_a_letras_en,
    numero_a_letras_pt,
    numero_a_letras_fr,
)

numero_a_letras(1000000)        # 'un millón'
numero_a_letras(1000000000)     # 'mil millones'   (¡no "un billón"!)
numero_a_letras(1000000000000)  # 'un billón'
numero_a_letras(200, "f")       # 'doscientas'    (concordancia de género)

numero_a_letras_en(1000000000)  # 'one billion'    (escala corta del inglés)

numero_a_letras_pt(21, "f")     # 'vinte e uma'    (concordancia de género)

numero_a_letras_fr(71)          # 'soixante et onze'  (base vigesimal del francés)

Divisas y subunidades

El catálogo sigue el estándar ISO 4217, incluido el número de decimales de cada divisa. Eso cambia la salida:

a_letras(125.50, moneda="JPY")
# 'CIENTO VEINTISÉIS YENES JAPONESES'      el yen no tiene subunidad

a_letras("125.500", moneda="KWD")
# 'CIENTO VEINTICINCO DINARES KUWAITÍES CON 500/1000'   el dinar se divide en 1000

a_letras(1.25, moneda="GBP", centavos="palabras")
# 'UNA LIBRA ESTERLINA CON VEINTICINCO PENIQUES'        no "centavos"

a_letras(1.25, moneda="EUR", centavos="palabras")
# 'UN EURO CON VEINTICINCO CÉNTIMOS'

El género de la divisa arrastra al número, como exige la gramática — y no solo en el último dígito: las centenas concuerdan aunque se interponga "mil".

a_letras(200, moneda="GBP")
# 'DOSCIENTAS LIBRAS ESTERLINAS CON 00/100'

a_letras(200000, moneda="GBP")
# 'DOSCIENTAS MIL LIBRAS ESTERLINAS CON 00/100'

a_letras(200, moneda="USD")
# 'DOSCIENTOS DÓLARES CON 00/100'

a_letras(200000000, moneda="GBP")
# 'DOSCIENTOS MILLONES DE LIBRAS ESTERLINAS CON 00/100'   "millones" es masculino

Los cuatro idiomas cubren las 156 divisas del catálogo, cada una con su nombre, su género gramatical y, cuando la tiene, el nombre de su subunidad:

Idioma Divisas Ejemplo
es (español) 156 UNA CORONA CHECA CON 00/100
en (inglés) 156 ONE CZECH KORUNA AND 00/100
pt (portugués) 156 UMA COROA TCHECA E 00/100
fr (francés) 156 UNE COURONNE TCHÈQUE ET 00/100

Divisas retiradas. Las que el estándar retiró se conservan, marcadas con la fecha en MONEDAS[codigo]["retirada"] — el florín antillano (ANG, 2025-03), el dólar zimbabuense (ZWL, 2024-09) y el lev búlgaro (BGN, 2026-01). Una factura de 2023 se tiene que poder escribir igual.

Montos negativos

Por defecto se rechazan, porque en un cheque casi siempre son un error. Para notas de crédito y devoluciones:

a_letras(-125.50, negativos="prefijo")
# 'MENOS CIENTO VEINTICINCO DÓLARES CON 50/100'

Plantilla de salida

Cada país tiene su fórmula legal. La plantilla permite calcarla:

a_letras(125.50, plantilla="SON: {monto} {moneda} {conector} {centavos}")
# 'SON: CIENTO VEINTICINCO DÓLARES CON 50/100'

a_letras(125.50, plantilla="{monto} {moneda} ({codigo})")
# 'CIENTO VEINTICINCO DÓLARES (USD)'

Marcadores disponibles: {signo}, {monto}, {moneda}, {conector}, {centavos} y {codigo}. Los espacios sobrantes se colapsan.

Ojo con mayusculas: pasa todo el resultado a mayúsculas o a minúsculas, la plantilla incluida. No conserva el texto tal como se escribió.

API

Función Descripción
a_letras(monto, ...) Convierte un monto con nombre de moneda.
numero_a_letras(n, genero="m") Solo el número, en español.
numero_a_letras_en(n) Solo el número, en inglés.
numero_a_letras_pt(n, genero="m") Solo el número, en portugués.
numero_a_letras_fr(n) Solo el número, en francés.
MONEDAS Catálogo de divisas ISO 4217, con decimales y subunidades.
IDIOMAS ("es", "en", "pt", "fr").
SpellMoneyError Error lanzado ante un monto, moneda o idioma inválidos.

Parámetros de a_letras:

Parámetro Valores Por defecto
monto int, float, Decimal o cadena decimal —
moneda código ISO 4217 "USD"
idioma "es", "en", "pt", "fr" "es"
centavos "fraccion", "palabras" "fraccion"
mayusculas bool True
negativos "error", "prefijo" "error"
plantilla str según la divisa

Redondeo y precisión

Un monto se puede pasar como float, como Decimal o como cadena decimal, y la diferencia importa:

  • Cadena o Decimal — a_letras("125.50"), a_letras(Decimal("125.50")): los dígitos se leen tal como fueron escritos, sin pasar por punto flotante. El redondeo del primer decimal sobrante es half-up exacto, así que "2.675" da 68/100. Es la vía recomendada cuando el monto viene de una base de datos, un formulario o un archivo.
  • float — a_letras(125.50): los montos de dos decimales se convierten de forma exacta. Verificado sobre el millón de montos de 0.00 a 9999.99: ninguna diferencia frente a aritmética decimal exacta. Con tres o más decimales, el empate exacto se resuelve según el valor binario que el float almacena realmente, que puede quedar apenas por debajo del decimal escrito: 2.675 da 67/100. Es una propiedad del tipo float, no de esta librería.

Rango soportado

Enteros de 0 a 999,999,999,999,999. Un monto fuera de ese rango lanza SpellMoneyError, igual que una moneda no reconocida o un idioma no soportado.

Desarrollo

git clone https://github.com/brandriver-bit/spellmoney.git
cd spellmoney
pip install -e ".[dev]"
pytest

Licencia

MIT — ver LICENSE.


spellmoney (English)

Turns numeric amounts into words, in the exact format legal and financial documents require — cheques, invoices, receipts and contracts: ONE HUNDRED TWENTY-FIVE DOLLARS AND 50/100.

▶ Try it in your browser · Leer esto en español

Four languages — Spanish, English, Brazilian Portuguese and French — and the ISO 4217 currency catalog, including each currency's minor units. Zero dependencies. There is also a TypeScript/JavaScript port with identical output.

Install

pip install spellmoney

Usage

from spellmoney import a_letras

a_letras(125.50, idioma="en")
# 'ONE HUNDRED TWENTY-FIVE DOLLARS AND 50/100'

a_letras("125.50", idioma="en", moneda="GBP", centavos="palabras")
# 'ONE HUNDRED TWENTY-FIVE POUNDS STERLING AND FIFTY PENCE'

a_letras(125.50, idioma="en", moneda="JPY")
# 'ONE HUNDRED TWENTY-SIX JAPANESE YEN'      the yen has no minor unit

a_letras("125.500", idioma="en", moneda="KWD")
# 'ONE HUNDRED TWENTY-FIVE KUWAITI DINARS AND 500/1000'

There's also a CLI:

spellmoney 125.50 --idioma en --moneda GBP

The API is in Spanish because that's the audience it was written for. a_letras(amount, ...) is the entry point; moneda is the ISO 4217 code, idioma the language, centavos whether the minor unit is written as a fraction (50/100) or in words, mayusculas the casing, negativos how to treat negative amounts, and plantilla an output template for matching a specific legal wording.

Pass the amount as a string or a Decimal to have its digits read exactly, without floating point: "2.675" rounds half-up to 68/100, while the float 2.675 gives 67/100 because the nearest double sits just below it.

All four languages cover every currency in the catalog, each with its name, grammatical gender and, where it has one, the name of its minor unit. Withdrawn currencies are kept and flagged with the date they left the standard, so older documents can still be spelled.

MIT licensed.

Metadata

Release files for spellmoney 2.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for spellmoney 2.0.0
File Size Uploaded Provenance Actions
spellmoney-2.0.0.tar.gz 35.7 kB Without provenance Details for spellmoney-2.0.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for spellmoney 2.0.0
File Interpreter ABI Platform Actions
spellmoney-2.0.0-py3-none-any.whl Python 3 none any Details for spellmoney-2.0.0-py3-none-any.whl

Total release size: 64.1 kB

Release files / spellmoney-2.0.0.tar.gz

Download URL spellmoney-2.0.0.tar.gz
Size 35.7 kB
Tags Source
SHA-256 checksum
How to use checksums
ec732daf1317c9fc8011cdde6b20c47938bd528cebfbc1ddae4c683e27327e44
BLAKE2b-256 checksum
How to use checksums
fbe87377a9b9f392a60debafc1c5ee5a3552ab3bd6c2f9f7c8dedf8f4252bfbd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / spellmoney-2.0.0-py3-none-any.whl

Download URL spellmoney-2.0.0-py3-none-any.whl
Size 28.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b1d257ac319aa89963c6d8e47e8ab8395582851cc0d957e4b69501771b56decf
BLAKE2b-256 checksum
How to use checksums
4af2ebc1dbc10dac6111b07f423af4d758a2b8798e4822aae06905d58081a4ad
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for spellmoney 2.0.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page