Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consistent warning that "I18nProvider did not render ..." #1194

Closed
tommhuth opened this issue Jan 14, 2022 · 18 comments
Closed

Consistent warning that "I18nProvider did not render ..." #1194

tommhuth opened this issue Jan 14, 2022 · 18 comments

Comments

@tommhuth
Copy link

tommhuth commented Jan 14, 2022

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?

@usercao
Copy link

usercao commented Jan 20, 2022

I18nProvider did not render. A call to i18n.activate still needs to happen or forceRenderOnLocaleChange must be set to false.
Me too.

@dmitryshelomanov
Copy link

@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)

@dmitryshelomanov
Copy link

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)

@boy-bizzmine
Copy link

boy-bizzmine commented Feb 18, 2022

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

@marcvangend
Copy link
Contributor

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.

@gpessa
Copy link

gpessa commented May 6, 2022

dmitryshelomanov do you have a complete example of your solution ?

@feledori
Copy link

feledori commented Jul 6, 2022

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.

@gpessa
Copy link

gpessa commented Jul 6, 2022

haven't found one so far

@stale
Copy link

stale bot commented Sep 8, 2022

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.

@stale stale bot added the wontfix label Sep 8, 2022
@gpessa
Copy link

gpessa commented Sep 9, 2022

still happening

@stale stale bot removed the wontfix label Sep 9, 2022
@oyed
Copy link

oyed commented Oct 5, 2022

Seeing this exact problem as well.

@stale
Copy link

stale bot commented Dec 4, 2022

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.

@usercao
Copy link

usercao commented Dec 4, 2022

Please refer to ice-test of this project for a complete solution.

@stale stale bot added the wontfix label Dec 4, 2022
@dmitryshelomanov
Copy link

@gpessa create codesandbox for me with default states (lingui, redux (?)) and etc
I will try to share complex solution

@stale stale bot removed the wontfix label Dec 10, 2022
@gpessa
Copy link

gpessa commented Dec 14, 2022

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

@dmitryshelomanov
Copy link

// 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

@dmitryshelomanov
Copy link

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

@vonovak
Copy link
Collaborator

vonovak commented May 26, 2023

@andrii-bodnar I believe this can be closed as the implementation has changed in v4 🙂

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests