Файли
openidea/src/features/settings/runtime.ts
T
Julien Dudek 59567f1af0 feat(i18n): add French (#730)
Adds French as a UI language, with French catalogs for message keys and source text,
and the French space before a colon in settings labels.

UI languages are now registered in one place, `LOCALES` in `src/platform/i18n.ts` (name
in its own language and `<html lang>` tag); the Language and Region options, settings
validation and `<html lang>` all come from it. The catalog tests read every catalog in
`locales/` and `locales/text/`, so a new file is always checked, and literal message keys
given to `t` must exist in `en.json`. Only Chinese must cover every UI string; French and
Korean show English for text they lack.

Also makes two date tests independent of DST changes.

Co-authored-by: J-Dudek <[email protected]>
2026-11-04 11:48:45 +08:00

64 рядки
2.7 KiB
TypeScript

/**
* Applies settings that no other feature owns: keymap preset + overrides,
* the Appearance options (UI font, zoom, compact mode… see
* `appearanceRuntime`) and the document language. (Theme / accent are applied
* by the workbench, editor options by the editor.) Runs on startup and
* whenever `useProject.settings` changes.
*
* Settings written by any window (e.g. the Settings window) reach every window
* through `settingsChanged`, which re-reads the effective settings.
*/
import { LOCALES } from "@/platform/i18n";
import { isTauri, onIdeEvent } from "@/platform/ipc";
import { applyKeymapSettings } from "@/platform/keymap";
import { loadSettings, useProject } from "@/platform/project";
import { applyAppearanceOptions, installAltDragGuard, installIdleSave } from "./appearanceRuntime";
import { validateSettings } from "./model/schema";
export function applyRuntimeSettings(raw: unknown, root: HTMLElement = document.documentElement): void {
const s = validateSettings(raw);
applyKeymapSettings(s.keymap, s.keymapOverrides, s.customKeymaps);
applyAppearanceOptions(s, root);
root.lang = LOCALES[s.appearance.locale].tag;
}
/** Subscribes to settings changes; returns the unsubscribe function. */
export function trackRuntimeSettings(): () => void {
let last: unknown = undefined;
const run = (settings: unknown) => {
if (!settings || settings === last) return;
last = settings;
try {
applyRuntimeSettings(settings);
} catch (e) {
console.error("applying settings failed", e);
}
};
run(useProject.getState().settings);
let cache: { raw: unknown; valid: ReturnType<typeof validateSettings> } | null = null;
const current = () => {
const raw = useProject.getState().settings;
if (cache?.raw !== raw) cache = { raw, valid: validateSettings(raw) };
return cache.valid;
};
let reload: ReturnType<typeof setTimeout> | undefined;
const unsubs = [
useProject.subscribe((s) => run(s.settings)),
// One Apply writes several keys: re-read once.
onIdeEvent("settingsChanged", () => {
clearTimeout(reload);
reload = setTimeout(() => void loadSettings().catch((e) => console.warn("cannot reload settings", e)), 30);
}),
() => clearTimeout(reload),
installAltDragGuard(() => current().appearance.dndWithAltOnly),
installIdleSave(() => ({ enabled: current().general.saveOnIdle, seconds: current().general.idleSeconds })),
];
// Without a project nothing loads the global settings; do it so theme / keymap apply on the welcome screen.
if (isTauri() && !useProject.getState().settings) {
loadSettings().catch((e) => console.warn("cannot load settings", e));
}
return () => unsubs.forEach((u) => u());
}