Modules to convert numbers to words in multiple languages with support for 50+ locales.
—
The foundation of num2words is the Num2Word_Base class, which provides the core architecture and methods that all language-specific converters inherit from. This design enables consistent behavior across all 50+ supported languages while allowing for language-specific customizations.
The foundation class that all language converters inherit from.
class Num2Word_Base:
"""
Base class for all language-specific number-to-word converters.
Attributes:
- CURRENCY_FORMS: dict - Currency format definitions for the language
- CURRENCY_ADJECTIVES: dict - Currency adjective forms
- is_title: bool - Whether to title-case output
- precision: int - Decimal precision for float handling
- negword: str - Prefix for negative numbers
- pointword: str - Word for decimal point
- cards: OrderedDict - Number word mappings
- MAXVAL: int - Maximum supported number value
"""
def __init__(self): ...Usage Examples:
from num2words.base import Num2Word_Base
# Access base converter (not typically used directly)
base_converter = Num2Word_Base()
# Language converters inherit from this base
from num2words import CONVERTER_CLASSES
english_converter = CONVERTER_CLASSES['en']
print(type(english_converter).__bases__) # Shows Num2Word_Base in inheritanceCore method for converting numbers to cardinal word form.
def to_cardinal(self, value):
"""
Convert number to cardinal word representation.
Parameters:
- value: int/float - Number to convert
Returns:
str - Cardinal number as words
Raises:
OverflowError - If number exceeds MAXVAL
"""Usage Examples:
from num2words import CONVERTER_CLASSES
# Access converter directly
en_converter = CONVERTER_CLASSES['en']
result = en_converter.to_cardinal(42) # "forty-two"
result = en_converter.to_cardinal(-15) # "minus fifteen"
result = en_converter.to_cardinal(1000) # "one thousand"
# Different languages
fr_converter = CONVERTER_CLASSES['fr']
result = fr_converter.to_cardinal(42) # "quarante-deux"Specialized handling for floating-point numbers.
def to_cardinal_float(self, value):
"""
Convert floating-point number to word representation.
Handles decimal precision and fractional parts appropriately.
Parameters:
- value: float - Float number to convert
Returns:
str - Float number with decimal point as words
Raises:
TypeError - For invalid number types
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
result = en_converter.to_cardinal_float(42.5) # "forty-two point five"
result = en_converter.to_cardinal_float(3.14) # "three point one four"
result = en_converter.to_cardinal_float(0.001) # "zero point zero zero one"Convert numbers to ordinal form (language-dependent implementation).
def to_ordinal(self, value):
"""
Convert number to ordinal word representation.
Base implementation delegates to to_cardinal.
Language subclasses override for proper ordinal forms.
Parameters:
- value: int - Integer to convert to ordinal
Returns:
str - Ordinal number as words
Raises:
TypeError - For float inputs or negative numbers
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
result = en_converter.to_ordinal(1) # "first"
result = en_converter.to_ordinal(2) # "second"
result = en_converter.to_ordinal(21) # "twenty-first"
result = en_converter.to_ordinal(42) # "forty-second"
# Validation
try:
en_converter.to_ordinal(42.5) # Floats not allowed
except TypeError:
print("Ordinals require integers")Convert numbers to numeric ordinal form.
def to_ordinal_num(self, value):
"""
Convert number to numeric ordinal representation.
Base implementation returns the number unchanged.
Language subclasses override for proper suffixes.
Parameters:
- value: int - Integer to convert
Returns:
str - Numeric ordinal (e.g., "42nd")
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
result = en_converter.to_ordinal_num(1) # "1st"
result = en_converter.to_ordinal_num(2) # "2nd"
result = en_converter.to_ordinal_num(3) # "3rd"
result = en_converter.to_ordinal_num(4) # "4th"
result = en_converter.to_ordinal_num(21) # "21st"Convert numbers to year word format.
def to_year(self, value, **kwargs):
"""
Convert number to year word representation.
Base implementation delegates to to_cardinal.
Language subclasses can override for year-specific formatting.
Parameters:
- value: int - Year to convert
- **kwargs: Language-specific year formatting options
Returns:
str - Year as words
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
result = en_converter.to_year(1984) # "nineteen eighty-four"
result = en_converter.to_year(2000) # "two thousand"
result = en_converter.to_year(2023) # "twenty twenty-three"Convert numbers to currency format with proper localization.
def to_currency(self, val, currency='EUR', cents=True, separator=',', adjective=False):
"""
Convert number to currency word representation.
Parameters:
- val: int/float - Currency value
- currency: str - Currency code (default: 'EUR')
- cents: bool - Include verbose cents (default: True)
- separator: str - Separator between currency and cents (default: ',')
- adjective: bool - Include currency adjective prefix (default: False)
Returns:
str - Formatted currency string
Raises:
NotImplementedError - If currency not supported for language
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
result = en_converter.to_currency(42.50)
# "forty-two euros, fifty cents"
result = en_converter.to_currency(42.50, currency='USD')
# "forty-two dollars, fifty cents"
result = en_converter.to_currency(42.50, cents=False)
# "forty-two euros, 50"
result = en_converter.to_currency(42.50, separator=' and ')
# "forty-two euros and fifty cents"Convert string representations to numeric values.
def str_to_number(self, value):
"""
Convert string to Decimal number for processing.
Parameters:
- value: str - String representation of number
Returns:
Decimal - Parsed number
Raises:
ValueError - For invalid string formats
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
number = en_converter.str_to_number("42") # Decimal('42')
number = en_converter.str_to_number("42.5") # Decimal('42.5')
number = en_converter.str_to_number("-15") # Decimal('-15')Internal methods for breaking down numbers according to language rules.
def splitnum(self, value):
"""
Split number into components according to language rules.
Parameters:
- value: int - Number to split
Returns:
list - Structured number components for word generation
"""
def float2tuple(self, value):
"""
Split float into integer and fractional parts.
Parameters:
- value: float - Float to split
Returns:
tuple - (integer_part, fractional_part)
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
# Split complex numbers
components = en_converter.splitnum(1234567)
# Returns structured breakdown for "one million, two hundred..."
# Split floats
integer_part, fractional_part = en_converter.float2tuple(42.567)
# Returns (42, 567) with appropriate precision handlingMethods for configuring language-specific behavior.
def setup(self):
"""
Language-specific setup method.
Override in language subclasses to configure:
- negword: Negative number prefix
- pointword: Decimal point word
- exclude_title: Words to exclude from title casing
- Number word dictionaries and mappings
"""
def set_numwords(self):
"""Set up number word dictionaries from language definitions."""
def set_high_numwords(self, *args):
"""Set up high-value number words (millions, billions, etc.)."""
def set_mid_numwords(self, mid):
"""Set up mid-range number words (tens, hundreds)."""
def set_low_numwords(self, numwords):
"""Set up low-value number words (0-19)."""Specialized method for splitting numbers with custom formatting options.
def to_splitnum(self, val, hightxt="", lowtxt="", jointxt="", divisor=100, longval=True, cents=True):
"""
Split number into high and low components with custom formatting.
Primarily used for currency and complex number formatting.
Parameters:
- val: int/float/tuple - Value to split
- hightxt: str - Text for high component
- lowtxt: str - Text for low component
- jointxt: str - Text to join components
- divisor: int - Division factor (default: 100)
- longval: bool - Use verbose format (default: True)
- cents: bool - Verbose cents representation (default: True)
Returns:
str - Formatted split number string
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
# Currency-style splitting
result = en_converter.to_splitnum(42.50, hightxt="dollars", lowtxt="cents")
# "forty-two dollars fifty cents"
# Custom splitting with divisor
result = en_converter.to_splitnum(365, hightxt="years", lowtxt="days", divisor=365)
# Custom format based on divisorInternal methods used by to_currency() for formatting currency components.
def _money_verbose(self, number, currency):
"""
Convert currency major unit to verbose representation.
Parameters:
- number: int - Major currency unit
- currency: str - Currency code
Returns:
str - Verbose representation of major currency unit
"""
def _cents_verbose(self, number, currency):
"""
Convert currency minor unit to verbose representation.
Parameters:
- number: int - Minor currency unit (cents)
- currency: str - Currency code
Returns:
str - Verbose representation of minor currency unit
"""
def _cents_terse(self, number, currency):
"""
Convert currency minor unit to terse numeric representation.
Parameters:
- number: int - Minor currency unit (cents)
- currency: str - Currency code
Returns:
str - Terse numeric representation (e.g., "50")
"""Usage Examples:
en_converter = CONVERTER_CLASSES['en']
# These are internal methods used by to_currency()
money_part = en_converter._money_verbose(42, 'EUR') # "forty-two"
cents_part = en_converter._cents_verbose(50, 'EUR') # "fifty"
cents_terse = en_converter._cents_terse(50, 'EUR') # "50"Helper methods for text processing and formatting.
def title(self, value):
"""
Apply title casing based on is_title setting.
Parameters:
- value: str - Text to potentially title-case
Returns:
str - Formatted text
"""
def inflect(self, value, text):
"""
Basic pluralization for currency and other forms.
Parameters:
- value: int - Number for pluralization decision
- text: str - Text with plural forms (format: "singular/plural")
Returns:
str - Appropriately inflected text
"""
def parse_minus(self, num_str):
"""
Extract minus sign from number string.
Parameters:
- num_str: str - Number string that may start with '-'
Returns:
tuple - (minus_prefix, cleaned_number_string)
"""Methods that must be implemented by language subclasses.
def pluralize(self, n, forms):
"""
Language-specific pluralization rules.
Must be implemented by language subclasses.
Parameters:
- n: int - Number for pluralization decision
- forms: tuple - Available forms for pluralization
Returns:
str - Correctly pluralized form
Raises:
NotImplementedError - If not implemented by subclass
"""
def merge(self, curr, next):
"""
Language-specific number component merging.
Must be implemented by language subclasses.
Parameters:
- curr: tuple - Current number component
- next: tuple - Next number component
Returns:
tuple - Merged component
Raises:
NotImplementedError - If not implemented by subclass
"""The language converters follow a clear inheritance pattern:
# Base class
Num2Word_Base
├── Num2Word_EU (European base class)
│ ├── Num2Word_EN (English)
│ │ ├── Num2Word_EN_IN (English India)
│ │ └── Num2Word_EN_NG (English Nigeria)
│ ├── Num2Word_FR (French)
│ │ ├── Num2Word_FR_BE (French Belgium)
│ │ ├── Num2Word_FR_CH (French Switzerland)
│ │ └── Num2Word_FR_DZ (French Algeria)
│ ├── Num2Word_ES (Spanish)
│ │ ├── Num2Word_ES_CO (Spanish Colombia)
│ │ ├── Num2Word_ES_CR (Spanish Costa Rica)
│ │ └── ...
│ └── ... (other European languages)
├── Num2Word_AR (Arabic)
├── Num2Word_JA (Japanese)
├── Num2Word_KO (Korean)
└── ... (other non-European languages)Each converter can be configured with various attributes:
class ConverterAttributes:
"""Common configuration attributes for converters."""
# Text formatting
is_title: bool = False # Enable title casing
exclude_title: list = [] # Words to exclude from title casing
# Number representation
negword: str = "(-) " # Negative number prefix
pointword: str = "(.)" # Decimal point representation
precision: int = 2 # Decimal precision
# Currency support
CURRENCY_FORMS: dict = {} # Currency name forms
CURRENCY_ADJECTIVES: dict = {} # Currency adjectives
# Number limits
MAXVAL: int # Maximum supported number
# Error messages
errmsg_nonnum: str # Non-numeric input error
errmsg_floatord: str # Float ordinal error
errmsg_negord: str # Negative ordinal error
errmsg_toobig: str # Number too large errorThe base converter provides standardized error handling:
# Type validation
converter = CONVERTER_CLASSES['en']
try:
converter.to_ordinal(42.5) # Floats not allowed for ordinals
except TypeError as e:
print(e) # "Cannot treat float 42.5 as ordinal."
try:
converter.to_ordinal(-5) # Negative numbers not allowed for ordinals
except TypeError as e:
print(e) # "Cannot treat negative num -5 as ordinal."
# Overflow protection
try:
converter.to_cardinal(10**100) # Exceeds MAXVAL
except OverflowError as e:
print(e) # "abs(value) must be less than MAXVAL."Install with Tessl CLI
npx tessl i tessl/pypi-num2words