Sanitize malformed locale tags in navigator.languages
What does this MR do and why?
navigator.languages is supposed to contain BCP 47 language tags, but some environments inject malformed tags. When one of these reaches Intl.DateTimeFormat (via the globally-loaded time-ago tooltip and other locale/datetime consumers), it throws RangeError: Invalid language tag and the tooltip fails to render.
A previous fix (commit 7bea1ce39d46) stripped HTTP Accept-Language quality values (e.g. en;q=0.9), but Sentry shows the same RangeError continuing with a sibling variant — POSIX locale modifiers such as en-US@posix — which that fix did not cover.
This MR makes getPreferredLocales() (app/assets/javascripts/locale/index.js) robust against any malformed tag, not just the known variants:
- Salvage the
language[-territory]part of each entry: strip HTTP quality values (;q=0.9), POSIX modifiers (@posix), codeset suffixes (.UTF-8), and stray commas, and convert_separators to-. A raw POSIX locale likeen_US.UTF-8@posixbecomesen-US, keeping the user's locale preference instead of discarding it. - Validate each candidate with
Intl.getCanonicalLocales()inside atry/catchand drop any entry that still is not a valid BCP 47 tag (e.g.C).
Because invalid entries are filtered out rather than passed through, Intl APIs always receive valid locales and any future malformed variant is handled too.
References
- Fixes https://gitlab.com/gitlab-org/gitlab/-/work_items/625056
- Sentry triage comment: https://gitlab.com/gitlab-org/gitlab/-/work_items/625056#note_3865334873
- Related prior fix: commit
7bea1ce39d46
Screenshots or screen recordings
No UI change — this only prevents a RangeError from being thrown; date/time rendering is unchanged for valid locales.
| Before | After |
|---|---|
Intl.DateTimeFormat throws RangeError for malformed navigator.languages entries |
Malformed entries are salvaged to valid BCP 47 tags where possible, otherwise dropped; dates render with a valid locale |
How to set up and validate locally
- Run the locale specs:
yarn jest spec/frontend/locale/index_spec.js - Or verify the core behavior in Node:
node -e "try { new Intl.DateTimeFormat('en_US.UTF-8@posix'); } catch (e) { console.log('throws:', e.message); } console.log('salvaged:', Intl.getCanonicalLocales('en_US.UTF-8@posix'.split(/[;@.,]/)[0].replace(/_/g, '-')));"en_US.UTF-8@posixthrows, while the salvageden-USis valid.
MR acceptance checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.