69 lines
2.4 KiB
JavaScript
69 lines
2.4 KiB
JavaScript
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
import {
|
|
DEFAULT_EXTERNAL_LOCALE,
|
|
EXTERNAL_LANGUAGE_OPTIONS,
|
|
EXTERNAL_LOCALE_STORAGE_KEY,
|
|
externalDirection,
|
|
externalMessage,
|
|
normalizeExternalLocale
|
|
} from "./messages.js";
|
|
|
|
const defaultTranslate = (key, values) => interpolate(externalMessage(DEFAULT_EXTERNAL_LOCALE, key), values);
|
|
const ExternalI18nContext = createContext({
|
|
direction: "ltr",
|
|
languages: EXTERNAL_LANGUAGE_OPTIONS,
|
|
locale: DEFAULT_EXTERNAL_LOCALE,
|
|
setLocale: () => {},
|
|
t: defaultTranslate
|
|
});
|
|
|
|
export function ExternalI18nProvider({ children }) {
|
|
// The product default is deliberately English. Browser language is ignored until the operator explicitly chooses and persists another locale.
|
|
const [locale, setLocaleState] = useState(readPersistedLocale);
|
|
const direction = externalDirection(locale);
|
|
const setLocale = useCallback((nextLocale) => {
|
|
const normalized = normalizeExternalLocale(nextLocale);
|
|
setLocaleState(normalized);
|
|
try {
|
|
globalThis.localStorage?.setItem(EXTERNAL_LOCALE_STORAGE_KEY, normalized);
|
|
} catch {
|
|
// Storage can be unavailable in hardened/private browser contexts; the in-memory locale still changes for the current session.
|
|
}
|
|
}, []);
|
|
const t = useCallback((key, values) => interpolate(externalMessage(locale, key), values), [locale]);
|
|
|
|
useEffect(() => {
|
|
// Keep native controls, assistive technology, MUI portals and the shell aligned when Arabic changes writing direction.
|
|
const root = globalThis.document?.documentElement;
|
|
if (!root) {
|
|
return;
|
|
}
|
|
root.lang = locale;
|
|
root.dir = direction;
|
|
globalThis.document.body?.setAttribute("dir", direction);
|
|
}, [direction, locale, t]);
|
|
|
|
const value = useMemo(
|
|
() => ({ direction, languages: EXTERNAL_LANGUAGE_OPTIONS, locale, setLocale, t }),
|
|
[direction, locale, setLocale, t]
|
|
);
|
|
|
|
return <ExternalI18nContext.Provider value={value}>{children}</ExternalI18nContext.Provider>;
|
|
}
|
|
|
|
export function useExternalI18n() {
|
|
return useContext(ExternalI18nContext);
|
|
}
|
|
|
|
function readPersistedLocale() {
|
|
try {
|
|
return normalizeExternalLocale(globalThis.localStorage?.getItem(EXTERNAL_LOCALE_STORAGE_KEY));
|
|
} catch {
|
|
return DEFAULT_EXTERNAL_LOCALE;
|
|
}
|
|
}
|
|
|
|
function interpolate(message, values = {}) {
|
|
return String(message).replace(/\{(\w+)\}/g, (match, key) => (values[key] === undefined ? match : String(values[key])));
|
|
}
|