next-translate
next-translate copied to clipboard
[Question] DynamicNamespaces problems
I'm doing an application where the user language is defined after login, so after get the user information I set correct language
useEffect(() => {
const changeUserLanguage = async (locale: string) => setLanguage(locale)
...
if (userLocale) {
changeUserLanguage(userLocale)
}
}, [...])
The texts that are not dynamic updates to the correct language immediately, but the content inside DynamicNamespaces do not update. I print the locale to see if they're changing and it was, but the property lang
returned by dynamic doesn't.
const getDynamic = async (lang = 'pt-BR', nameSpace: string) => {
try {
const widgetName = getWidgetName(widget.name)
const language = await import(
`packages/widgets/${widgetName}/locales/${lang}/${nameSpace}.json`
)
return language.default
} catch (err) {
console.error(err)
return null
}
}
return (
<DynamicNamespaces namespaces={['dynamic']} dynamic={getDynamic}>
{appProps && (
<WidgetComponent
widget={widget}
appProps={appProps}
prefetchData={getPrefetchData(prefetchUrl)}
/>
)}
</DynamicNamespaces>
)
Here you can see that after the language changes, they not call getDynamic again
Is this expected or is a bug? I really need to make this work urgently
@william-hotmart I think that <DynamicNamespace>
isn't updating since its props aren't. Try to wrap getDynamic
with useCallback
and add current lang as its dependency. Thus changing language will change getDynamic
and trigger updating of <DynamicNamespace>
.
Not sure tho, just passing by 😄
@william-hotmart I think that
<DynamicNamespace>
isn't updating since its props aren't. Try to wrapgetDynamic
withuseCallback
and add current lang as its dependency. Thus changing language will changegetDynamic
and trigger updating of<DynamicNamespace>
. Not sure tho, just passing by
Hi @vlad-elagin, thanks for the answer.
Teorically the getDynamic
function is created in every render. What seems not to change is lang
property. Or at least is the dynamic
property is not being called again.
I'll rewrite the DynamicNamespace
component locally and it works. So maybe this can be a bug.
Here is my version of DynamicNamespace
import { useEffect, useMemo, useState } from 'react'
import { DynamicNamespacesProps, I18nDictionary } from 'next-translate'
import I18nProvider from 'next-translate/I18nProvider'
import { useRouter } from 'next/router'
const DynamicNamespaces = ({
dynamic,
namespaces = [],
fallback,
children
}: DynamicNamespacesProps) => {
const { locale } = useRouter()
const [loaded, setLoaded] = useState<boolean>(false)
const [pageNs, setPageNs] = useState<I18nDictionary[]>([])
useEffect(() => {
const loadNamespaces = async () => {
if (dynamic) {
const pageNamespaces = await Promise.all(namespaces.map((ns) => dynamic(locale, ns)))
setPageNs(pageNamespaces)
setLoaded(true)
}
}
loadNamespaces()
}, [dynamic, locale, namespaces])
const structuredNamespaces = useMemo(() => {
return namespaces.reduce((obj: Record<string, I18nDictionary>, ns, i) => {
obj[ns] = pageNs[i]
return obj
}, {})
}, [namespaces, pageNs])
if (loaded) {
return (
<I18nProvider lang={locale} namespaces={ns}>
{children}
</I18nProvider>
)
}
if (fallback) {
return <>{fallback}</>
}
return null
}
export default DynamicNamespaces
I proved this code but the problem is:
DynamicNamespaces don't refresh namespaces when change locale and I18NProvider only refresh when locale change so... the first render when you are requesting namespaces I18nProvider don't have namespaces yet. When you will have namespaces, the provider not update namespaces, only when change language soo..
I added a state: const [locale2, setLocale2] = useState(locale === 'en' ? 'es' : 'en'); (it's necesary locale2 exist in your page languages)
and upodate locale2 when you have namespaces: ->setLocal2(locale)
and the new lang param of i18nProvider will be locale2.
like this:
import { useEffect, useMemo, useState } from 'react'
import { DynamicNamespacesProps, I18nDictionary } from 'next-translate'
import I18nProvider from 'next-translate/I18nProvider'
import { useRouter } from 'next/router'
const DynamicNamespaces = ({
dynamic,
namespaces = [],
fallback,
children
}: DynamicNamespacesProps) => {
const { locale } = useRouter()
const [loaded, setLoaded] = useState<boolean>(false)
const [locale2, setLocale2] = useState(locale === 'en' ? 'es' : 'en');
const [pageNs, setPageNs] = useState<I18nDictionary[]>([])
useEffect(() => {
const loadNamespaces = async () => {
if (dynamic) {
const pageNamespaces = await Promise.all(namespaces.map((ns) => dynamic(locale, ns)))
setPageNs(pageNamespaces)
setLocale2(locale)
setLoaded(true)
}
}
loadNamespaces()
}, [dynamic, locale, namespaces])
const structuredNamespaces = useMemo(() => {
return namespaces.reduce((obj: Record<string, I18nDictionary>, ns, i) => {
obj[ns] = pageNs[i]
return obj
}, {})
}, [namespaces, pageNs])
if (loaded) {
return (
<I18nProvider lang={locale2} namespaces={pageNs}>
{children}
</I18nProvider>
)
}
if (fallback) {
return <>{fallback}</>
}
return null
}
export default DynamicNamespaces
And is it really necessary to use DynamicNamespace for this case? After login you can redirect to the same path with the lang changed and everything becomes much simpler.