Gregorian#month_names and #weekday_names return partial data for 104 locales (en-CA, en-GB, en-IN, ...)
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 97
- Forks
- 17
- Avg merge
- 13h 33m
- Merged PRs (30d)
- 11
Description
Summary
Worldwide::Calendar::Gregorian.month_names and .weekday_names return partial results for 104 locales, including en-CA, en-GB, en-IN, en-AU, en-NZ, en-ZA and every other en-001 descendant.
Worldwide::Calendar::Gregorian.month_names(locale: "en-CA", width: :abbreviated)
#=> ["Sept"]
# expected: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sept", "Oct", "Nov", "Dec"]
Worldwide::Calendar::Gregorian.weekday_names(locale: "se-FI")
#=> {mon: "mánnodat", tue: "disdat", thu: "duorastat", sat: "lávvordat"}
# expected: all seven, with sun/wed/fri inherited from `se`
Reproduced on worldwide 1.26.2 (current main, ad6eeefb), i18n 1.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.yml contains exactly:
months:
stand_alone:
abbreviated:
9: Sept
I18n::Backend::Fallbacks#translate returns the first non-nil node it finds in the fallback chain. That is correct for leaves (months.stand_alone.abbreviated.1 still resolves to "Jan" from en) but wrong for a whole node: months.stand_alone.abbreviated matches en-CA's one-entry hash and the eleven inherited entries never get merged in.
month_names then calls .values on 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.
| Method | Width | Count | Locales |
|---|---|---|---|
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 |
month_names |
:narrow |
3 | ar-DZ, ar-MA, ar-TN |
month_names |
:wide |
3 | ar-DZ, ar-MA, ar-TN |
weekday_names |
:wide |
1 | se-FI |
Worst cases return a single entry: hi-Latn and se-FI return 1 of 12 abbreviated month names; sr-Latn-ME and sr-Latn-XK return 5 of 12. en-GB and 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:
Worldwide::Cldr.t("calendars.gregorian.days.stand_alone.wide", locale: :some_locale_without_data)
#=> "wide"
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_names then fails with NoMethodError: undefined method 'values' for an instance of String some distance from the cause. (This is how the same call sites failed on worldwide < 1.25.6, before the fiber-storage fix in 76762d19 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 have weekday_names / month_names raise if an entry is still missing rather than returning degraded data.
PR: #NNN
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read lib/worldwide/calendar/gregorian.rb and lib/worldwide/i18n_exception_handler.rb, then reproduce the en-CA and se-FI examples using the current CLDR fallback behavior. Trace I18n::Backend::Fallbacks#translate for structural keys and compare the affected locale data in data/cldr/locales/. Done means inherited entries are present for the listed methods and widths, while missing structural data raises instead of degrading to a string.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- internationalization, localization
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100