speaker_helper.spoken_numbers module

Numbers, dates, times and amounts, said as words before an engine reads them.

Module summary

A neural engine trained on prose reads “le 14/11 à 9h30, 3 200 €” however its training data happened to: measured on 2026-11-04, Audio8 said “14/11” as an hour and swallowed the colon after “Correction”. Whisper hearing the right words back does not prove the listener did. The robust fix is the oldest one in speech synthesis: hand the engine words, not digits.

This module is that step for French and English, deterministic and dependency-free. Other languages pass through untouched — a wrong verbalisation is worse than the engine’s own guess. What it rewrites:

  • dates 14/11, 14/11/2026 (fr: day/month; en: month/day unless the first number cannot be a month);

  • times 9h30, 14 h, 9:30, 2:30 p.m.;

  • amounts 3 200 €, 12,50 €, 3 M€, $3,200, €12.50, £5;

  • percentages 7,94 %, 12%;

  • ordinals 1er, 2e, 3ème, 1st, 14th;

  • grouped and decimal numbers 3 200, 7,94 (fr) / 3,200, 2.91 (en), negatives, leading zeros (06 → “zéro six”), English years (2026 → “twenty twenty-six”).

It is applied by Speaker to what is spoken, never to what a page shows: a narration’s cues keep the document’s digits. settings.numbers_to_words = False turns it off.

Usage example

>>> from speaker_helper.spoken_numbers import verbalize
>>> verbalize("Rendez-vous le 14/11 à 9h30 pour 3 200 €.", "fr")
'Rendez-vous le quatorze novembre à neuf heures trente pour trois mille deux cents euros.'
>>> verbalize("Meet on July 12th at 2:30 p.m., $3,200.", "en")
'Meet on July twelfth at two thirty p.m., three thousand two hundred dollars.'

Author

Warith HARCHAOUI — https://linkedin.com/in/warith-harchaoui

speaker_helper.spoken_numbers.SUPPORTED_LANGUAGES: tuple[str, ...] = ('fr', 'en')

Languages this module verbalises; anything else is returned unchanged.

speaker_helper.spoken_numbers.en_cardinal(n)[source]

Spell a non-negative integer in English.

Examples

>>> en_cardinal(3200)
'three thousand two hundred'
>>> en_cardinal(1_000_001)
'one million one'
Parameters:

n (int)

Return type:

str

speaker_helper.spoken_numbers.en_ordinal(n)[source]

Spell an English ordinal.

Examples

>>> en_ordinal(1), en_ordinal(12), en_ordinal(14), en_ordinal(21), en_ordinal(40)
('first', 'twelfth', 'fourteenth', 'twenty-first', 'fortieth')
Parameters:

n (int)

Return type:

str

speaker_helper.spoken_numbers.en_year(n)[source]

Read a year the way English speakers do.

Examples

>>> en_year(2026), en_year(2000), en_year(2005)
('twenty twenty-six', 'two thousand', 'two thousand five')
>>> en_year(1999), en_year(1900)
('nineteen ninety-nine', 'nineteen hundred')
Parameters:

n (int)

Return type:

str

speaker_helper.spoken_numbers.fr_cardinal(n)[source]

Spell a non-negative integer in French.

Examples

>>> fr_cardinal(71)
'soixante et onze'
>>> fr_cardinal(3200)
'trois mille deux cents'
>>> fr_cardinal(80_000)
'quatre-vingt mille'
>>> fr_cardinal(2_000_001)
'deux millions un'
Parameters:

n (int)

Return type:

str

speaker_helper.spoken_numbers.fr_ordinal(n)[source]

Spell a French ordinal (1 → “premier”).

Examples

>>> fr_ordinal(1), fr_ordinal(5), fr_ordinal(9), fr_ordinal(21)
('premier', 'cinquième', 'neuvième', 'vingt et unième')
Parameters:

n (int)

Return type:

str

speaker_helper.spoken_numbers.verbalize(text, language)[source]

Rewrite the digits in text as the words a speaker would say.

Parameters:
  • text (str) – Text about to be synthesised.

  • language (str) – ISO-639-1 code ("fr-FR" is fine); anything but French or English returns text unchanged.

Returns:

The text with dates, times, amounts, percentages, ordinals and numbers spelled out; unchanged when it holds no digit.

Return type:

str

Examples

>>> verbalize("Correction : non pas le 14, mais le 15.", "fr")
'Correction : non pas le quatorze, mais le quinze.'
>>> verbalize("Un WER de 7,94 %.", "fr")
'Un WER de sept virgule quatre-vingt-quatorze pour cent.'
>>> verbalize("Hola 12", "es")
'Hola 12'