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

Could you write manuall for migration from 7 to 8 version #1040

Closed
sergeushenecz opened this issue Mar 8, 2021 · 54 comments
Closed

Could you write manuall for migration from 7 to 8 version #1040

sergeushenecz opened this issue Mar 8, 2021 · 54 comments

Comments

@sergeushenecz
Copy link

Hello everyone. I was looking for manual for migration but i don't found. Could you pls write

@isaachinman
Copy link
Contributor

Sounds like a great opportunity for user contribution!

@darkmavis1980
Copy link

To me, it sounds like something that should be defined in a changelog, as you kinda need to know the project very well and understand what changed from 7 to 8.

@jim-king-2000
Copy link

The change is too large. The migration works seems very heavy.

@jim-king-2000
Copy link

jim-king-2000 commented Mar 9, 2021

I'm still using withTranslation in next-i18next@8.x.x. But it can't load the local string. How to resolve it?

@jim-king-2000
Copy link

How to let the following code work on next-i18next?

import NextI18Next from 'next-i18next';
import path from 'path';

const NextI18NextInstance = new NextI18Next({
  defaultLanguage: 'en-US',
  otherLanguages: ['zh-CN'],
  localePath: path.resolve('./public/static/locales'),
  shallowRender: true,
  detection: { cookieMinutes: 60 * 24 * 365 },
});

export default NextI18NextInstance;

export const {
  appWithTranslation,
  withTranslation,
} = NextI18NextInstance;

@jim-king-2000
Copy link

Out legacy code uses classes, which prevents us from using hooks.

@joseph1125
Copy link

joseph1125 commented Mar 9, 2021

First paragraph of the manual:

If you are using getInitialProps for pages, sucks to be you and migrate all of them to getServerSideProps before continuing.

@jim-king-2000
Copy link

I have migrated it from v7 to v8. It takes me a whole day. It seems that next.js and next-i18next are not friendly with class components.

@jim-king-2000
Copy link

The key to the migration is as the following:

const Index = PageWrapper(Users);
export default Index;

export const getServerSideProps = async (ctx) => {
  const result = await Index.WrappedComponent.getInitialProps(ctx);
  return {
    props: {
      ...await serverSideTranslations(ctx.locale, ['common']),
      ...result,
    },
  };
};

Since we can't use getInitialProps directly, we can write getServerSideProps instead and invoke getInitialProps in it.

@jim-king-2000
Copy link

Finally, we don't use i18n.changeLanguages() any more. We use the code instead.

onChange={({ option }) => router.replace(router.pathname, router.pathname, { locale: option.value })}

@isaachinman
Copy link
Contributor

Please migrate your components away from getInitialProps entirely, and don't invoke getInitialProps from within getServerSideProps.

@vechnii2007
Copy link

Previously, I could use i18n in non-components using new NextI18Next. How can we create a new instance now?

@isaachinman
Copy link
Contributor

@vechnii2007 You can do:

import { i18n } from 'next-i18next'

@vechnii2007
Copy link

in console.log(i18n) have null

@vechnii2007
Copy link

vechnii2007 commented Mar 9, 2021

const { i18n } = require("./next-i18next.config"); in next.config.js

const path = require("path");

module.exports = {
    i18n: {
        defaultLocale: "en",
        locales: ["en", "th"],
    },
    otherLanguages: ["en", "th"],
    defaultLanguage: "en",
    localePath: path.resolve("./public/static/locales"),
    fallbackLng: ["en"],
    localeStructure: "{lng}/{ns}",
    interpolation: {
        prefix: "{",
        suffix: "}",
    },
    localeExtension: "json5",
    browserLanguageDetection: false,
    serverLanguageDetection: false,
};

in next-i18next.config.js

in App component

export default appWithTranslation(MyApp);

But i have another outside file, store.ts, where i used i18n from config file

const NextI18NextInstance = new NextI18Next({config})
export const { appWithTranslation, useTranslation, i18n, Trans } = NextI18NextInstance;

@jim-king-2000
Copy link

Please migrate your components away from getInitialProps entirely, and don't invoke getInitialProps from within getServerSideProps.

That would be a lot of work. We can't finish it in a short time.

@NicolasMalburet
Copy link

Hello,

