Number-to-words engine reference
Orientation
Choose a rendering engine by the language's composition, scale, gender, and ordinal rules. Locale-owned lexicons and switches belong in YAML; reusable composition stays in the shared runtime kernel.
Example
surfaces:
number:
words:
engine: 'conjunctional-scale'
minusWord: 'minus'
andWord: 'and'
Number-To-Words Engines
For every engine below, scalar *Word, *Prefix, *Suffix, *Joiner, and *Separator fields are literal locale-owned strings. Array *Map fields are lexical tables. scales is always ordered from larger to smaller scale values unless the engine documentation says otherwise.
When an engine has nested objects such as cardinal, ordinal, or endings, keep those groupings intact in YAML. They exist to keep one locale file readable by semantic area instead of flattening unrelated values into one giant list.
agglutinative-ordinal-scale
Fields:
minusWordtensSuffixteenSuffixordinalTensSuffixunitsMapordinalUnitsMapscalesordinalExceptions
appended-group
Fields:
zeroWordnegativeWordconjunctionWordordinalZeroWordordinalSeparatorWordordinalPrefixfirstOrdinalMasculinefirstOrdinalFemininegroupsappendedGroupspluralGroupsonesGrouptensGrouphundredsGroupappendedTwostwosfeminineOnesGroupordinalExceptionsfeminineOrdinalExceptions
billion-strategy
Fields:
minusWordandWordcardinalordinal
Nested cardinal fields:
hundredExactWordthousandWordmillionSingularWordmillionPluralWordbillionStrategybillionSingularWordbillionPluralWordscalesunitsMaptensMaphundredsMap
Nested ordinal fields:
billionStrategythousandWordmillionWordbillionWordmillionJoinModeunitsMaptensMaphundredsMap
Notes:
- Use this engine when a locale's main variability is how it names the billion scale and how the cardinal and ordinal branches differ at higher scales.
- Keep
cardinalandordinalwords separate even when many values happen to match; they model two distinct runtime sub-profiles. - Prefer descending
cardinal.scalesrows for authored values above one million. Each row declaresvalue,singular,plural, and optionalomitOne; the legacy billion fields remain available for existing profiles. ordinal.millionJoinModecontrols the separator beforemillionWord: usespacedfor a space orcompactfor no separator.
conjoined-gendered-scale
Fields:
minusWordconjunctionunitsMaptensMaphundredsMaphundredsOrdinalMapunitsOrdinalunitFormswith optionalmasculine,feminine, andneuterunit override mapsordinalZerowithmasculine,feminine, andneuterformsordinalOverHundredSuffixeswithmasculine,feminine, andneutersuffixes for hundreds and scale stemsordinalUnitsAndTensSuffixeswithmasculine,feminine, andneutersuffixes for unit and tens stemsscales
Notes:
- Omitted
unitFormsgender maps, or missing entries inside a gender map, fall back tounitsMap. The ordinal form blocks are required because there is no safe runtime fallback for locale-specific ordinal wording.
conjunctional-scale
Fields:
minusWordandWordhundredWordhundredOrdinalWordtensUnitsSeparatordefaultAddAndaddAndModeandStrategytupleSuffixordinalLeadingOneStrategyordinalModeordinalWholePhrasePrefixexactOrdinalsunitsMapordinalUnitsMaptensMapordinalTensMapscalesnamedTuples
Notes:
defaultAddAnd,addAndMode, andandStrategytogether define when conjunctions appear. Do not try to encode that behavior with ad hoc words or duplicated tables.ordinalModedecides whether ordinals come from dedicated lexical tables, whole-phrase prefixing, numeric suffixes, or other structural strategies within the shared kernel.ordinalWholePhrasePrefixsupplies the prefix for locales that form compound ordinals by prefixing the whole cardinal phrase.exactOrdinalsis a sparse value-to-word map for standalone ordinal exceptions that should bypass the compositional ordinal path. Use it when an exact value has a natural form that is not valid inside compounds; keep compound unit/tens wording inordinalUnitsMapandordinalTensMap.namedTuplesis for irregular compact tuple-style forms; keep it sparse and comment unusual values in the locale file.
construct-state-scale
Fields:
defaultGenderzeroWordminusWordandPrefixteenMasculineWordteenFeminineWordteenNormalizationOldteenNormalizationNewunitsFeminineunitsMasculinetensMaponeHundredWordtwoHundredsWordhundredsPluralSuffixthousandsPluralSuffixthousandsSingularSuffixthousandsSpecialCasesscalesuseCulture
contextual-decimal
Fields:
zeroWordminusWordordinalPrefixtenWordtensWordzeroTensWorddigitWordsscalesteenUnitExceptionspostTensUnitExceptionsexactOrdinals
contracted-one-scale
Fields:
zeroWordminusWordhundredWordhundredUnitWordunitstensscales
east-asian-grouped
Fields:
zeroWordnegativePrefixordinalPrefixordinalSuffixdigitWordssmallUnitWordslargeUnitsomitOneBeforeTenomitOneBeforeTenOnlyWhenLeadingomitOneBeforeHundredomitOneBeforeThousandinsertZeroInGroupinsertZeroBetweenGroupsordinalMap
Notes:
- Prefer sparse numeric-slot mappings for
smallUnitWordsorlargeUnitswhenever the locale only defines words from a non-zero starting slot. - The
omitOneBefore*flags are composition rules, not lexical exceptions; if you find yourself adding many one-off words instead, the locale may belong on a different engine.
east-slavic
Fields:
zeroWordminusWordzeroOrdinalStemhundredsMaptensMapunitsMapunitsOrdinalPrefixestensOrdinalPrefixestensOrdinalunitsOrdinalfeminineOneneuterOnefeminineTwooneOrdinalPrefixscalesendings
Nested endings fields:
masculinefeminineneuter
gendered-scale-ordinal
Fields:
zeroWordminusWordfeminineSingularmasculineOrdinalPrefixfeminineOrdinalPrefixmasculineOrdinalSuffixfeminineOrdinalSuffixjoinGroupsjoinAboveTwentyunitsVariantsteensVariantstensMapordinalUnderTenVariantsscales
harmony-ordinal
Fields:
minimumValuemaximumValueminusWordunitsMaptensMapscalestupleSuffixesnamedTupleshundredWordhundredStrategyordinalSuffixesterminalVowelOrdinalSuffixesordinalSuffixPairordinalSuffixStrategysecondOrdinalSuffixCharacterssoftenTerminalTBeforeSuffixdropTerminalVowelBeforeHarmonySuffix
Notes:
- Use this engine only for suffix systems driven by vowel harmony or final-character membership. If the locale needs wholly different tens/hundreds composition, start by checking another render-side engine first.
ordinalSuffixes,terminalVowelOrdinalSuffixes,ordinalSuffixPair, andsecondOrdinalSuffixCharacterswork together; document unusual combinations with a YAML comment in the locale file.- In
last-vowel-mapmode,ordinalSuffixesis the default map selected from the rendered word's last matching vowel. It should model the ordinary/consonant-final stem case, for example a Kyrgyz consonant-final stem with lastаcan useа: 'ынчы'to produceмиллиардынчы. terminalVowelOrdinalSuffixesis an optional override map used only when the rendered ordinal stem already ends in a configured vowel. Use it for harmony systems where a vowel-final cardinal stem takes a different ordinal suffix from a consonant-final stem with the same last vowel, for example Kyrgyzжыйырма+нчы->жыйырманчы, or Kazakh vowel-final stems that useншы/нші/сыншыinstead of the default consonant-final suffixes.terminalVowelOrdinalSuffixesdoes not affecttupleSuffixes; tuple rendering always uses the tuple suffix map directly.
hyphenated-scale
Fields:
zeroWordzeroOrdinalWordminusWordunitsMaptensMaphundredsMapordinalUnitsMapordinalUnitsExceptionsordinalTensMapscalesthousandScaletupleMaptwoPrefixWord
hyphenated-ordinal
Fields:
zeroWordnegativeWordunitsMasculineunitsFeminineteenstenshundredsMasculinehundredsFemininethousandWordmillionSingularmillionPluralmillionSingularPrefixmasculineCompoundOnefeminineCompoundOnemasculineScaleCountOnemasculineOrdinalOnefeminineOrdinalOneordinalHundredsMasculineordinalHundredsFeminineordinalMasculineordinalFeminineordinalUnitComponentsordinalTensStemsmasculineTensOrdinalSuffixfeminineTensOrdinalSuffixdefaultOrdinalAbbreviationMasculinedefaultOrdinalAbbreviationFeminineordinalAbbreviationsdefaultTensJoinerspecialTensJoinerspecialJoinerTensValuetupleMaptupleFallbackWordscales
Scale rows declare value, singular, plural, ordinalMasculine, and
ordinalFeminine. They may also declare singularPrefix, omitOne,
countUsesRequestedGender, and groupCountByThousands.
linked-vigesimal
Use this render and parse engine pair for locales whose natural lower numbers are lexicalized or linked/vigesimal, while larger values are built with scale nouns before their counts. Yoruba (yo) uses it for directly authored sub-100 forms such as mẹ́tàlélógún, with scale rows for ẹgbẹ̀rún kan, igba, and other hundred-scale overrides. Do not use this engine for bound-stem scale morphology; use stemmed-scale for that case.
Render fields:
zeroWordnegativeWordnegativeJoinerpartJoinerterminalRemainderJoinerterminalRemainderAlternateJoiner(optional; used when the rendered terminal remainder starts with a configured initial)terminalRemainderAlternateJoinerInitials(optional initial-character set for the alternate joiner)terminalRemainderThresholdordinalSuffixwords— dense cardinal words from zero through the highest lexicalized low numberscalesordinalExceptions
Nested scales fields:
valueoneoneWithRemainder(optional; defaults toone)namenameWithRemainder(optional; defaults toname)countJoiner(optional; defaults to a space)countOverrides(optional exact phrases keyed by scale count)countOverridesWithRemainder(optional exact phrases keyed by scale count)
Parse fields mirror render-side words, scales, terminalRemainderJoiner, and optional terminalRemainderAlternateJoiner, plus optional negativePrefixes, ordinalSuffixes, ordinalMap, and additionalCardinals. Parsers accept both the base and alternate terminal joiner tokens; parser profiles do not need terminalRemainderAlternateJoinerInitials because they match explicit joiner tokens rather than selecting a joiner while rendering.
stemmed-scale
Use this render and parse engine pair for additive count+scale systems where a count has an independent cardinal word, but scale composition uses a bound count stem before the scale suffix. Sinhala (si) uses it for forms such as දෙ + දහස් -> දෙදහස් while still emitting independent low-number words such as දෙක.
Render fields:
zeroWordnegativeWordnegativeJoinerjoinerordinalSuffixwords— dense cardinal words for 0 through the highest directly authored low numbercountStems— dense bound stems indexed by count; empty entries are allowed for counts that should fall back towordsscalesordinalExceptions
Nested scales fields:
valueoneoneWithRemaindersuffixsuffixWithRemainderstemJoiner(optional; defaults to empty)fallbackName/fallbackNameWithRemainder(optional; used when no bound stem exists for a scale count)fallbackJoiner(optional; defaults to a space)
Parse fields:
wordscountStemsscalesnegativePrefixesordinalSuffixesordinalMapadditionalCardinals(optional)
Notes:
- Keep this engine narrow. It is additive count+scale stem morphology, not a general natural-number grammar engine. Do not use it for vigesimal, subtractive, or clock-like composition.
- The parser greedily tokenizes generated scale/count forms and low-number phrases so multi-word low cardinals can round-trip.
- Author
number.wordsandnumber.parsewith matchingwords,countStems, andscalesunless the parser has a documented reason to accept additional input-only forms.
indian-scale-forms
Fields:
zeroWordnegativeWordordinalSuffixdenseUnitsMapscalesordinalMapordinalTerminalReplacements
Nested scales fields:
valuesingularsingularWithRemainderpluralpluralWithRemainderomitOne
Notes:
- Use this engine for Indian-grouped decimal systems whose scale nouns have singular, plural, and continuing forms. Telugu (
te) uses it for forms such as lakh/crore scale phrases that change when a lower remainder follows. denseUnitsMapmust provide words for 0 through 99; the lowest scale value must be covered by that dense range.scalesare ordered from larger to smaller scale values. Each row can omit the explicit one-count word withomitOne.ordinalTerminalReplacementsrewrites terminal cardinal tokens before appendingordinalSuffix, whileordinalMaphandles exact irregular ordinals.
indian-grouping
Fields:
zeroWordnegativeWordunitsMaptensMaphundredsMapthousandsMapsingleLakhWordlakhWordcroreWordquadrillionWordquintillionWordthousandsOneBridgehundredsContinuingSuffixhundredsExactSuffixhundredsNineContinuingSuffixhundredsNineExactSuffixdefaultTensWithRemainderSuffixnineTensWithRemainderSuffixspecialTensWithRemainderSuffixexactTensDefaultSuffixexactTensNineSuffixthousandContinuingSuffixthousandExactSuffixlakhContinuingSuffixlakhExactSuffixcroreContinuingSuffixordinalSuffixordinalExceptions
indian-grouping-gendered
Fields:
zeroWordnegativeWordhundredWordthousandWordlakhWordsingleLakhWordcroreWordarabWordkharabWorddenseUnitsMapordinal
Nested ordinal fields:
masculine.defaultSuffixmasculine.exactReplacementsfeminine.defaultSuffixfeminine.exactReplacementsneuterFallback
Notes:
- This engine is used by Indian-subcontinent locales with lakh/crore/arab/kharab grouping and gendered word ordinals, such as Hindi, Punjabi, and Urdu.
denseUnitsMapsupplies the cardinal word forms used below one hundred and for recursive scale counts.ordinal.masculineandordinal.femininemodel productive suffixes plus exact low-number replacements.neuterFallbackmust bemasculineorfeminineand is used when callers requestGrammaticalGender.Neuterfor a two-gender locale.
inverted-tens
Fields:
minusWordunitsMaptensMaphundredWordoneHundredWordhundredsPrefixMapunitTensJoinerunitTensAlternateJoinerunitTensAlternateJoinerUnitEndinghundredJoinerhundredRemainderSeparatorhundredTailPrefixhundredTailPrefixModescaleTailPrefixscaleTailPrefixModeleadingOneWordleadingOnePreservePrefixscalesordinalModeordinalDefaultSuffixordinalSteSuffixordinalSteSuffixEndingCharsordinalExceptionsremoveLeadingOneInOrdinal
joined-scale
Fields:
zeroWordminusWordjoinWordnegativeJoinWordunderHundredJoinWordscaleCountJoinWordcompoundOrdinalWordcompoundOrdinalRemainderdefaultOrdinalSuffixmatchingOrdinalSuffixordinalSuffixMatchCharactersmaximumValueomitOneWhenSingularAlwayssubHundredMapunitsMaptensMaphundredsMaphundredsMapWithRemainderscalesvaluenamenameWithRemainder(optional)pluralName(optional)pluralNameWithRemainder(optional)omitOneWhenSingular(optional)
ordinalExceptionscompoundOrdinalExcludedValuesordinal: optional gendered word-ordinal profile. When present, it overrides the legacydefaultOrdinalSuffix/ordinalExceptionspath forToOrdinalWords(number, gender, culture).masculine: gender block withdefaultSuffixand optionalexactReplacements.feminine: optional gender block with the same shape asmasculine.neuter: optional gender block with the same shape asmasculine.neuterFallback: gender to use whenGrammaticalGender.Neuteris requested and noneuterblock exists. Must be'masculine'or'feminine'.joined-scaleintentionally allows omittedfeminineandneuterblocks because some locales only need masculine word ordinals or use masculine as a shared fallback. This differs fromordinalizer: number-word-suffix, which requires bothmasculineandfemininebecause that ordinalizer surface models explicitly gendered numeric ordinalization.
compositionalOrdinal: optional word-replacement profile for locales that form compound ordinals by changing each cardinal token.nonTerminalReplacements: token replacements used before the final token.terminalReplacements: token replacements used for the final token.compactTerminalWords: scale words that join directly to the preceding transformed count.
Join fields are literal strings, not separator-mode enums:
negativeJoinWordjoinsminusWordto the positive number phrase and defaults to one space.scaleCountJoinWordjoins a rendered scale count to its scale name and defaults to one space.underHundredJoinWordjoins pieces inside an under-hundred fragment. Omit it to reusejoinWord; set it explicitly when the locale needs a different literal, including an empty string.
linking-scale
Fields:
zeroWordminusWordunitsMaptensMaphundredWordsconjunctionWordtensRemainderJoinerscalePrefixesscaleLinkRulesscales
long-scale-stem-ordinal
Fields:
zeroWordnegativeWordunitsMasculineunitsFeminineunitsMasculineAbbreviationtensMaptensJoinerhundredthsRootsthousandthsRootsordinalUnitRootstenthsRootsexactHundredWordminLongValueWordthousandWordthousandOrdinalStemhighestScaleValuehighestScaleOrdinalSourcehighestScaleOrdinalTargetroundHigherScaleCompactValuemasculineOrdinalEndingfeminineOrdinalEndingtupleMaptupleFallbackSuffixhundredsMasculinehundredsFemininelargeScales
dual-form-scale
Fields:
prefixMapunitsMaptensMapconjunctionhundredWordhundredPrefixWorddualHundredsWordfeminineOneWordthousandScalemillionScalebillionScaleexactOrdinalsminusSuffix
ordinal-prefix-scale
Fields:
minusWordandWorddefaultGenderunitsMapmasculineUnitsMapfeminineUnitsMapneuterUnitsMaptensMapunitsOrdinalPrefixestensOrdinalPrefixeshundredSingularhundredPluralordinalTwoMasculineordinalTwoFeminineordinalTwoNeutermasculineOrdinalEndingnonMasculineOrdinalEndingscales
pluralized-scale
Fields:
zeroWordminusWordzeroOrdinalStemunitsMaptensMaphundredsMapscalesformDetectorunitVariantStrategyordinalModesupportsNeutermasculineOrdinalSuffixfeminineOrdinalSuffixordinalUnitsMapordinalTensMapordinalHundredsMapuseCulture
scale-leading-compound
Fields:
zeroWordminusWordconjunctionWordterminalRemainderConjunctionWordordinalPrefixordinalSuffixunitsMaptensMapscalesordinalMap
Nested scales fields:
valuename
Notes:
- Use this engine for languages whose scale noun precedes the count token, for example a structure like "hundred one and two". Hausa (
ha) and Swahili (sw) use this shared family. unitsMapmust cover 0 through 19 andtensMapmust be keyed through index 9.scalesare ordered from larger to smaller scale values and must include a scale no greater than 100 so the recursive renderer can decompose all larger numbers.conjunctionWordjoins tens-plus-units and terminal sub-hundred remainders.terminalRemainderConjunctionWordcan override that conjunction for potentially ambiguous terminal remainders after larger scales; when omitted, it falls back toconjunctionWord.- Ordinals use
ordinalMapfor exact values. Otherwise the engine wraps the cardinal phrase withordinalPrefixandordinalSuffix.
scale-strategy
Fields:
cardinalStrategyordinalStrategymaximumValuedefaultGenderzeroWordminusWordoneDefaultoneMasculineoneFeminineoneNeutertensLinkerlargeScaleRemainderJoinerexactLargeScaleOrdinalSuffixexactDefaultOrdinalSuffixtensOrdinalTrimEndCharacterstensOrdinalSuffixshortOrdinalUpperBoundExclusiveshortOrdinalTrimEndCharactersshortOrdinalTrimmedSuffixshortOrdinalSuffixhundredWordhundredCompositeSingularWordthousandWordthousandSingularWordthousandCompositeSingularWordunitsMaptensMaphundredUnitMapscalesordinalExceptions
Notes:
- This engine is for locales where the same broad scale decomposition works, but the exact cardinal and ordinal policies vary by strategy enum.
- Use
cardinalStrategyandordinalStrategybefore adding extra booleans. If a new distinction cannot be named cleanly as a strategy, the kernel may need redesign instead of more flags.
segmented-scale
Fields:
maximumValuezeroWordminusWordteenPrefixexactOneHundredWordunitsDefaultunitsPluralizedtensMaphundredsDefaulthundredsPluralizedscalesmaximumOrdinalordinalMap
south-slavic-cardinal
Fields:
maximumValueallowLongMinzeroWordminusWordscaleFormDetectornumberCompositioninvertedTensLinkerunitsMaptensMaphundredsMapfeminineOnefeminineTwoordinalSuffixordinalCompoundJoinerordinalUnitsMapordinalTensMapordinalHundredsMapscales
Each scales row includes value, gender, singular, paucal, and
plural. It can also supply oneForm, dual, trialQuadral, ordinal, and
pipe-delimited ordinalCountPrefixes.
terminal-ordinal-scale
Fields:
zeroWordminusWordunitStemsordinalUnitStemstensMaphundredsExactStemsexactOneHundredCardinalexactOneHundredAfterHigherScaleoneHundredWithRemainderhundredsPluralWordmasculineOrdinalSuffixfeminineOrdinalSuffixscales
triad-scale
Fields:
zeroWordminusWordfeminineOneWordleadingOneWordtenWordtenOrdinalStemcommonOrdinalStemmasculineOrdinalSuffixfeminineOrdinalSuffixordinalUnit3RestoredVowelordinalUnit6RestoredVowelunitsMapunitsFinalAccenttensMapteensMaphundredsMapordinalUnderTenscales
unit-leading-compound
Fields:
zeroWordminusWordmasculineOnefeminineOneneuterOnefeminineTwotensJoinertensJoinerTransformordinalStemSuffixmasculineOrdinalEndingfeminineOrdinalEndingneuterOrdinalEndingsupportsEifelerRuleunitsMapcompoundUnitsMaptensMapunitsOrdinalscales
variant-decade
Fields:
minusWordseventyStrategyninetyStrategyspecialSeventyOneWordpluralizeExactEightytensUsingEtWhenUnitIsOnetensMapscales
Nested scales fields:
valuesingularpluralomitOne(optional)pluralizeMultiplier(optional; defaults totrue)
The same authored scale rows drive both number-word rendering and metric
UseScaleWord output.
west-slavic-gendered
Fields:
minusWordunitsMaptensMaphundredsMapunitsMasculineFormsunitsFeminineFormsunitsNeuterFormsunitsInvariantFormsthousandsmillionsbillionsuseCulture
Pitfall
Do not select an engine by name resemblance alone or add locale-specific branches to a shared kernel. Exact-output tests must cover the rule boundaries, not only single-digit examples.
Version notes
These rendering engines are the accepted main/preview contracts.
Historical branches may use different engines or handwritten converters.