Humanizr/Humanizer · error · InvalidOperationException
Locale '{localeCode}' must author durationCases instead of i
Error message
Locale '{localeCode}' must author durationCases instead of inheriting them from language or script-incompatible locale '{inheritedLocaleCode}'. What it means
durationCases encode language- and script-specific duration grammar forms that do not transfer across language boundaries. The generator refuses to silently inherit durationCases from an ancestor whose language subtag differs or whose script is incompatible, forcing the locale author to explicitly author correct forms for their language.
Source
Thrown at src/Humanizer.SourceGenerators/Common/LocaleYamlCatalog.cs:632
ImmutableDictionary<string, SimpleYamlValue> inheritedFeatures)
{
_ = features.TryGetValue(featureName, out var localValue);
_ = inheritedFeatures.TryGetValue(featureName, out var inheritedValue);
if (featureName == "inflection" &&
inheritedLocaleCode is not null &&
!SharesExactLanguageSubtag(localeCode, inheritedLocaleCode))
{
inheritedValue = null;
}
if (featureName == "durationCases" &&
localValue is null &&
inheritedValue is not null &&
inheritedLocaleCode is not null &&
(!SharesExactLanguageSubtag(localeCode, inheritedLocaleCode) ||
!HasCompatibleScript(localeCode, inheritedLocaleCode)))
{
throw new InvalidOperationException(
$"Locale '{localeCode}' must author durationCases instead of inheriting them from language or script-incompatible locale '{inheritedLocaleCode}'.");
}
return MergeFeatureValue(localeCode, featureName, inheritedValue, localValue);
}
static bool SharesExactLanguageSubtag(string localeCode, string inheritedLocaleCode) =>
string.Equals(
GetExactLanguageSubtag(localeCode),
GetExactLanguageSubtag(inheritedLocaleCode),
StringComparison.OrdinalIgnoreCase);
static string GetExactLanguageSubtag(string localeCode)
{
var separatorIndex = localeCode.IndexOf('-');
return separatorIndex >= 0
? localeCode.Substring(0, separatorIndex)
: localeCode;View on GitHub (pinned to ffc2b77c0f)
Solutions
- Author a 'durationCases:' block directly in the locale's own YAML file, duplicating from a same-language locale and adapting the forms.
- Change the 'inherits:' target to a locale sharing the same language subtag and a compatible script.
- If the locale genuinely shares the language, verify the script subtags match (both absent, or both identical, or both Han).
Example fix
# before — de-CH.yml inherits: fr # (no durationCases block) # after — de-CH.yml inherits: de durationCases: # ... German-specific forms authored here
Defensive patterns
Strategy: validation
Validate before calling
# Before building, verify every locale either authors durationCases locally
# or inherits from a same-language, script-compatible parent.
import pathlib, re
def lang_subtag(code):
return code.split('-')[0].lower()
def script_subtag(code):
parts = code.split('-')
return parts[1] if len(parts) > 1 and len(parts[1]) == 4 else None
locales_dir = pathlib.Path('src/Humanizer/Locales')
for f in locales_dir.rglob('*.yml'):
text = f.read_text()
code = f.stem
has_local = 'durationCases:' in text
m = re.search(r'^inherits:\s*(\S+)', text, re.MULTILINE)
parent = m.group(1) if m else None
if not has_local and parent:
if lang_subtag(code) != lang_subtag(parent):
print(f'{code}: must author durationCases (different language from {parent})')
elif script_subtag(code) and script_subtag(parent) and script_subtag(code) != script_subtag(parent):
print(f'{code}: must author durationCases (incompatible script with {parent})') Prevention
- When creating a locale that inherits across a language boundary, always author durationCases explicitly.
- Keep a reference locale with the same language nearby to copy duration grammar from.
- Add a CI lint that flags durationCases inheritance across differing language subtags.
When it happens
Trigger: A locale omits a local 'durationCases:' block AND its resolved ancestor has a different exact language subtag (e.g. 'de-CH' inheriting from 'fr') or an incompatible script subtag (e.g. 'zh-Hant' inheriting from 'zh-Hans').
Common situations: Creating a regional variant that inherits from a base locale of a different language; duplicating a locale file and changing only the 'inherits:' target without re-authoring duration grammar; merging locale data from an unrelated language family.
Related errors
- Phrase '{path}' must define forms.
- Phrase '{path}' must define 'numeric', 'text', or 'words'.
- Phrase '{path}' must define a scalar string or an explicit '
- Locale '{localeCode}' is not defined.
- Locale inheritance cycle detected at '{localeCode}'.
AI-assisted analysis of Humanizr/Humanizer@ffc2b77c0f (2026-08-13).
Data as JSON: /api/errors/4d380634261d5c11.
Report an issue: GitHub.