Repository navigation
fix(console): a language picked on the sign-in page formats the date cells, not the browser's language (#27625) - #27680
Merged
Conversation
…27625) LocalizationFetchProvider reads /auth/me/localization through sharedGetJson's bare fetch, so it never carried the <html lang> Accept-Language every other console API call carries. A user with no sys_user.locale who picked a language on the sign-in page got the Accept-Language rung answered in the browser's language, and date cells formatted in it on every load. When the device holds an explicit language choice the read now states it, and re-reads when it changes. Claude-Session: https://claude.ai/code/session_01Utp6CXAd1Uo5DCp8mUzmWj Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Utp6CXAd1Uo5DCp8mUzmWj Co-authored-by: Claude <noreply@anthropic.com>
#27625) Claude-Session: https://claude.ai/code/session_01Utp6CXAd1Uo5DCp8mUzmWj Co-authored-by: Claude <noreply@anthropic.com>
Contributor
Author
|
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC 席位核对ACCEPT · head
Generated by Claude Code |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
domain:ui#2 · os-bill · session_01Utp6CY2n1JmZZKrHgtp9jC
Requested by Bill · project thread
Fixes #27625
Clause-②: no
Metadata-protocol: none
维护者速读
/auth/me/localization时,若本设备有明确的语言选择(如登录页选了中文),请求的Accept-Language就写这门语言;选择变了就重读一次。服务器档位顺序与useDisplayLocale的优先级都没动。fetch,没有像其它 console 请求那样带上界面语言,于是没存语言的用户在登录页选了中文后,服务器按浏览器的en-US作答,表格日期每次加载都是Nov 18。ui/apps/console/src/LocalizationFetchProvider.tsx(statedLanguage一行与 headers 里的Accept-Language);LocalizationFetchProvider.test.tsx新的 describe 块。pnpm --dir ui exec vitest run apps/console/src/LocalizationFetchProvider.test.tsx,预期 22 个测试全绿,其中 4 个在states the device's chosen language块下。What changes
LocalizationFetchProvider(console) now states the device's chosen UI language as theAccept-Languageof itsGET /api/v1/auth/me/localizationread whenever the device holds an explicit language choice (readStoredLanguage(), the slot the sign-in page's globe and the avatar menu both write), and reads again when that language changes. With no choice on the device, nothing is stated and the browser's own header goes out, as before.Cause, measured on a running stack (step 1 of the order). On
examples/app-showcase, admin withsys_user.localeunset, a browser context inen-US:langattribute after the sign-in page pick of 中文zhzhzhzhAccept-Languageon the localization read (grid load, reload)en-USzh{authenticated:true, locale:"en-US", currency:null, timezone:"UTC"}{… locale:"zh" …}Oct 11, Nov 18, Nov 1, Nov 1010月11日, 11月18日, 11月1日, 11月10日So the pick already reached the html
langattribute; the read never stated it. Every other console API call goes throughcreateAuthenticatedFetch, which stamps that attribute asAccept-Language; this provider reads throughsharedGetJson's barefetch, so it carried the browser's header, the server answered itsAccept-Languagerung in English, anduseDisplayLocaleformatted with that answer.Within the ruling (triage 6501838569). No server file, no new key, no new server field; the server's rung order and
useDisplayLocale's precedence are untouched. The triage's diagnosis "the read the console makes … does not state the active UI language" is what this changes. Two assumptions of the order were falsified by the measurement and named here: the triage line "The console'sAccept-Languagealready follows" the htmllangattribute does not hold for this one read, and the sign-in pick does reach that attribute (solanguageSeed.tsand the module holding the pick,@object-ui/app-shell'sLocaleSwitcherthroughuseLanguageSelection, signed out a barechangeLanguage, are unchanged). The seat agreed the route before the fix.Why gate the header on an explicit choice. Without one, the boot is exactly the one on which
seedTenantLanguage()asks the same endpoint with no header, and the two share one request only while their headers match (sharedGetJsonkeys on them; objectui#5544). Stating a language there would split them into two requests on every first visit. Without a choice the UI language came from that seed or the browser, so the browser's header is the right signal on those boots.Re-read on a change.
statedLanguageis an effect dependency, so a change of the chosen language reads again. That read cannot join a request still in flight under the old language: the in-flight key includes the headers. The #27498 re-read after a write to the user's ownsys_userrow, and its in-flight opt-out, are unchanged.Tests
New
describeblockstates the device's chosen language (objectstack#27625)inui/apps/console/src/LocalizationFetchProvider.test.tsx, under a realI18nProvider, probinguseDisplayLocale()plusformatDate('2026-10-11', undefined, { locale, alwaysShowYear: true }):a language picked before sign-in is the one the read states, and the dates follow it: explicit-choice slotzh, no column; the request stateszh, the probe showszh|2026年10月11日, one request.with no choice on this device, the read states nothing and the browser's header goes out.a change of the chosen language reads again, stating the new one:enthenchangeLanguage('zh'); two requests statingenthenzh, the probe follows.a stored sys_user.locale still wins over the stated language: the request stateszh, the server answers its column rungde-DE, and the dates format inde-DE, not Chinese.The #27498 block (
re-reads after a write to the signed-in user's own row, 4 cases) andlocalizationBootDedup.test.tsx(objectui#5544, 3 cases) are unchanged and green.Targeted run and ablation
pnpm --dir ui exec vitest run --reporter=verbose apps/console/src/LocalizationFetchProvider.test.tsx apps/console/src/__tests__/localizationBootDedup.test.tsx apps/console/src/languageSeed.test.ts(head 861694d) →Test Files 3 passed (3),Tests 33 passed (33).scripts/ablation-replace.mjs, fix committed first:const statedLanguage = readStoredLanguage() ? language : undefined;→… readStoredLanguage() && !'ABLATED_27625' ? language : undefined;(anchor 1 → 0, blob 5147c4a0 → a88b06c9). Red: the picked-before-sign-in, change-reads-again and stored-column cases (Tests 3 failed | 19 passed (22)); the no-choice case stays green, as it should. Restored: blob equal to HEAD's,git diff HEADempty.distinvolved: the console suite resolves the provider and@object-ui/*from source.Acceptance notes
Accept-Language): column unset +zh→locale:"zh"; columnja-JP+zh→ja-JP; columnja-JP+en-US→ja-JP; column reset +zh→zh. The column still answers first.sys_user.localeat sign-in (signed out the globe is the bare switch, by design inuseLanguageSelection). Not changed here; with this fix that no longer leaves the dates in the browser's language on this device.Verification
Live reproduction (backend :4625 --fresh, console vite :5625 from ui/apps/console source)
Playwright, browser context
en-US: open/login, footer globe → 中文, sign in as admin through the form, open/apps/showcase_app/showcase_task, wait, read the htmllangattribute, theobjectui-localeslot, every/auth/me/localizationrequest'sAccept-Languageand its answer, and the date lines; then reload and read them again. Before: see the table above (head 144702c). After: the same script on the branch with the fix, the table's right column. The one header-less localization request on/loginbefore the pick isseedTenantLanguage()on a device with no choice yet, answered{authenticated:false}, in both runs.Local gates on head 42e6d4b (after merging origin/main); the farm is CI's
Derived with
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack(3 paths vs merge base b761968). Reconciliation--ran: 33 derived, 33 run, 0 NOT-MEASURED, 0 UNRUN.node scripts/check-sdui-manifest.mjsand its--self-test, the changeset gates,check-closing-keyword-parity.mjs, andpnpm --dir ui exec vitest run scripts/(Test Files 169 passed | 2 skipped (171),Tests 4902 passed | 2 skipped (4904), run with the dev servers stopped).pnpm check:changeset-fixed(its roster lives under.changeset/) → exit 0;pnpm --dir ui exec vitest run apps/console/src/→Test Files 262 passed (262),Tests 2606 passed (2606);pnpm --filter @object-ui/console run type-check→ exit 0 afterpnpm --filter '@object-ui/console^...' build;pnpm exec eslint --no-inline-configon both touched files → exit 0.pnpm lint.Generated by Claude Code