diff --git a/package.json b/package.json index cd05a3d..f1af80d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@worldware/msg-react", - "version": "1.0.0", + "version": "1.1.0", "description": "React components for rendering messages from @worldware/msg", "main": "dist/index.cjs", "module": "dist/index.mjs", diff --git a/src/components/MsgResourceProvider/MsgResourceProvider.tsx b/src/components/MsgResourceProvider/MsgResourceProvider.tsx index 48027ed..85a56cc 100644 --- a/src/components/MsgResourceProvider/MsgResourceProvider.tsx +++ b/src/components/MsgResourceProvider/MsgResourceProvider.tsx @@ -1,7 +1,7 @@ 'use client' import {useEffect, useRef, useState, createContext} from 'react'; -import { type MsgResource } from '@worldware/msg'; +import { MsgResource } from '@worldware/msg'; export const MsgResourceContext = createContext(null) @@ -14,21 +14,46 @@ export function MsgResourceProvider(props: MsgProviderProps) { const { resource, children } = props; const msgRef = useRef(null); - const [res, setRes] = useState(resource) + const [res, setRes] = useState(resource); - useEffect(() => { - const closestLangAttribute: string | null | undefined = msgRef.current?.closest('[lang]')?.getAttribute('lang'); - const navigatorLanguage: string = navigator.language; - const lang = closestLangAttribute ?? navigatorLanguage; + function detectLanguageChange(element: Element) { + const observer = new MutationObserver((mutations) => { + mutations.forEach(mutation => { + if (mutation.type === 'attributes' && mutation.attributeName === 'lang') { + const lang = element.getAttribute('lang') || navigator.language; + if (lang) { + translate(lang); + } + } + }) + }); + + observer.observe(element, {attributes: true, attributeFilter: ['lang']}); + return observer; + } + + function getClosestElementWithLangAttribute(): Element | null | undefined { + return msgRef.current?.closest('[lang]'); + } - async function translate(langTag: string) { - const res = await resource.getTranslation(langTag); - setRes(res); + async function translate(langTag: string) { + try { + const translated = await resource.getTranslation(langTag) + setRes(translated); + } catch (e) { + setRes(resource); } + } + + useEffect(() => { + const closest = getClosestElementWithLangAttribute() || document.documentElement; + const lang = closest.getAttribute('lang') || navigator.language; if (lang) { translate(lang); } - }, [resource]); + const observer = detectLanguageChange(closest); + return () => observer.disconnect(); + }, []); return (
@@ -38,4 +63,3 @@ export function MsgResourceProvider(props: MsgProviderProps) {
) } -