import React from 'react'; import type { MosaicLocalization } from './catalog'; import type { MosaicMessages } from './registry'; import { mosaicMessages } from './registry'; interface MosaicLocalizationValue { messages: MosaicMessages; locale: string; } const MosaicLocalizationContext = React.createContext({ messages: mosaicMessages, locale: 'en', }); export const MosaicLocalizationProvider = MosaicLocalizationContext.Provider; function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null; } function merge(base: unknown, overrides: unknown): unknown { if (!isRecord(base) || !isRecord(overrides)) { return overrides ?? base; } let result = base; for (const [key, value] of Object.entries(overrides)) { if (value === undefined) { continue; } const dot = key.indexOf('.'); const head = dot === -1 ? key : key.slice(0, dot); const nested = dot === -1 ? value : { [key.slice(dot + 1)]: value }; result = { ...result, [head]: merge(result[head], nested) }; } return result; } function resolveLocale(locale: string | undefined): string { if (!locale) { return 'en'; } try { Intl.getCanonicalLocales(locale); return locale; } catch { return 'en'; } } export function resolveLocalization(localization: MosaicLocalization | undefined): MosaicLocalizationValue { const layers = [localization?.messages, localization?.overrides]; return { messages: layers.reduce(merge, mosaicMessages) as MosaicMessages, locale: resolveLocale(localization?.locale), }; } export function useMessages(namespace: Namespace): MosaicMessages[Namespace] { return React.useContext(MosaicLocalizationContext).messages[namespace]; } export function useLocale(): string { return React.useContext(MosaicLocalizationContext).locale; }