From 32897a3570edbe1ec7169d35f5527206826d781e Mon Sep 17 00:00:00 2001 From: Joel Sahleen Date: Sun, 9 Aug 2026 17:42:16 -0600 Subject: [PATCH 1/2] chore: Bump package version to 1.1.0 and enhance MsgResourceProvider with language detection --- package.json | 2 +- .../MsgResourceProvider.tsx | 47 ++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) 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..7d743ef 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,42 @@ 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; - - async function translate(langTag: string) { - const res = await resource.getTranslation(langTag); + 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 && lang !== res.attributes.lang) { + translate(lang); + } + } + }) + }); + + observer.observe(element, {attributes: true}); + } + + function getClosestElementWithLangAttribute(): Element | null | undefined { + const closest = msgRef.current?.closest('[lang]'); + console.log(closest?.id); + return closest; + } + + async function translate(langTag: string) { + try { + const res = await resource.getTranslation(langTag) setRes(res); + } catch (e) { + setRes(resource); } - if (lang) { - translate(lang); - } - }, [resource]); + } + + useEffect(() => { + const closest = getClosestElementWithLangAttribute() || document.documentElement; + detectLanguageChange(closest); + }, []); return (
From 3605483186bcb12c99570377bf57fa7592dbe89d Mon Sep 17 00:00:00 2001 From: Joel Sahleen Date: Sun, 9 Aug 2026 17:46:02 -0600 Subject: [PATCH 2/2] refactor: Improve language detection and translation handling in MsgResourceProvider --- .../MsgResourceProvider.tsx | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/components/MsgResourceProvider/MsgResourceProvider.tsx b/src/components/MsgResourceProvider/MsgResourceProvider.tsx index 7d743ef..85a56cc 100644 --- a/src/components/MsgResourceProvider/MsgResourceProvider.tsx +++ b/src/components/MsgResourceProvider/MsgResourceProvider.tsx @@ -21,26 +21,25 @@ export function MsgResourceProvider(props: MsgProviderProps) { mutations.forEach(mutation => { if (mutation.type === 'attributes' && mutation.attributeName === 'lang') { const lang = element.getAttribute('lang') || navigator.language; - if (lang && lang !== res.attributes.lang) { + if (lang) { translate(lang); } } }) }); - observer.observe(element, {attributes: true}); + observer.observe(element, {attributes: true, attributeFilter: ['lang']}); + return observer; } function getClosestElementWithLangAttribute(): Element | null | undefined { - const closest = msgRef.current?.closest('[lang]'); - console.log(closest?.id); - return closest; + return msgRef.current?.closest('[lang]'); } async function translate(langTag: string) { try { - const res = await resource.getTranslation(langTag) - setRes(res); + const translated = await resource.getTranslation(langTag) + setRes(translated); } catch (e) { setRes(resource); } @@ -48,7 +47,12 @@ export function MsgResourceProvider(props: MsgProviderProps) { useEffect(() => { const closest = getClosestElementWithLangAttribute() || document.documentElement; - detectLanguageChange(closest); + const lang = closest.getAttribute('lang') || navigator.language; + if (lang) { + translate(lang); + } + const observer = detectLanguageChange(closest); + return () => observer.disconnect(); }, []); return ( @@ -59,4 +63,3 @@ export function MsgResourceProvider(props: MsgProviderProps) {
) } -