Stop a language change undoing itself, and stop the translate prompt
Two reports, both about the language setting. **Picking a language sometimes took several clicks.** The subtree that reads the account's settings file is keyed on the language version, so choosing a language deliberately throws it away and builds it again. The remount re-read the settings file — which still held the old language, because the write is debounced by three seconds — and applied it, putting the old language back. The click that appeared to work was the one made after the previous write had landed, which is exactly the "sometimes" in the report. Worse than it looked: the queued push survived the remount, so the file was eventually written with the new language while the screen showed the old one. A reload then changed the language on its own. Fixed twice over, because either alone leaves a race. The file is read once per account per page load rather than once per mount, and hydrate now holds back any key with a change still queued — a change that has not been written up is newer than the file by definition. That rule is `mergeRemote`, pulled out as a pure function so it could be tested without a JMAP client. **Both browsers kept offering to translate an English page.** They were right to: `<html lang>` said English while the visible text was 6,289 message rows of marketing copy and brand names in whatever language the sender wrote in. The list is most of the text on the screen, so that is what the detector was reading. Sender, subject and preview in the list, and the thread subject and sender name in the reader, are now marked as what they are — content, not interface. Message bodies were already marked, so this is the same line drawn in the places the earlier pass missed rather than a new one. Whether it silences the prompt is Chrome's call and cannot be checked from inside the page; the marking is right either way.
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { create } from "zustand";
|
||||
import { loadJson, saveJson } from "@/lib/storage";
|
||||
import { queueSettingsPush } from "@/lib/settingsSync";
|
||||
import { pendingSettingsKeys, queueSettingsPush } from "@/lib/settingsSync";
|
||||
import { setDateTimePrefs, setUiLanguageForFormatting, type DateFormat, type TimeFormat } from "@/lib/datetime";
|
||||
import type { SwipeAction } from "@/lib/swipe";
|
||||
import { resolveUiLanguage } from "@/lib/languages";
|
||||
@@ -280,6 +280,26 @@ export function acceptRemote(remote: Record<string, unknown>): Partial<Settings>
|
||||
return out as Partial<Settings>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The settings file laid over the ones in hand, minus anything still queued.
|
||||
*
|
||||
* A change that has not been written up yet is newer than the file by
|
||||
* definition, so it wins. Picking a language is where this showed: that
|
||||
* remounts the tree, the remount re-reads the file, and the file still holds
|
||||
* the language from before the click, so the click came undone. Reported as
|
||||
* "sometimes it takes several clicks" — the click that stuck was the one made
|
||||
* after the previous write had landed.
|
||||
*/
|
||||
export function mergeRemote(
|
||||
current: Settings,
|
||||
remote: Record<string, unknown>,
|
||||
held: ReadonlySet<string> = new Set(),
|
||||
): Settings {
|
||||
const incoming = acceptRemote(remote);
|
||||
for (const key of held) delete incoming[key as keyof Settings];
|
||||
return { ...current, ...incoming };
|
||||
}
|
||||
|
||||
interface SettingsState {
|
||||
settings: Settings;
|
||||
update(patch: Partial<Settings>): void;
|
||||
@@ -333,7 +353,7 @@ export const useSettings = create<SettingsState>((set, get) => ({
|
||||
}
|
||||
},
|
||||
hydrate(remote) {
|
||||
const settings = { ...get().settings, ...acceptRemote(remote) };
|
||||
const settings = mergeRemote(get().settings, remote, pendingSettingsKeys());
|
||||
// Cache it, so the next first frame on this browser is already right.
|
||||
saveJson("settings", settings);
|
||||
set({ settings });
|
||||
|
||||
Reference in New Issue
Block a user