Do you have any indications on how to migrate the NextJs error files?
For the 404 page, translation was working fine for me, but now that we must use getStaticProps or getServerSideProps my translation are no longer working.
I assume I have to use the _error page to manage 404 errors from now on, because there I can use getStaticProps. But Next won't let me use getInitialProps beside getStaticProps, and because of that I can no longer get the error code, which was provided with:

Error.getInitialProps = ({ res, err }: any) => {
  const namespacesRequired = ["common"];
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
  return { statusCode, namespacesRequired };
};

That error code doesn't seem to be available inside of getStaticProps.
Has someone solved this issue?

@jim-king-2000

This comment has been minimized.

@NicolasMalburet
Copy link

I am not sure how your PageWrapper is defined, and I cannot use getServerSideProps on the _error page.

@vechnii2007
Copy link

how use globali18n if we haven't access to global i18n ?

@ruhaim
Copy link

ruhaim commented Mar 11, 2021

Im also in the process of migration from v7 to v8. Hasn't been a smooth ride for the past few days.
My project was heavily dependent on getInitalProps.

Few things I learnt the hard way. These pointers might help to be included in the manual

  1. The old i18n.js which is of no use any more, new NextI18Next({opts}) is not a thing anymore
  2. serverSideTranslations should called at least once for the i18n to be properly initialized. This step is required
  3. serverSideTranslations() can only be imported within the getServerSideProps() in a page component.
  4. If serverSideTranslations() is called from anywhere else, NextJS will not build or pesky runtime error will keep showing.
    Note that if you have a common getServerSideProps() function for multiple pages (I had such a function for my getIntialProps() prior to migration), serverSideTranslations() cannot still be called in the common function. You will still endup with errors at build time.

ModuleNotFoundError: Module not found: Error: Can't resolve 'fs' in '/node_modules/next-i18next/dist/commonjs'

There was a thread in nextjs repo to as a possible workaround,
This was how I implemented
withCommonServerSideProps.js

export function withCommonServerSideProps(customSeversidePropsFn, opts) {
  return async function f(appContext) {
   // ...your common code here
    let props = {   };
    let customFnProps = { props: {} };
    if (customSeversidePropsFn) {
      customFnProps = await customSeversidePropsFn(appContext, props);
      props = {
        ...props,
        ...customFnProps.props,
      };
    }
    return {
      props: { ...JSON.parse(JSON.stringify(props)) },
    };
  };
}

pages/index.js

import { withCommonServerSideProps } from './withCommonServerSideProps';
//...your page component code
export const getServerSideProps = withCommonServerSideProps(
  async (appContext, commonProps) => {
    const i18nextProps = await serverSideTranslations(
      'nl-NL',
      ['common'],
    );
    return { props: {...i18nextProps} };
  },
  { },
);
  1. Always when returning props from getServerSideProps() make sure you do the following
return {
      props: { ...JSON.parse(JSON.stringify(props)) },
    };

If not you will run into another error in the lines of undefined cannot be parsed

  1. If there is a mismatch between the text cases in defined in the next.config.js i18n:{} and in the locale you pass to the serverSideTranslations() function, eg: 'nl-NL and nl-nl', A React Suspense error gets thrown.
    make sure there is an exact case match when passing the locales in to the functions

My migration is not over yet, but these were some of the worst ones, I will update this thread if find any further in to the task.

Hope this helps someone!!

@VitaliyInshakov
Copy link

in console.log(i18n) have null

@isaachinman, what with this trouble(bug)? lib doesn't work properly? do you plan to fix it?

@isaachinman
Copy link
Contributor

It's not a bug, the i18n instance is null until it is initialised.

@isaachinman
Copy link
Contributor

I would like to reiterate for any users who are new to NextJs, that you should be using getStaticProps unless you have a specific reason to be using getServerSideProps.

@annbeemsterboer
Copy link

annbeemsterboer commented Mar 19, 2021

@ruhaim you write "If serverSideTranslations() is called from anywhere else, NextJS will not build or pesky runtime error will keep showing.". The README mentions it should also be possible from getStaticProps, did you purposefully exclude it?

I keep having the same error you mention (but from use with getStaticProps )
ModuleNotFoundError: Module not found: Error: Can't resolve 'fs' in '/node_modules/next-i18next/dist/commonjs'

Edit: just saw @isaachinman's comment: answer is should be possible :) Doesnt resolve my error though. I am not calling it anywhere outside getStaticProps and have no unused imports (where it would be included in the client-side bundle). Any tips here?

