MSD: Server-render the interim omnibar in the user's language#109904
MSD: Server-render the interim omnibar in the user's language#109904StevenDufresne wants to merge 2 commits intotrunkfrom
Conversation
Jetpack Cloud Live (direct link)
Automattic for Agencies Live (direct link)
Dashboard Live (dotcom) (direct link)
|
Populate the bootstrapped user's locale data in `defaultI18n` during
the server-side document render, so the masterbar HTML ships with
translated strings for non-English users, and have the client apply
the same data before hydration so the first client render matches.
Eliminates the visible flash of English before the client-side
locale fetch completes.
Changes:
- `client/server/dashboard-i18n.ts` — new Express middleware that
loads the user's locale JSON from `public/languages/` (falling
back to the Calypso CDN) and applies it to `defaultI18n` for the
duration of the request's render. Cached per language.
- `client/server/pages/index.js` — `handleSectionPath` takes an
optional `extraMiddleware` that runs after `setUpRoute`; wires
the new middleware into all dashboard section paths (dotcom,
ciab, start-store).
- `client/dashboard/app/shared-locale-loader.ts` — new module with
`getUserLanguage` (mirrors the server's `setUpLoggedInRoute`
derivation so both sides agree on the effective locale, including
the `use_fallback_for_incomplete_languages` gate) and
`loadUserLocaleData` (a cache-aware pure fetch with no singleton
mutation — callers apply the result themselves).
- `client/dashboard/app/interim-omnibar/index.tsx` — loadOmnibar
fetches the locale in parallel with the auth query and chunk
import, then applies it to `defaultI18n` via `resetLocaleData`
before calling `hydrateRoot`.
- `client/dashboard/app/i18n.tsx` — refactored to use the shared
loader; removes the duplicate `fetchLocaleData` definition.
`I18nProvider`'s `useEffect` now applies `resetLocaleData` inside
a `cancelled`-gated `.then`, so stale completions from a slower
previous request can't override a newer locale.
Requires `wpcom-user-bootstrap: true` for the server to know the
user's locale at render time. Dashboard environments (horizon, stage,
production) have this enabled; local dev does not by default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
e918d9c to
a0cb8f2
Compare
|
This PR modifies the release build for the following Calypso Apps: For info about this notification, see here: PCYsg-OT6-p2
To test WordPress.com changes, run |
Revert the refactor that replaced `I18nProvider`'s internal `fetchLocaleData` helper and `AbortController` with the shared `loadUserLocaleData` and a `cancelled` flag. Keep only the minimum change needed for server/client agreement on the effective locale: have `useLocaleSlug` call `getUserLanguage` from the shared loader so it applies the same `use_fallback_for_incomplete_languages` gate as the server's `setUpLoggedInRoute`. Reasons to go minimal here: - Restores the unmount-time HTTP request cancellation that was added in response to review feedback on #103635. The refactor's `cancelled` flag prevented setState-after-unmount but did not actually abort the in-flight fetch. - Shrinks the branch's `i18n.tsx` diff from ~50 lines to ~7, making review and future history-walking cheaper. - The shared fetch cache (one network request shared between `loadOmnibar` and the main I18nProvider) is a nice-to-have, not load-bearing. Both callers hit the same CDN URL with far-future cache headers, so the worst case is one extra request once per session for non-English users. The partial-locale hydration correctness is preserved via the `getUserLanguage` import — both `loadOmnibar` and `I18nProvider` derive the same slug, matching the server's decision. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| // effective locale. | ||
| const [ { InterimOmnibarContainer }, localeData ] = await Promise.all( [ | ||
| import( './interim-omnibar-container' ), | ||
| loadUserLocaleData( getUserLanguage( window.currentUser ?? null ) ), |
There was a problem hiding this comment.
This is the tradeoff. For non-english, we do wait to download the payload.
| export const loadDashboardLocaleData: RequestHandler = ( req, res, next ) => { | ||
| const language = ( req as CalypsoRequest ).context?.lang; | ||
| if ( ! language || language === 'en' ) { | ||
| defaultI18n.resetLocaleData(); |
There was a problem hiding this comment.
I don't think we can use the global here 🤔 This isn't PHP, node requests don't get their own thread, and setting the global locale could interfere with other requests.
We need some sort of locale provider to make sure each React tree being rendered on the server can have it's own locale data 🤔 Importing __ at the module level means that it will use defaultI18n, but the other way is to do const { __ } = useI18n(); at that means you can provide your own i18n data to each tree.
That's how Calypso's old translate() function worked too. I wonder if I was wrong to migrate the logged in master bar over to core's translation functions 😬 I thought I was making it more compatible but I may have made it worse.
There was a problem hiding this comment.
🤦 I was too busy trying to reign in my dragon, this very important details slipped past. hmmmm.
Part of DOTMSD-1199
Proposed Changes
Why are these changes being made?
The interim omnibar currently renders in English regardless of the user's account language. It's rendered on the server using the default-English `defaultI18n` singleton, then hydrated on the client the same way. Non-English users never see the masterbar in their own language — they see English, and then (if the main dashboard's `I18nProvider` finishes loading before anything else) the strings flip.
This PR gives the omnibar first-class language support: the server knows the user's locale at render time and applies it, the client applies the same locale before hydration, and both sides share one derivation so they can't disagree.
Requirements
Requires `wpcom-user-bootstrap: true` so the server knows the user's locale at render time. Horizon, stage, and production dashboard environments have this enabled; local dev (`dashboard-development.json`) does not by default.
Testing Instructions
To test locally, flip `wpcom-user-bootstrap: true` in `config/dashboard-development.json` and make sure `wpcom_calypso_rest_api_key` is in your secrets.
Pre-merge Checklist