Skip to main content
Version: 4.0 (next)

Locale YAML reference

Orientation

This is the index for the canonical main/preview authoring contract under src/Humanizer/Locales/*.yml. Use the smallest reference that answers the question:

Together with Locale YAML how-to and Add or update a locale, these references describe the checked-in locale contract without requiring contributors to reverse-engineer generator source.

Example

A regional variant declares its parent and overrides only real differences:

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

surfaces:
list:
engine: 'oxford'

Omitted surfaces inherit from en. A parity claim still needs a recorded ownership chain and proving assertions for inherited surfaces.

Grammatical-case duration surface

Every terminal locale root must classify surfaces.durationCases; a regional variant may inherit that classification only through its declared same-language, same-script variantOf chain. An authored child block replaces the parent's entire duration-case surface; omit the block to inherit it.

The release classifications are:

  • distinct: the locale has an evidenced case inventory and explicitly realizes every inventory case.
  • invariant: the locale has an evidenced inventory whose applicable cases have the same written duration rendering.
  • not-applicable: grammatical case is not applicable to this locale's narrowed written duration surface, with an authoritative reason.

unsupported is available only while developing locale data. Release validation rejects every applicable unsupported root, case, and unit.

Each non-not-applicable root declares:

  • inventory: every case in the language's written bare-duration scope.
  • citationCase: the inventory case whose authored base-duration phrases provide the locale's citation rendering. It is commonly nominative, but locales such as Basque use absolutive; the generator rejects a citation case that is absent from the inventory.
  • sources: immutable CLDR, grammar, corpus, native-authored, or native-review evidence with URL, revision, locator, and credit.
  • cases: exactly one realization for every inventory case.

Checked-in locale YAML appends a same-line DS173237 waiver to immutable 40-hex revision values because DevSkim otherwise mistakes Git commit hashes for secrets. The waiver applies only to that revision line and rule.

A case realization is exactly one of:

  • authored, with all eight units;
  • sameRenderedAs: <case>, for an evidenced same-written-output relationship;
  • notApplicable: <reason>, with provenance; or
  • development-only unsupported: <reason>.

An authored unit is exactly one of phrase, sameRenderedAs, notApplicable, or development-only unsupported. Case and unit aliases are flattened during generation. Missing targets, self references, cycles, and aliases to unavailable data fail generation.

surfaces:
durationCases:
classification: 'distinct'
inventory:
- 'nominative'
- 'dative'
citationCase: 'nominative'
sources:
cldr48:
kind: 'cldr'
url: 'https://github.com/unicode-org/cldr/blob/acd6d88ae493633240e19a87a721076a8a75c310/common/main/de.xml'
revision: 'acd6d88ae493633240e19a87a721076a8a75c310'
locator: 'long duration-unit patterns'
credit: 'Unicode CLDR contributors'
cases:
nominative:
authored: 'base-duration'
provenance: [cldr48]
dative:
authored:
units:
millisecond:
sameRenderedAs: nominative
provenance: [cldr48]
second:
phrase:
single:
numeric: '1 Sekunde'
words: 'einer Sekunde'
multiple:
forms: 'Sekunden'
provenance: [cldr48]
# minute through year are also required
provenance: [cldr48]

Case-aware calls validate the requested case against inventory before looking up a phrase and fail clearly when it is unavailable. Existing case-free Humanize calls continue to use the legacy duration path unchanged.

Phrase leaves use the same singular and counted-phrase grammar as surfaces.phrases.duration. Every authored leaf supplies a singular phrase and a numeric multiple phrase. When surfaces.formatter.casePluralRule is explicitly declared, every reachable named multiple form is also required for authored overlays and citation/base duration phrases. For example, casePluralRule: arabic-cardinal requires default, zero, dual, plural, and many; count 1 remains the separate singular branch. Without an explicit case plural rule, normal multiple-form fallback remains valid. The singular words variant can contain a locale-authored one-word or article phrase; counted forms may write the count or encode it in the unit morphology. Do not synthesize prepositions or arbitrary number-word declension.

At runtime, HumanizeWithCase returns a bare duration phrase. Nominative also uses the case-aware singular selection. sameRenderedAs selects the evidenced same-language rendering; notApplicable, unsupported, an absent requested case, or an unsupported unit throws NotSupportedException. Missing classifications or incomplete overlays fail generation, and no path falls back to English or invents morphology. Case-aware duration formatting is independent of relative-date and date-ordinal grammar.

Generator Pipeline Touchpoints

These are the main files that turn locale YAML into runtime behavior:

  1. src/Humanizer.SourceGenerators/Common/LocaleYamlCatalog.cs
    • reads YAML
    • resolves locale inheritance
    • merges child mappings with parent mappings
    • normalizes author-facing references such as self
  2. src/Humanizer.SourceGenerators/Common/EngineContractCatalog.cs
    • defines the typed generator-side structural contracts for shared engines
  3. src/Humanizer.SourceGenerators/Generators/ProfileCatalogs/*.cs
    • emit typed profile catalogs for the supported surfaces
  4. src/Humanizer.SourceGenerators/Generators/LocaleRegistryInput.cs
    • emits the locale-to-implementation registry wiring
  5. src/Humanizer/Localisation/*
    • shared runtime kernels

Regional Variant Checklist

Before creating a new regional variant file:

  1. Do not use plain culture fallback as parity proof for a shipped locale.
  2. If the variant has no locale-owned generated overrides, do not create a YAML file.
  3. If the variant differs only in a few fields inside a feature block, declare variantOf and override only those fields.
  4. If the variant needs a different engine, replace the whole mapping intentionally.
  5. For parity work, inherited surfaces still need locale-specific proving assertions and a recorded inheritance chain to the terminal owner.

A locale parity claim is invalid unless every canonical surface is explicitly accounted for as locale-owned or same-language inherited with proof. There is no shipped-locale exemption list in this repo.

Exception for no-delta regional variants: A parity epic may ship minimum-valid no-delta variant files (locale: + variantOf:) when first-class matrix/sweep coverage is required. This makes the regional culture explicit in LocaleRegistrySweepTests and LocaleTheoryMatrixCompletenessTests rather than relying on implicit culture fallback. The no-delta file inherits all surfaces from the parent and produces identical output; its purpose is registry presence and test matrix coverage, not linguistic differentiation. The surfaces key may be omitted entirely for these files. Examples: ur-PK.yml and ur-IN.yml ship as no-delta variants of ur.yml.

Examples in the current repo:

  • en-US.yml exists because U.S. ordinal date formatting differs from en.
  • ru-RU.yml does not need to exist when ru already covers the generated behavior.
  • en-IN.yml declares variantOf: 'en' and overrides only the number.words fields that genuinely differ.

Pitfall

Do not invent fields, use empty mappings as inheritance sentinels, copy a parent file into every variant, or reference generator-internal profile keys. Changing engine replaces that mapped block instead of merging it.

The reference describes accepted structure; it does not prove that authored words or inherited behavior are natural for a culture.

Version notes

This schema documents the canonical main/preview locale YAML compiler. Published releases through 3.0.10 use their own checked-in localization and package shapes. Do not backport a field merely because it appears here.