month_names |
:abbreviated |
101 |
ar-DZ, ar-MA, ar-TN, en-001, en-150, en-AG, en-AI, en-AT, en-BB, en-BE, en-BM, en-BS, en-BW, en-BZ, en-CA, en-CC, en-CH, en-CK, en-CM, en-CX, en-CY, en-DE, en-DG, en-DK, en-DM, en-ER, en-FI, en-FJ, en-FK, en-FM, en-GD, en-GG, en-GH, en-GI, en-GM, en-GY, en-HK, en-IE, en-IL, en-IM, en-IN, en-IO, en-JE, en-JM, en-KE, en-KI, en-KN, en-KY, en-LC, en-LR, en-LS, en-MG, en-MO, en-MS, en-MT, en-MU, en-MV, en-MW, en-MY, en-NA, en-NF, en-NG, en-NL, en-NR, en-NU, en-NZ, en-PG, en-PK, en-PN, en-PW, en-RW, en-SB, en-SC, en-SD, en-SE, en-SG, en-SH, en-SI, en-SL, en-SS, en-SX, en-SZ, en-TC, en-TK, en-TO, en-TT, en-TV, en-TZ, en-UG, en-VC, en-VG, en-VU, en-WS, en-ZA, en-ZM, en-ZW, hi-Latn, hi-Latn-IN, se-FI, sr-Latn-ME, sr-Latn-XK |
Summary
Worldwide::Calendar::Gregorian.month_namesand.weekday_namesreturn partial results for 104 locales, includingen-CA,en-GB,en-IN,en-AU,en-NZ,en-ZAand every otheren-001descendant.Reproduced on
worldwide1.26.2 (currentmain,ad6eeefb),i18n1.15.2, Ruby 3.4.8.Cause
CLDR resolves locale data item by item: the effective data for a locale is the union of its own data with each of its ancestors', with the more specific locale winning per item (UTS #35 §4.1). Locale files in
data/cldr/locales/are stored as deltas accordingly —data/cldr/locales/en-CA/calendars.ymlcontains exactly:I18n::Backend::Fallbacks#translatereturns the first non-nil node it finds in the fallback chain. That is correct for leaves (months.stand_alone.abbreviated.1still resolves to"Jan"fromen) but wrong for a whole node:months.stand_alone.abbreviatedmatchesen-CA's one-entry hash and the eleven inherited entries never get merged in.month_namesthen calls.valueson that hash, so the truncation is silent —lib/worldwide/calendar/gregorian.rb#L20.Affected locales
805 known locales × 2 methods × 3 widths = 4830 combinations; 108 of them are wrong, spanning 104 distinct locales.
month_names:abbreviatedar-DZ,ar-MA,ar-TN,en-001,en-150,en-AG,en-AI,en-AT,en-BB,en-BE,en-BM,en-BS,en-BW,en-BZ,en-CA,en-CC,en-CH,en-CK,en-CM,en-CX,en-CY,en-DE,en-DG,en-DK,en-DM,en-ER,en-FI,en-FJ,en-FK,en-FM,en-GD,en-GG,en-GH,en-GI,en-GM,en-GY,en-HK,en-IE,en-IL,en-IM,en-IN,en-IO,en-JE,en-JM,en-KE,en-KI,en-KN,en-KY,en-LC,en-LR,en-LS,en-MG,en-MO,en-MS,en-MT,en-MU,en-MV,en-MW,en-MY,en-NA,en-NF,en-NG,en-NL,en-NR,en-NU,en-NZ,en-PG,en-PK,en-PN,en-PW,en-RW,en-SB,en-SC,en-SD,en-SE,en-SG,en-SH,en-SI,en-SL,en-SS,en-SX,en-SZ,en-TC,en-TK,en-TO,en-TT,en-TV,en-TZ,en-UG,en-VC,en-VG,en-VU,en-WS,en-ZA,en-ZM,en-ZW,hi-Latn,hi-Latn-IN,se-FI,sr-Latn-ME,sr-Latn-XKmonth_names:narrowar-DZ,ar-MA,ar-TNmonth_names:widear-DZ,ar-MA,ar-TNweekday_names:widese-FIWorst cases return a single entry:
hi-Latnandse-FIreturn 1 of 12 abbreviated month names;sr-Latn-MEandsr-Latn-XKreturn 5 of 12.en-GBand friends return 1 of 12.Secondary issue: missing structural keys degrade into a plausible string
Worldwide::I18nExceptionHandler#degraded_translation(lib/worldwide/i18n_exception_handler.rb#L51-L57) turns any unresolved key into a humanized copy of its last segment. For a structural lookup that means a missing weekday table comes back as the string"wide"rather than raising:That is a reasonable default for leaf strings in a UI, but for a hash-valued CLDR node it converts a data gap into a plausible-looking value, and
month_namesthen fails withNoMethodError: undefined method 'values' for an instance of Stringsome distance from the cause. (This is how the same call sites failed on worldwide < 1.25.6, before the fiber-storage fix in 76762d1 restored the CLDR fallback chain on Ruby 3.2+.)Proposed fix
Resolve structural CLDR keys with CLDR's inheritance rules — walk the fallback chain from the least specific ancestor to the most specific, deep-merging each locale's own contribution, and resolve
<alias>nodes against the requested locale rather than the ancestor they were found in. Then haveweekday_names/month_namesraise if an entry is still missing rather than returning degraded data.PR: #NNN