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

fix: execute function in I18nProviderWrapper instead of I18nProvider #316

Merged
merged 7 commits into from
Dec 24, 2023

Conversation

Yovach
Copy link
Contributor

@Yovach Yovach commented Dec 20, 2023

Closes #290

With this fix, I wasn't able to reproduce the crash.

What is this PR ?

It moves the call of () => import("./en") from I18nProvider to I18nProviderWrapper.

I changed this because according to the React documentation of use hook (https://react.dev/reference/react/use#streaming-data-from-server-to-client), the promise is executed and passed as a prop from the parent but awaited in the child.

Copy link

vercel bot commented Dec 20, 2023

Someone is attempting to deploy a commit to a Personal Account owned by @QuiiBz on Vercel.

@QuiiBz first needs to authorize it.

Copy link
Owner

@QuiiBz QuiiBz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you so much! Just tried and everything seems to be working as expected. Some suggestions:

examples/next-app/locales/client.ts Outdated Show resolved Hide resolved
Copy link

vercel bot commented Dec 21, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
next-international ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 21, 2023 5:33pm

Copy link
Owner

@QuiiBz QuiiBz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the update. Unfortunately adding back the artificial delay shows that we now have a loading state when switching locale in client components, which we don't want:

Screen.Recording.2023-12-23.at.08.57.47.mov

I believe we'll need to add back the localesCache. use() always triggers suspense so we should only use it when loading the page for the first time.

@Yovach
Copy link
Contributor Author

Yovach commented Dec 23, 2023

Thanks for the update. Unfortunately adding back the artificial delay shows that we now have a loading state when switching locale in client components, which we don't want:

Screen.Recording.2023-12-23.at.08.57.47.mov
I believe we'll need to add back the localesCache. use() always triggers suspense so we should only use it when loading the page for the first time.

Based on your feedback, the I18nProvider now checks if there's a cached value for the current locale, otherwise it'll call the use hook with the import and store the result in the localesCache variable.

I've also added a check in changeLocale to execute the call the import function only if the newLocale is supported.

I think in the client.ts, we can add a parameter here :

// locales/client.ts

export const { useI18n, useScopedI18n, I18nProviderClient, useChangeLocale, defineLocale, useCurrentLocale } =
  createI18nClient(
    {
      en: async (isChanging: boolean = false) => { // <---- HERE
        if (!isChanging) {
          await new Promise(resolve => setTimeout(resolve, 100));
        }
        return import('./en');
      },
      fr: async (isChanging: boolean = false) => { // <---- HERE
        if (!isChanging) {
          await new Promise(resolve => setTimeout(resolve, 100));
        }
        return import('./fr');
      },
    },
    {
      // Uncomment to set base path
      // basePath: '/base',
      // Uncomment to use custom segment name
      // segmentName: 'locale',
      // Uncomment to set fallback locale
      // fallbackLocale: en,
    },
  );

and in the

// packages/next-international/src/app/client/create-use-change-locale.ts
export function createUseChangeLocale<LocalesKeys>(
  useCurrentLocale: () => LocalesKeys,
  locales: ImportedLocales,
  config: I18nClientConfig,
) {
  return function useChangeLocale(changeLocaleConfig?: I18nChangeLocaleConfig) {
    const { push, refresh } = useRouter();
    const currentLocale = useCurrentLocale();
    const path = usePathname();
    // We call the hook conditionally to avoid always opting out of Static Rendering.
    // eslint-disable-next-line react-hooks/rules-of-hooks
    const searchParams = changeLocaleConfig?.preserveSearchParams ? useSearchParams().toString() : undefined;
    const finalSearchParams = searchParams ? `?${searchParams}` : '';

    let pathWithoutLocale = path;

    if (config.basePath) {
      pathWithoutLocale = pathWithoutLocale.replace(config.basePath, '');
    }

    if (pathWithoutLocale.startsWith(`/${currentLocale}/`)) {
      pathWithoutLocale = pathWithoutLocale.replace(`/${currentLocale}/`, '/');
    } else if (pathWithoutLocale === `/${currentLocale}`) {
      pathWithoutLocale = '/';
    }

    return function changeLocale(newLocale: LocalesKeys) {
      const importFnLocale = locales[newLocale as keyof typeof locales];
      if (!importFnLocale) {
        warn(`The locale '${newLocale}' is not supported.`);
        return;
      }

      importFnLocale(true).then(module => { // <---- HERE
        localesCache.set(newLocale as string, module.default);
        push(`/${newLocale}${pathWithoutLocale}${finalSearchParams}`);
        refresh();
      });
    };
  };
}

As we don't need to wait for 100ms when changing the locale from the client

Copy link
Owner

@QuiiBz QuiiBz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks!

There's no need for isChanging for now, this is an implementation detail that shouldn't be exposed to the user. And keeping the timeout is very important in this example, to reveal issues like the one above in slow networks.

I'll publish a release in the next few days!

@QuiiBz QuiiBz merged commit 1bac288 into QuiiBz:main Dec 24, 2023
4 of 5 checks passed
@Yovach Yovach deleted the fix/use-promise-i18n-provider branch December 24, 2023 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

The PAGE CRASHES when you add I18nProviderClient and write in input control
2 participants