@vechnii2007
Copy link

I would like to reiterate for any users who are new to NextJs, that you should be using getStaticProps unless you have a specific reason to be using getServerSideProps.

can u show example how can init i18n, when we build project, and need instance i18n not pages or components

@ruhaim
Copy link

ruhaim commented Mar 19, 2021 via email

@vechnii2007
Copy link

It's not a bug, the i18n instance is null until it is initialised.

where i can do the initialization of i18n, except gSSp, gSP?

@isaachinman
Copy link
Contributor

except gSSp, gSP?

That is exactly where it is initialised. Please feel free to check out the source code.

@ruhaim
Copy link

ruhaim commented Mar 19, 2021

@ruhaim you write "If serverSideTranslations() is called from anywhere else, NextJS will not build or pesky runtime error will keep showing.". The README mentions it should also be possible from getStaticProps, did you purposefully exclude it?

I keep having the same error you mention (but from use with getStaticProps )
ModuleNotFoundError: Module not found: Error: Can't resolve 'fs' in '/node_modules/next-i18next/dist/commonjs'

Edit: just saw @isaachinman's comment: answer is should be possible :) Doesnt resolve my error though. I am not calling it anywhere outside getStaticProps and have no unused imports (where it would be included in the client-side bundle). Any tips here?

@annbeemsterboer Could you check if there is an unused reference or an import to serverSideTranslations in your codebase? It causes the same error to be thrown. I experienced it.

@vechnii2007
Copy link

vechnii2007 commented Mar 19, 2021

except gSSp, gSP?

That is exactly where it is initialised. Please feel free to check out the source code.

I don't want feel free to check out the SOURCE CODE, I just want an adequate normal migration guide from one version to another, otherwise there is no need such versions

why this offtopic? @isaachinman we ask a normal question, how to get access to i18n instance from another file, not page or component?
if i import { i18n } from "next-i18next"; i have null object
maybe need return constructor for create a new Instance?

i mean this
const NextI18NextInstance = new NextI18Next({})

@saqbach
Copy link

saqbach commented Mar 21, 2021

I'm going to go out on a limb and say it was marked as off-topic because it was hostile. This project is amazing and really helps when it comes to adding i18n to a Nextjs application and some of ya'll are being pretty demanding without offering a whole lot of support. Open source only works when other people contribute. If you can't become a sponsor (how are there only 4 sponsors?!?!) you should, at a minimum, consider contributing documentation, adding to the README, etc.

The absolute worst thing you can do is to to be antagonistic or hostile. We get it. You have a job to do and you'd like for it to be as easy as possible. We all do. Get over it. You want to write a library to support i18n on Nextjs from scratch? Me either.

Ya'll really expect @isaachinman to maintain the library, write all the documentation, keep up with the incredibly fast pace of the Nextjs team's changes, write migration guides, answer all your questions in a timely manner AND deal with hostile comments? For free?

I don't want feel free to check out the SOURCE CODE, I just want an adequate normal migration guide from one version to another

Then write one yourself & make it available to the community. You are not entitled to anything.

I think he has been pretty clear in this and in other issues. @ruhaim's comment above is especially helpful. I've only been playing around with the library for ~ 24 hours, but my understanding is the following (feel free to fact check me if any of this is incorrect):

  1. You must use the built-in Nextjs i18n routing that was released in 10.0.0.
  2. You must use serverSideTranslations for the i18n instance to be initialized. If you do not, you will see an error message. You cannot randomly import { i18n } and expect it to work.
  3. You can only import and call serverSideTranslations inside a Nextjs /pages/{page} component. If you attempt to use it in a non page component, you will see an error message.
  4. The i18n instance is null until it is initialized.
  5. You should not be using getInitialProps -- this is not a next-i18next thing, this is a Nextjs thing. The Nextjs team added getStaticProps and getServerSideProps over a year ago. You should use them. They are orders of magnitude better for reasoning through your code & deciding what data needs to be fetched at build time and what should be server rendered on each request.The fact that serverSideTranslations is incompatible with getInitialProps is listed on the README.
  6. You have to use hooks. React added those in 16.8. They were introduced 2.5 years ago. Yes, it sucks if you have a bunch of class components, but worst case and you really can't rewrite the class component, you should be able to use the hook as an HOC.
  7. Once you have invoked serverSideTranslations inside either getStaticProps or getServerSideProps on a page component, you can then use the useTranslation hook in any component in that tree. You can see what that looks like by looking at the Footer component in the simple example.
  8. If you are using a conditional render that depends on a client call like checking whether someone is authenticated i.e. {user ? <Button>Dashboard</Button> : <Button>Login</Button>} and you attempt to use the useTranslation hook i.e. {t('dashboard')} it won't work & you will see the react-i18next:: You will need to pass in an i18next instance by using initReactI18next error. I haven't really found a graceful fix for this other than just changing my conditional render pattern.
  9. If you attempt to import / use the useTranslation hook on a component where the parent page does not have serverSideTranslations invoked, you will get the react-i18next:: You will need to pass in an i18next instance by using initReactI18next error.

