{"record":{"id":"0c0c4c2f555ea745","repo":"Humanizr/Humanizer","slug":"locale-localecode-surfaces-calendar-hijrimonths-0c0c4c","errorCode":null,"errorMessage":"Locale '{localeCode}.surfaces.calendar.hijriMonths' must not contain directionality controls (U+200E, U+200F, U+061C).","messagePattern":"Locale '(.+?)\\.surfaces\\.calendar\\.hijriMonths' must not contain directionality controls \\(U\\+200E, U\\+200F, U\\+061C\\)\\.","errorType":"validation","errorClass":"InvalidOperationException","httpStatus":null,"severity":"critical","filePath":"src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs","lineNumber":512,"sourceCode":"            if (calendarSurface.TryGetValue(\"hijriMonths\", out var hijriMonthsValue))\n            {\n                if (hijriMonthsValue is not SimpleYamlSequence hijriSeq || hijriSeq.Items.Length != 12)\n                {\n                    throw new InvalidOperationException(\n                        $\"Locale '{localeCode}.surfaces.calendar.hijriMonths' must be a sequence of exactly 12 strings.\");\n                }\n\n                foreach (var item in hijriSeq.Items)\n                {\n                    if (item is not SimpleYamlScalar scalar)\n                    {\n                        throw new InvalidOperationException(\n                            $\"Locale '{localeCode}.surfaces.calendar.hijriMonths' items must be scalar strings.\");\n                    }\n\n                    if (scalar.Value.IndexOfAny(['\\u200E', '\\u200F', '\\u061C']) >= 0)\n                    {\n                        throw new InvalidOperationException(\n                            $\"Locale '{localeCode}.surfaces.calendar.hijriMonths' must not contain directionality controls (U+200E, U+200F, U+061C).\");\n                    }\n                }\n            }\n\n            features[\"calendar\"] = calendarSurface;\n        }\n\n        static string NormalizeCanonicalText(string value)\n        {\n            var normalized = value.Replace(\"\\r\\n\", \"\\n\");\n            normalized = normalized.TrimEnd('\\n') + \"\\n\";\n            return normalized;\n        }\n\n        static readonly HashSet<string> ExplicitDefaultEnginePaths =\n        [\n            \"surfaces.ordinal.numeric\",","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/Humanizr/Humanizer/blob/ffc2b77c0f30d2fb176875841424379319d0ae9b/src/Humanizer.SourceGenerators/Common/CanonicalLocaleAuthoring.cs#L494-L530","documentation":"Thrown by AddCalendarFeatures when any Hijri month string contains a Unicode bidirectional-formatting control character: U+200E (LRM), U+200F (RLM), or U+061C (ALM). These invisible marks corrupt mixed-direction rendering and are easy to paste accidentally from RTL sources, so the canonical schema bans them at build time.","triggerScenarios":"A Hijri month string copied from a web page or another locale contains an embedded U+200E/U+200F/U+061C. The IndexOfAny check at CanonicalLocaleAuthoring.cs:509-513 detects the control and fails the build.","commonSituations":"Pasting Arabic month names from browsers/documents that wrap them in LRM/RLM marks; copying from a locale file that previously stored the controls; editors that auto-insert directionality marks in RTL paragraphs.","solutions":["Strip U+200E, U+200F, and U+061C from every hijriMonths entry (e.g. regex replace or an editor that shows invisible characters).","Re-type the affected month names from a trusted plain-text source rather than copy-pasting.","Rebuild to confirm the directionality-control check passes."],"exampleFix":"# before (the string contains an invisible U+200E before 'Muharram')\ncalendar:\n  hijriMonths: [\"\\u200EMuharram\", Safar, ...]\n# after\ncalendar:\n  hijriMonths: [Muharram, Safar, Rabi al-Awwal, Rabi al-Thani, Jumada al-Awwal, Jumada al-Thani, Rajab, Shaban, Ramadan, Shawwal, Dhu al-Qidah, Dhu al-Hijjah]","handlingStrategy":"validation","validationCode":"# Detect directionality controls in hijriMonths before building.\n$controls = [char]0x200E, [char]0x200F, [char]0x061C\n$yaml = Get-Content src/Humanizer/Locales/<code>.yml -Raw\nforeach ($c in $controls) {\n  if ($yaml.Contains($c)) { Write-Error \"Locale contains directionality control U+$('{0:X4}' -f [int]$c)\" }\n}\n# Strip: $yaml = $yaml -replace '[\\u200E\\u200F\\u061C]', ''","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Enable 'show invisible characters' in your editor when editing RTL month names.","Re-type Hijri month names from a trusted plain-text source rather than copy-pasting from browsers.","Run the pre-build control-stripping check above before 'dotnet build'."],"tags":["localization","yaml","source-generator","locale","build","calendar","hijri","unicode","rtl"],"backgroundTag":null,"analyzedSha":"ffc2b77c0f30d2fb176875841424379319d0ae9b","analyzedAt":"2026-08-13T21:42:34.584Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}