Skip to main content
Version: 4.0 (next)

Locale YAML how-to

Orientation

Each file under src/Humanizer/Locales owns one locale. YAML holds words, phrases, lexical tables, formatting overrides, and structural engine choices. Reusable algorithms stay in runtime C#; the source generator compiles YAML into typed registrations, so runtime code never parses YAML or JSON.

Valid top-level keys are locale, optional variantOf, and surfaces. Canonical surfaces are list, formatter, phrases, inflection, number, ordinal, clock, compass, and calendar.

Example

locale: 'en-US'
variantOf: 'en'

surfaces:
number:
words:
engine: 'conjunctional-scale'
minusWord: 'minus'
andWord: 'and'
parse:
engine: 'token-map'
normalizationProfile: 'LowercaseRemovePeriods'
cardinalMap:
one: 1
two: 2

Author dense lexical tables as sequences when every slot matters. Use numeric keys for sparse tables:

tensMap:
2: 'twenty'
3: 'thirty'

Inheritance merges mappings and replaces sequences. A child scalar replaces the parent scalar. Changing engine replaces that mapped block.

Use calendar.months, calendar.monthsGenitive, or calendar.hijriMonths only when platform globalization data is incorrect or differs across targets. Use number.formatting for proven decimal-separator, negative-sign, or group-separator drift. These overrides do not mutate CultureInfo and do not override a caller-supplied custom provider.

Follow the complete platform globalization override recipe to capture the cross-target probe, author the narrowest override, and test every affected API.

Pitfall

Omission is the inheritance signal; do not use empty mappings. Do not add a block merely to say “default.” The narrow exception is engine: 'default' on the documented ordinal and clock surfaces.

Keep phrases (the output tables) separate from formatter (selection and grammar metadata). Keep render-side number.words aligned with parse-side number.parse.

If no existing engine fits, use the engine-choice workflow before adding schema or runtime code.

Version notes

This authoring contract is for main/preview. The exhaustive YAML reference lists the currently accepted engines and fields. Historical branches can have different schema and runtime ownership; use their source rather than copying a current block backward.