js-lingui
js-lingui copied to clipboard
Consistent warning that "I18nProvider did not render ..."
When using I18nProvider
from @lingui/react
in a Next app, I got a consistent console warning every-time warning that
I18nProvider did not render. A call to i18n.activate still needs to happen or forceRenderOnLocaleChange must be set to false.
We load the locale async in an useEffect
like
const { locale = 'en' } = useRouter();
useEffect(() => {
async function load(locale: string) {
const { messages } = await import(
`../translations/locales/${locale}/messages.po`
);
i18n.load(locale, messages);
i18n.activate(locale);
}
load(locale);
}, [locale]);
meaning activate will always get called, though not in the initial server side render output. Is this warning an indication of an issue or problem? If so how can I fix it? Setting forceRenderOnLocaleChange
to false
is not an option as I cannot see a reason why I would not want children
to rerender if the user changes the language.
Or is this async locale load simply not the way to do it?
I18nProvider did not render. A call to i18n.activate still needs to happen or forceRenderOnLocaleChange must be set to false.
Me too.
@tommhuth You need to set forceRenderOnLocaleChange={false}
And create local instance like this
const [i18n] = useState(() =>
setupI18n({
messages: {
[locale]: { ...messages },
},
localeData: {
en: { plurals: en },
ru: { plurals: ru },
},
locale,
}),
);
On ssr I created thunk with webpack dynamic import First SSr render completed with correct locales On static (no ssr) mode app waiting for tryToLoad locale (its quickly operation)
SSR steps -> fetchData -> create store -> render app (locales already)
(Between page navigation we can local locales same) -> go to page -> call fetch -> render page with next data
Static steps
-> render app -> call fetch inside effects -> try import and set flag to store -> in root return null if false (its more usable then fonts change from lang to another lang)
Same question as @tommhuth and same setup. Language files are loaded in async/await and only then activate()/load() is called. It seems to be working anyway but quite annoying if it doesn't really indicate a real issue. It should be possible though according to https://lingui.js.org/guides/dynamic-loading-catalogs.html#final-i18n-loader-helper
I ran into the same issue after applying the dynamic loading method. It seems that it is triggered by the <I18nProvider>
component when it is first rendered, before the useEffect hook runs.
Maintainers, please correct me if I'm wrong. As far as I can see things still work as expected. The warning doesn't seem to do any harm, but it is annoying and it is costing developers time because it looks like something that needs to be fixed.
As a workaround, to get rid of the warning, I added two lines to the I18n loader helper, immediately after the call to i18n.loadLocaleData()
:
i18n.load(defaultLocale, {});
i18n.activate(defaultLocale);
This activates the default locale with an empty set of messages, so at least a "dummy locale" is active when <I18nProvider>
is first rendered.
dmitryshelomanov do you have a complete example of your solution ?
Running in to the same issue with a ssg next.js app. is there an official solution to this problem? if so I could make a pull request on the official next.js example.
haven't found one so far
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
still happening
Seeing this exact problem as well.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Please refer to ice-test of this project for a complete solution.
@gpessa create codesandbox for me with default states (lingui, redux (?)) and etc I will try to share complex solution
i'm cloning the example in this repo. if you load the index, and check the source code of the generate page, you'll see it empty
// Provider
import { ReactNode, useEffect, useState } from 'react';
import { en, ru } from 'make-plural';
import { setupI18n } from '@lingui/core';
import { I18nProvider } from '@lingui/react';
import { useStore } from 'effector-react/scope';
import { $locale, $messages } from './model';
type Props = {
children: ReactNode;
};
export function LocaleProvider({ children }: Props) {
const locale = useStore($locale);
const messages = useStore($messages);
const [i18n] = useState(() =>
setupI18n({
messages: {
[locale]: { ...messages },
},
localeData: {
en: { plurals: en },
ru: { plurals: ru },
},
locale,
}),
);
useEffect(() => {
i18n.load(locale, { ...messages });
i18n.activate(locale);
}, [i18n, locale, messages]);
return (
<I18nProvider i18n={i18n} forceRenderOnLocaleChange={false}>
{children}
</I18nProvider>
);
}
model
import { Messages } from '@lingui/core';
import { createEffect, createEvent, createStore, sample } from 'effector';
import { appStarted } from 'shared/start';
export const $locale = createStore('ru');
export const $messages = createStore<Messages>({});
export const changeLocale = createEvent<string>();
export const loadLocalesFx = createEffect(async ({ locale }: { locale: string }) => {
const rootMessages = await import(/* webpackChunkName: "root-i18-[request]" */ `i18n/locales/${locale}.js`).then(
({ messages }) => messages as Messages,
);
return rootMessages;
});
$locale.on(loadLocalesFx.done, (_, { params }) => params.locale);
$messages.on(loadLocalesFx.doneData, (_, messages) => messages);
sample({
clock: appStarted,
source: $locale,
fn: locale => ({ locale }),
target: loadLocalesFx,
});
sample({
clock: changeLocale,
fn: locale => ({ locale }),
target: loadLocalesFx,
});
With redux
effector replace with redux and use createAsyncThunk for handle async import, selectors for data access
@gpessa
and you need to trans with
const {i18n} = useLingui()
Even if you use lingui macro
macro transform you code and set i18 global when local not found
@andrii-bodnar I believe this can be closed as the implementation has changed in v4 🙂