{"record":{"id":"4230994941e04a68","repo":"Humanizr/Humanizer","slug":"phrase-path-can-only-use-placeholders-in-expli","errorCode":null,"errorMessage":"Phrase '{path}' can only use placeholders in explicit 'template' entries.","messagePattern":"Phrase '(.+?)' can only use placeholders in explicit 'template' entries\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs","lineNumber":529,"sourceCode":"        static string ValidateLiteralText(string path, string text, params string[] allowedPlaceholders)\n        {\n            foreach (var placeholder in GetPlaceholderNames(text))\n            {\n                if (int.TryParse(placeholder, out _))\n                {\n                    throw new InvalidOperationException($\"Phrase '{path}' cannot use numeric placeholder '{{{placeholder}}}'.\");\n                }\n\n                if (placeholder.Length == 0 || !char.IsLetter(placeholder[0]) || placeholder.Any(static c => !char.IsLetterOrDigit(c) && c != '_'))\n                {\n                    throw new InvalidOperationException($\"Phrase '{path}' uses unsupported placeholder '{{{placeholder}}}'.\");\n                }\n\n                if (!allowedPlaceholders.Contains(placeholder, StringComparer.Ordinal))\n                {\n                    throw new InvalidOperationException(\n                        allowedPlaceholders.Length == 0\n                            ? $\"Phrase '{path}' can only use placeholders in explicit 'template' entries.\"\n                            : $\"Phrase '{path}' can only use placeholders: {string.Join(\", \", allowedPlaceholders.Select(static value => $\"{{{value}}}\"))}.\");\n                }\n            }\n\n            return text;\n        }\n\n        static IEnumerable<string> GetPlaceholderNames(string text) =>\n            PlaceholderRegex.Matches(text)\n                .Cast<Match>()\n                .Select(static match => match.Groups[\"name\"].Value);\n\n        static SimpleYamlMapping ExpectMapping(SimpleYamlValue value, string path) =>\n            value as SimpleYamlMapping ??\n            throw new InvalidOperationException($\"Phrase section '{path}' must be a mapping.\");\n\n        static void RejectUnknownKeys(SimpleYamlMapping mapping, string path, params string[] allowedKeys)\n        {","sourceCodeStart":511,"sourceCodeEnd":547,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/LocalePhraseNormalization.cs#L511-L547","documentation":"Thrown by ValidateLiteralText when a literal phrase string contains any placeholder but the field allows none (allowedPlaceholders is empty). Many literal fields (e.g. data-unit symbol, relativeDate now) are pure text and cannot interpolate; formatting belongs in an explicit 'template' entry. Surfaced as compiler diagnostic HSG003 (severity Error).","triggerScenarios":"Writing 'symbol: {count} B' or 'now: {value}' on a surface whose literals take no placeholders.","commonSituations":"Author assumes all fields accept {count}; migrating from a format-string-based resource; copy-paste of a templated value into a literal slot.","solutions":["Remove the placeholder from the literal so it is plain text.","If interpolation is required, add an explicit 'template' entry to that phrase (templates permit the surface's allowed placeholders).","Rebuild to confirm the diagnostic clears."],"exampleFix":"# before\ndataUnits:\n  byte:\n    symbol: '{count} B'\n# after\ndataUnits:\n  byte:\n    symbol: B\n    template:\n      value: '{count} {unit}'","handlingStrategy":"validation","validationCode":"# Surfaces whose literals allow NO placeholders include data-unit 'symbol',\n# relativeDate now/today/never, and duration 'zero'. Find any {placeholder} there.\ngrep -nE '(symbol|now|today|never|zero):.*\\{[^}]+\\}' src/Humanizer/Locales/<code>.yml","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat symbol/now/today/never/zero as static text.","Move interpolation into an explicit 'template' entry on that phrase.","Build after restructuring."],"tags":["humanizer","source-generator","locale","yaml","localization","phrases","placeholder","literal","template"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}