{"record":{"id":"1782a9a42a4cb6d2","repo":"Humanizr/Humanizer","slug":"billion-word-cardinal-strategy-requires-a-plural-b","errorCode":null,"errorMessage":"Billion-word cardinal strategy requires a plural billion word.","messagePattern":"Billion-word cardinal strategy requires a plural billion word\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/GenerationHelpers.cs","lineNumber":738,"sourceCode":"            first = false;\n        }\n\n        builder.Append(\" }\");\n        return builder.ToString();\n    }\n\n    static string CreateLegacyBillionStrategyCardinalScaleArrayExpression(JsonElement cardinalElement)\n    {\n        var millionScale = $\"new(1000000UL, {QuoteLiteral(GetRequiredString(cardinalElement, \"millionSingularWord\"))}, {QuoteLiteral(GetRequiredString(cardinalElement, \"millionPluralWord\"))})\";\n        if (GetRequiredString(cardinalElement, \"billionStrategy\") != \"billion-word\")\n        {\n            return $\"new BillionStrategyCardinalScale[] {{ {millionScale} }}\";\n        }\n\n        var billionSingular = GetOptionalString(cardinalElement, \"billionSingularWord\")\n            ?? throw new InvalidOperationException(\"Billion-word cardinal strategy requires a singular billion word.\");\n        var billionPlural = GetOptionalString(cardinalElement, \"billionPluralWord\")\n            ?? throw new InvalidOperationException(\"Billion-word cardinal strategy requires a plural billion word.\");\n        return $\"new BillionStrategyCardinalScale[] {{ new(1000000000UL, {QuoteLiteral(billionSingular)}, {QuoteLiteral(billionPlural)}), {millionScale} }}\";\n    }\n\n    static string CreateContractedOneScaleArrayExpression(JsonElement arrayElement)\n    {\n        if (arrayElement.ValueKind != JsonValueKind.Array)\n        {\n            throw new InvalidOperationException(\"Expected JSON array.\");\n        }\n\n        var builder = new StringBuilder(\"new ContractedOneScaleNumberToWordsConverter.Scale[] { \");\n        var first = true;\n\n        foreach (var item in arrayElement.EnumerateArray())\n        {\n            if (item.ValueKind != JsonValueKind.Object)\n            {\n                continue;","sourceCodeStart":720,"sourceCodeEnd":756,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/GenerationHelpers.cs#L720-L756","documentation":"Thrown when a locale's cardinal scale declares billionStrategy: 'billion-word' but omits the billionPluralWord property. The BillionStrategyCardinalScale row needs both singular and plural billion terms to pluralize counts of billions; the generator refuses to emit an incomplete row. It is the sibling check to the singular-billion-word error.","triggerScenarios":"A locale YAML sets numberToWords cardinal.billionStrategy to 'billion-word' and provides billionSingularWord but not billionPluralWord. The throw happens immediately after the singular-word null-coalesce in CreateLegacyBillionStrategyCardinalScaleArrayExpression.","commonSituations":"A contributor adds the singular billion word while editing but forgets the plural, or copies a locale where the two keys diverge in naming. Surfaces as a CS8785 generator failure at build time, often right after the singular-word check is satisfied.","solutions":["Add the 'billionPluralWord' key alongside billionSingularWord under numberToWords cardinal (e.g. billionPluralWord: 'billions').","If the locale does not distinguish singular/plural billion forms, set billionStrategy to a non-'billion-word' value so neither key is required.","Mirror the exact key set from a working billion-word locale such as en.yml."],"exampleFix":"# before\ncardinal:\n  billionStrategy: 'billion-word'\n  billionSingularWord: 'un milliard'\n# after\ncardinal:\n  billionStrategy: 'billion-word'\n  billionSingularWord: 'un milliard'\n  billionPluralWord: 'milliards'","handlingStrategy":"validation","validationCode":"# Ensure the plural billion word accompanies the singular one:\n#   rg \"billionSingularWord\" src/Humanizer/Locales/<code>.yml\n#   rg \"billionPluralWord\"  src/Humanizer/Locales/<code>.yml\n# Both must return a match within the cardinal block when billionStrategy is 'billion-word'.","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add billionSingularWord and billionPluralWord as a pair; never one without the other.","If the locale does not pluralize billions, choose a non-'billion-word' strategy instead.","Run 'dotnet build' after editing cardinal scales to catch missing plural words early."],"tags":["source-generator","locale-yaml","configuration","build-time","cardinal-scale","humanizer"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}