TL;DR - Be nice. Go sponsor the project.

@isaachinman
Copy link
Contributor

Hey @austinhale – thanks for the write up, and I appreciate the sentiment. Open source software is largely thankless work – that's just the way it is.

Your comments are all spot on, and I think they will be very helpful to other users.

I would like to point out a few other things:

  1. If you'd like to continue using getInitialProps, then don't upgrade to next-i18next@>=8. All previous versions support getInitialProps
  2. I think somehow the documentation must be misleading, because quite a few people have come under the impression that serverSideTranslations is optional. It is not – it is the core piece of functionality that allows next-i18next to work
  3. Hooks are recommended, but not actually required. next-i18next still exports the withTranslation HOC

Also, I'm not sure I understand your eighth point – do you mind opening an issue for that one? You should be able to call useTranslation anywhere inside the I18nextProvider context.

@vechnii2007 The next-i18next package no longer exports a class constructor. The i18n export is instantiated as null, and then reassigned here during the first React render. Therefore, you can only expect it to not be null after the first React render.

We are all software developers – don't be afraid of reading the source code.

@vechnii2007
Copy link

@austinhale @isaachinman Thanks guys for good answer. Sorry if i hurt your feelings.

@vechnii2007
Copy link

vechnii2007 commented Mar 21, 2021

@isaachinman
I solved the initialization issue, thanks
But faced localeStructure and interpolation problem
my json is for variables with single brackets.
in the config it was stated that

localeStructure: "{lng} / {ns}",
    interpolation: {
        prefix: "{",
        suffix: "}",
    },

now such an entry does not work, I looked in the code and found that in
node_modules/next-i18next/dist/commonjs/config/createConfig.js
you are doing a replacement
var defaultLocaleStructure = localeStructure.replace ('{{lng}}', lng) .replace ('{{ns}}', defaultNS);
If you change it to single brackets or add an entry, then everything will work.
Tell me, is such a hard comparison due to something?

@isaachinman
Copy link
Contributor

@vechnii2007 Although that check is just to ensure defaultNSExists and wouldn't break anything in production, it does seem as though we have a bug – that '{{lng}}' format should not be hardcoded. Do you mind opening a separate issue?

@vechnii2007

This comment has been minimized.

@annbeemsterboer
Copy link

You need to call serverSideTranslations() directly within getServerSideProps() or getStaicProps(). If you call serverSideTranslations() via a wrapper method, then you confront the error. In other words the serverSideTranslations import should be on a page level component. Never in an inner component

@ruhaim indeed this was my issue, I was using it in on a component level in addition to page level. Thanks for the info!

@vaniyokk

This comment has been minimized.

@isaachinman
Copy link
Contributor

@vaniyokk As previously stated, if you want to continue using getInitialProps, just use next-i18next@<8.

The getInitialProps method is still technically supported, but is not recommended and will most likely be fully deprecated in the future.

@joseph1125
Copy link

If you needs to keep using getInitialProps and requires continuous support and patches of i18n support, I would recommend switching to next-translate as they still keep supporting getInitialProps

@isaachinman
Copy link
Contributor

I'd like to stress that currently the only reason to use getInitialProps is for a custom _error page, because it currently does not support getServerSideProps, and there's no other way to retrieve the status code. This is a shortcoming of the NextJs framework, not next-i18next.

@Shariaty
Copy link

