2979d06f1c
Align control/presentation with presentation screen rect and darkness z-order; sync window titles and session window cleanup. Pack Win/Mac/Linux with npmRebuild disabled and release-native-prep for classic-level and sharp. Co-authored-by: Cursor <cursoragent@cursor.com>
77 lines
2.4 KiB
TypeScript
77 lines
2.4 KiB
TypeScript
import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
|
|
|
import {
|
|
EDITOR_LOCALE_STORAGE_KEY,
|
|
inferEditorLocaleFromSystem,
|
|
normalizeEditorLocale,
|
|
translateEditorMessage,
|
|
type EditorLocale,
|
|
} from './editorMessages';
|
|
import { getDndApi } from '../../shared/dndApi';
|
|
import { ipcChannels } from '../../../shared/ipc/contracts';
|
|
|
|
type EditorI18nContextValue = {
|
|
locale: EditorLocale;
|
|
setLocale: (next: EditorLocale) => void;
|
|
t: (key: string, vars?: Record<string, string | number>) => string;
|
|
};
|
|
|
|
const EditorI18nContext = createContext<EditorI18nContextValue | null>(null);
|
|
|
|
function readInitialLocale(): EditorLocale {
|
|
try {
|
|
return normalizeEditorLocale(localStorage.getItem(EDITOR_LOCALE_STORAGE_KEY));
|
|
} catch {
|
|
return inferEditorLocaleFromSystem();
|
|
}
|
|
}
|
|
|
|
export function EditorI18nProvider({ children }: { children: React.ReactNode }) {
|
|
const [locale, setLocaleState] = useState<EditorLocale>(readInitialLocale);
|
|
|
|
const setLocale = useCallback((next: EditorLocale) => {
|
|
setLocaleState(next);
|
|
try {
|
|
localStorage.setItem(EDITOR_LOCALE_STORAGE_KEY, next);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
const tag = locale === 'ru' ? 'ru-RU' : 'en-US';
|
|
try {
|
|
void getDndApi().invoke(ipcChannels.windows.syncChromeTitles, { localeTag: tag });
|
|
} catch {
|
|
// preload ещё не готов (редко при первом кадре)
|
|
}
|
|
}, [locale]);
|
|
|
|
// Другие окна Electron (пульт, материалы) подхватывают смену языка из редактора.
|
|
useEffect(() => {
|
|
const onStorage = (e: StorageEvent) => {
|
|
if (e.key !== EDITOR_LOCALE_STORAGE_KEY) return;
|
|
setLocaleState(normalizeEditorLocale(e.newValue));
|
|
};
|
|
window.addEventListener('storage', onStorage);
|
|
return () => window.removeEventListener('storage', onStorage);
|
|
}, []);
|
|
|
|
const t = useCallback(
|
|
(key: string, vars?: Record<string, string | number>) => translateEditorMessage(locale, key, vars),
|
|
[locale],
|
|
);
|
|
|
|
const value = useMemo<EditorI18nContextValue>(() => ({ locale, setLocale, t }), [locale, setLocale, t]);
|
|
|
|
return <EditorI18nContext.Provider value={value}>{children}</EditorI18nContext.Provider>;
|
|
}
|
|
|
|
export function useEditorI18n(): EditorI18nContextValue {
|
|
const ctx = useContext(EditorI18nContext);
|
|
if (!ctx) {
|
|
throw new Error('useEditorI18n must be used within EditorI18nProvider');
|
|
}
|
|
return ctx;
|
|
}
|