Locales are not loaded if Shallow Routing
Hi,
In order to change the location and maintain the app state and the current path (Change language while staying on the same route). I ran into this issue: next Router changes the local, but next-translate remains in the current language.
<Link href={router.asPath} locale={lng} key={lng} shallow={true}>...</Link>
I would like to understand in which cases you need shallow=true? Shallow routing allows you to change the URL without running data fetching methods again, which includes getServerSideProps, getStaticProps, and getInitialProps. But next-translate needs these methods to download the page translations.
I am currently working on migrating from react-app to nextJs, we are using redux for state management. So if I change the app language without shallow=true, as you say NextJs run data fetching methods again.
That cause the redux store to initialize, so we lost any data fetching that was happening on the client side.
@Aeet Maybe you can use a hook using the getT function to download in client-side the necessary translations without doing it in the fetching methods.
I guess it would be something like this:
import React, { Fragment, useEffect, useState } from 'react'
import Link from 'next/link'
import { useRouter } from 'next/router'
import useTranslation from 'next-translate/useTranslation'
import getT from 'next-translate/getT'
export default function useShallowTranslation(ns) {
const { locale } = useRouter()
const { lang, t } = useTranslation(ns)
const [_t, setT] = useState(() => t)
const [_lang, setLang] = useState(lang)
useEffect(() => {
if (lang === locale) return
getT(locale, ns).then(newT => {
setT(() => newT)
setLang(locale)
})
}, [lang, locale])
return { t: _t, lang: _lang }
}
Then you should use it similar to useTranslation but always passing the namespace it needs:
export default function MyComponent() {
const { t, lang } = useShallowTranslation('common')
const title = t('title')
return <h1>{title}</h1>
}
I think it should work. It's not a very elegant solution, but I hope it can work for you in this particular case (since it's not very usual to use shallow=true to switch languages).
I don't know if there is a way to know if the current navigation comes from shallow routing, if so, maybe we could force the I18nProvider to download the necessary page translations inside a useEffect, so you don't have to use the above workaround...
Was there any updates in here? I'm facing the same issue.
Thing is We have some requests to be made in our _app.js's getInitialProps and they get re-executed upon lang change :(
@Aeet Maybe you can use a hook using the
getTfunction to download in client-side the necessary translations without doing it in the fetching methods.
export default function useShallowTranslation(ns) { const { locale } = useRouter() const { lang, t } = useTranslation(ns) const [_t, setT] = useState(() => t) const [_lang, setLang] = useState(lang)
useEffect(() => { if (lang === locale) return getT(locale, ns).then(newT => { setT(() => newT) setLang(locale) }) }, [lang, locale])
If you switch the initial language and then u go back to it, it won't be reflected in the UI because lang from useTranslation doesn't change on shallow routing. Instead of the lang===locale check I added a mounted Ref check
import { useEffect, useRef, useState } from 'react'
import { useRouter } from 'next/router'
import _useTranslation from 'next-translate/useTranslation'
import getT from 'next-translate/getT'
export default function useTranslation(ns: string) {
const mounted = useRef(false)
const { locale } = useRouter()
const { lang, t } = _useTranslation(ns)
const [_t, setT] = useState(() => t)
const [_lang, setLang] = useState(lang)
useEffect(() => {
if (!mounted.current) {
mounted.current = true
return
}
getT(locale, ns).then((newT) => {
setT(() => newT)
setLang(locale)
})
}, [lang, locale])
return { t: _t, lang: _lang }
}
I don't know if there is a way to know if the current navigation comes from shallow routing, if so, maybe we could force the
I18nProviderto download the necessary page translations inside auseEffect, so you don't have to use the above workaround...
also Next can now identify if the route change is using shallow Update: I tried implementing shallow support in the provider, but for some reason the router object is not being updated #917
https://github.com/vercel/next.js/pull/19802 https://nextjs.org/docs/api-reference/next/router#routerevents