Skip to content

Compose chart axis labels with the locale, not with string glue - #77

Open
myml wants to merge 1 commit into
oddbit:mainfrom
myml:fix/chart-axis-locale
Open

myml wants to merge 1 commit into
oddbit:mainfrom
myml:fix/chart-axis-locale

Conversation

@myml

@myml myml commented Oct 14, 2026

Copy link
Copy Markdown

What

The chart's x-axis built its label by gluing a translated month name onto a day number, which hardcodes a month-first order and a space separator:

return monthName(parseInt(parts[1], 10)) + ' ' + parseInt(parts[2], 10);

That composition is wrong in three ways. A lang=zh viewer read 7月 16 for a day bucket where zh wants 7月16日, and 7月 26 for a monthly bucket, which reads as the 26th of July rather than July 2026. Swedish and Indonesian order the day first (16 juli, 16 Jul), and got the month first. The month branch also took the year from parts[0].slice(2), so the same label was ambiguous in every locale.

fmtLabel now builds a UTC Date from the bucket label and formats it with Intl.DateTimeFormat, which is the call the tooltip formatter (fmtBucketDate) and the server-side formatBucketLabel already make. The month branch carries a full year: a two-digit year is not an option, because zh ICU renders it 26年7月, which reads as the year 26.

Two consequences worth naming:

  • The shape of the label now picks the branch, not the range, so the range list that had to stay in agreement with the bucketing in click-repository.ts is gone. A weekly bucket label (YYYY-MM-DD) is handled the same as a daily one, which the 1y and long all ranges emit.
  • MONTH_KEYS and monthName are deleted: nothing else read them. The month.* translation keys stay in the locale tables for now. The client no longer reads them, but they cannot be dropped one locale at a time, because src/i18n.test.ts compares each locale's key set against en, and the zh locale is in flight in Add Simplified Chinese to the admin dashboard #71. A follow-up can drop all of them together once that lands.

English monthly axis labels grow by two characters (Jul 26 becomes Jul 2026). Daily labels are unchanged in English (Jul 16).

Tests

New src/__tests__/unit/client-chart-labels.test.ts cuts the shipped function out of adminClientScript() output and runs it per language, the way the other client.ts tests do. The chunk is evaluated with no t() in scope, so a return to the glue throws instead of rendering a wrong label. Assertions name the components that carry meaning (month, day, year) and their order rather than the whole string, following formatBucketLabel in big-chart.test.ts. Mutating the year option to 2-digit, or dropping the day option, fails the suite.

  • yarn test: 103 files, 1604 tests pass.
  • yarn e2e: 32 tests pass.
  • yarn tsc --noEmit: clean.

Context

Raised in the review of #71, which adds Simplified Chinese to the admin. The axis-label defect is independent of that locale: it is the composition that is wrong, and zh is the locale that makes it visible.

The x-axis composed its label by gluing a translated month name onto a day
number, which hardcodes a Latin month-first shape and a space separator. A
lang=zh viewer read "7月 16" for a day bucket, where zh wants 7月16日, and
"7月 26" for a monthly bucket, which reads as the 26th of July rather than
July 2026. The same glue put the month first for sv and id, whose locales
order the day first ("16 juli", "16 Jul").

fmtLabel now builds a UTC Date from the bucket label and formats it with
Intl.DateTimeFormat, the call the tooltip formatter (fmtBucketDate) and the
server-side formatBucketLabel already make. The month branch carries a full
year: a two-digit year is not an option, because zh ICU renders it
"26年7月", which reads as the year 26.

The shape of the label now picks the branch, not the range, which drops the
range list that had to agree with the bucketing in click-repository.ts. The
month.* translation keys are left in place: the client no longer reads them,
but zh.ts is in flight in another change, and dropping keys from one locale
table at a time fails the key-parity test.

New client-chart-labels.test.ts extracts the shipped function from
adminClientScript() output and runs it per language. The chunk is evaluated
with no t() in scope, so a return to the glue throws instead of rendering a
wrong label. Mutating the year option or dropping the day option fails the
suite.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant