cb754a0319
A first visit resolved to Chinese regardless of the browser: LocaleService read `dsh.locale` and fell straight back to `zh` when nothing was stored, ignoring the languages the browser already states it reads. The initial locale now resolves through three ordered sources — the persisted preference, then `navigator` (first entry of the ordered language list whose primary subtag names a shipped locale, so `zh-Hans-CN` -> zh and `en-GB` -> en), then `FALLBACK_LOCALE`. An explicit choice still wins and nothing writes the detected locale back to storage, so "has the user chosen?" stays a question only the stored value answers. Specs asserting the shipped Chinese copy now state the browser they assume: the web e2e scenarios open their page with `locale: ZH_BROWSER_LOCALE`, and package specs pin it through the new `pinBrowserLanguages` test helper. `settings-chrome.e2e.ts` gains an English-browser scenario as the assembled-app proof.
26 lines
1.2 KiB
TypeScript
26 lines
1.2 KiB
TypeScript
/**
|
|
* Browser-language pin for specs that assert localized copy. A fresh
|
|
* LocaleService with no stored preference opens in the language `navigator`
|
|
* asks for, and jsdom reports the runner's own (`en-US`) — so a spec asserting
|
|
* the product's Chinese copy states the browser it assumes instead of
|
|
* inheriting the machine's.
|
|
*/
|
|
|
|
/**
|
|
* Override `navigator.languages`/`navigator.language` for the current spec.
|
|
* @param primary - most preferred BCP 47 tag; also becomes `navigator.language`.
|
|
* @param rest - further tags in preference order.
|
|
* @returns restore function handing the properties back to the environment.
|
|
*/
|
|
export function pinBrowserLanguages(primary: string, ...rest: string[]): () => void {
|
|
Object.defineProperty(navigator, 'languages', { value: [primary, ...rest], configurable: true })
|
|
Object.defineProperty(navigator, 'language', { value: primary, configurable: true })
|
|
return () => {
|
|
// Deleting the own properties uncovers the environment's own accessors
|
|
// again (Navigator declares both readonly, hence the erased receiver).
|
|
const own = navigator as unknown as Record<string, unknown>
|
|
delete own.languages
|
|
delete own.language
|
|
}
|
|
}
|