Adding a language
July 31, 2026 · View on GitHub
Every language lives in its own module, ovos_number_parser/numbers_<code>.py,
and is wired into the dispatcher functions in ovos_number_parser/__init__.py.
1. Pick the implementation style
Romance languages (or any language with unit/ten/hundred/scale structure and joiner words) should use the declarative vocabulary engine: describe the language, don't reimplement the algorithm:
from ovos_number_parser.util import NumberVocabulary, RomanceNumberExtractor, Scale
_XX = NumberVocabulary(
LANG="xx-XX",
JOIN_WORD=["e"],
JOINER_ON_TWENTYS=True,
JOINER_ON_HUNDREDS=False,
JOINER_ON_THOUSANDS=False,
DECIMAL_MARKER=["coma", ".", ","],
NEGATIVE_SIGN=["menos"],
HUNDRED_PARTICLE="cento",
UNITS={0: "...", 1: "...", ...},
TENS={...},
HUNDREDS={...},
SHORT_SCALE={...},
LONG_SCALE={...},
ORDINAL_UNITS={...},
FRACTION={...},
...
)
XX = RomanceNumberExtractor(_XX)
See numbers_gl.py or numbers_ast.py for complete worked examples, and the
NumberVocabulary docstrings in util.py for every knob. Languages with
articled scale groups ("o mie"), a count-to-scale linker word
("douăzeci de mii"), multiplicative hundreds words ("două sute" = 200)
or particle-based ordinals ("al doilea"/"a doua") can describe those with
SCALE_ONE, SCALE_LINKER, SCALE_GENDERS, MULTIPLY_HUNDREDS,
FRACTION_ONE, JOINER_ON_SCALE_REMAINDER and the ORDINAL_PREFIX family.
See numbers_ro.py for a worked example.
Other language families implement the functions directly. Use an existing module of the same family as a template:
- Germanic compound-word languages:
numbers_de.py(includes the compound-splitting helpers). - Slavic languages with declension:
numbers_cs.pyornumbers_ru.py. - Token-based summing parsers:
numbers_en.py.
2. Functions to provide
At minimum:
pronounce_number_<code>(number, places=2, ...)extract_number_<code>(text, short_scale=True, ordinals=False)
Nice to have:
is_fractional_<code>,is_ordinal_<code>pronounce_ordinal_<code>numbers_to_digits_<code>
3. Wire the dispatcher
Add the language-prefix branch to each matching top-level function in
__init__.py (pronounce_number, extract_number, is_fractional, ...).
4. Tests
Add tests/test_number_parser_<code>.py with three parts (see any existing
language test for the pattern):
- Pronounce anchors: hand-verified spoken forms for a fixed set of values (0-20, tens, 100, 101, 123, 999, 1000, 2023, 1e6, ...).
- Extract anchors: the same table driven in reverse.
- Round-trip sweep:
extract_number(pronounce_number(n))must returnnover a wide range. This catches vocabulary typos and asymmetries cheaply.
Anchor expectations must come from reference material or native usage. Never trust engine output you have not verified. A wrong anchor locks the bug in.
5. README
Add the language row to the support matrix in README.md.