@isaachinman
Thank you so much for your effort developing this library to be used by the community. First, when I read the documentation it was really misleading and thought that the serverSideTranslations would be an optional feature which will be come in handy when we need locale or trans in next JS special functions such as getServerSideProps, while It was the core Idea behind the scene. However, I have a question and I would appreciate it if you could guide me through.
What would be the best practice to have translations across shared components, Such as the Header of the Application, Should each page use getStaticProps and turn the page into SSG and pass the translation data to the header layout, since the serverSideTranslations is not available in components and only will work in pages? Does it make sense?

@isaachinman
Copy link
Contributor

@Shariaty This is specifically covered in the documentation:

Note: useTranslation provides namespaces to the component that you use it in. However, serverSideTranslations provides the total available namespaces to the entire React tree and belongs on the page level. Both are required.

@Shariaty
Copy link

@isaachinman When both are required, It means that useTranslation hook wont work without serverSideTranslations and serverSideTranslations should be implemented in each and every page in order to useTranslation which is used inside header layout shared among all pages works ?

@isaachinman
Copy link
Contributor

Yes, that is correct.

@User5842
Copy link

@austinhale I just wanted to say that your reply saved me tons of time and frustration! Everyone should know about this comment. Thank you.

@gcaggia
Copy link

gcaggia commented May 31, 2021

Could someone help me and tell me what is the equivalence of i18n.changeLanguage() with the v8?
I was using this method to dynamically change the language and it is broken now 😢 .

@isaachinman In the basic example you shared in the documentation, you show just one approach with the Link tag and locale. It would be great to show other possibilities like doing dynamically in a component by calling a function. I am happy to contribute and help with the documentation if you need it.

@isaachinman
Copy link
Contributor

@gcaggia As stated previously, NextJs handles i18n routing internally.

@samfromaway
Copy link
Contributor

samfromaway commented Jun 2, 2021

Could someone help me and tell me what is the equivalence of i18n.changeLanguage() with the v8?
I was using this method to dynamically change the language and it is broken now 😢 .

@isaachinman In the basic example you shared in the documentation, you show just one approach with the Link tag and locale. It would be great to show other possibilities like doing dynamically in a component by calling a function. I am happy to contribute and help with the documentation if you need it.

Maybe this helps. That's a function where you can call everywhere: router.push(router.asPath, undefined, { locale: currentLanguage, });

This uses the router of next.js

@samfromaway
Copy link
Contributor

samfromaway commented Jun 2, 2021

Here a little summary what I did to migrate quite a large app.

My project env:
"react": "17.0.2",
"next-i18next": "^8.4.0",
"next": "10.2.3"
I configured my next.config.js to use webpack 4

  1. Remove i18n.js and add next-i18next.config.js like described in the docs
  2. Use replace-all (from VS code) to change import { withTranslation } from 'i18n.js to import { withTranslation } from 'next-i18next'
  3. Add to getServerSideProps or getInitialProps in the return as props...(await serverSideTranslations(locale, ['common'])) in every single page where I had translations in children (in my app I changed it in all pages).
  4. Add in custom 404 page the ...(await serverSideTranslations(locale, ['common'])), as a return -> props in getStaticProps so the 404 page works with translations as well.
  5. Remove namespacesRequired: ['common'], in _app (not used anymore)
  6. Adjust the Jest test settings to mock withTranslation, t() and i18n in props.
  7. Change the language changer to router.push(router.asPath, undefined, { locale: <YOUR_LOCALE>, });
  8. Add set cookie ('NEXT_LOCALE', <YOUR_LOCALE>); (optional)

Generally. I have quite a complex app where we use, phraseInContextEditor, translated data depending on locale from the DB and multilanguage sometimes depending on the ENV. Said that, it now works after around 1 day of work. So I'm sure most applications can be migrated quite easily. Just read carefully the docs and the issues section here.

@samfromaway
Copy link
Contributor

samfromaway commented Jun 3, 2021

@isaachinman If I'd write the manual where should I do it, on the readme?

@isaachinman
Copy link
Contributor

isaachinman commented Jun 4, 2021

@samfromaway No, I think we'd want a separate v8-migration markdown file somewhere, and link to it from the main README.

samfromaway added a commit to samfromaway/next-i18next that referenced this issue Jun 13, 2021
samfromaway added a commit to samfromaway/next-i18next that referenced this issue Jun 13, 2021
isaachinman pushed a commit that referenced this issue Jun 13, 2021
* init

* fix-issue-#1040

* fix: issue-#1040

* fix: init
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

No branches or pull requests