i18next / next-i18next

The easiest way to translate your NextJs apps.

Home Page:https://next.i18next.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

`next export` does not work

tizzle opened this issue · comments

Describe the bug
When doing a next export to built a static page, i get the following error:

TypeError: Cannot read property '0' of undefined
    at /Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/next-i18next/dist/hocs/app-with-translation.js:155:68
    at Array.filter (<anonymous>)
    at _callee$ (/Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/next-i18next/dist/hocs/app-with-translation.js:154:61)
    at tryCatch (/Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/regenerator-runtime/runtime.js:62:40)
    at Generator.invoke [as _invoke] (/Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/regenerator-runtime/runtime.js:288:22)
    at Generator.prototype.(anonymous function) [as next] (/Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/regenerator-runtime/runtime.js:114:21)
    at asyncGeneratorStep (/Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _next (/Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/@babel/runtime/helpers/asyncToGenerator.js:25:9)
    at /Users/tillhinrichs/Documents/_DEVELOPER/HTML/CleanCleanShop/cc-next2/node_modules/@babel/runtime/helpers/asyncToGenerator.js:32:7
    at new Promise (<anonymous>)

To Reproduce
Steps to reproduce the behavior:

  1. Clone or download this repository
  2. In terminal do cd example
  3. Install dependencies: yarn
  4. I had to install next-i18next as well: yarn add next-i18next
  5. Check if it runs in dev: yarn run dev -> Works
  6. Check if it builds: yarn run next build -> Works
  7. Check if it exports: yarn run next export -> Fails

Expected behaviour
A static version of the app/page should be built.

OS (please complete the following information):

  • Device: MacBook Pro (15-inch, 2017)
  • Browser: Chrome Version 70.0.3538.110

Interesting issue. I protected a couple of the language logic areas with simple if statements and got export working just fine.

That said, this project isn't really friendly to next export as it specifically requires some server side logic to detect language, fetch translation files, and so on. There's no way to do SSR translations without some server logic.

I'm curious as to how you expected this to work? Perhaps I'm missing something?

The only workable "solution" I can think of is to have the server render nothing, and the client can successfully fetch translated content as needed. This would depend upon NextJs exposing some sort of env var to indicate that an export is being run.

Hey @isaachinman,

Thanks for your prompt reply and for the great work on all things i18next.

My maybe naïve expectation was, that the export would write translated strings to static html. The resulting app/site would then have a set of pages for the defaultLanguage and another set of pages for every additional language inside a lang-folder (e.g. de).

I'm pretty sure there once was a react-i18next example for nextjs that exported like that.

But thinking about it a little more, i see that language switching might prove a bit tricky in that scenario in terms of keeping the route and not linking to /.

I will search for that example and see if it really exports as described above.

Thanks again and best regards!

Till

Ah, I see. That would indeed be very cool. I see two main problems with that:

1. Too opinionated

This approach would really only work with the localeSubpaths routing paradigm, which is a very opinionated approach, and just one way to handle routing with languages. Many people prefer subdomains, query params, and so on. It would be a big investment of development time for a feature that only helps a small portion of people

2. Requires build-step changes

This would also require serious build-time changes, as we'd need to essentially run next export n times, wherein n is your number of locales, each time somehow injecting that locale into the build process so we know which language to render, and then putting that out content into a subdir. I'm not entirely sure that's even possible, and if it was it'd certainly require some complex webpack overrides that I'd rather not get into.

All of that said, if you can find that example I would be very interested to see the approach. Regardless of all of this, I think I can get next export working in a way where the server delivers an empty page, and the client will pick it up. This is certainly not a real solution, but at least it will degrade gracefully.

Let me know what you think.

@tizzle I added my initial thoughts on a branch called support-next-export.

The aforementioned graceful degradation of SSR seems to be working fine. However, I realised that of course the localeSubpaths functionality won't work after an export, as the subpaths no longer exist, because we're not running an express server. I thought Next might do some fancy stuff and generate static routes based on our server.get calls, but that's not the case.

In short, it's sort of a lose-lose. I need to think awhile on this. Regardless of how we proceed, it will definitely be important to include this information in the README. My initial feeling is that we should just not support next export at all.

the react-i18next sample had a working export but that did not generate files per language - just the client did fetch the missing translations from /static/ and rendered (no server - no SSR)

edit: And yes - no subpaths at that time

Hi @isaachinman,

i think nextjs leaves the custom path definitions for exports to the user. There is a thing called exportPathMap you can put into next.config.js.

You can see this in action here: https://github.com/zeit/next.js/blob/canary/examples/with-static-export/next.config.js

For next-i18next this would be the place where the localeSubpaths had to be added. As i see it, this would definitely mean some manual work on the users' side and thus making the super minimal setup of this package more complex.

I also think the aforementioned static export example that worked as i expected made heavy use of this.

Maybe this helps to provide some export capabilities. I will also think about this a bit more.

@jamuhl Then, that is exactly what is achieved on the support-next-export branch.

I suppose we can merge this if users really want it, but it seems like it misses the entire point to me. Also, if you want to have a static translated website with NextJs, you might as well just create all the routes manually with the content directly inside the React components, and do a next export - basically don't use i18next at all...

@isaachinman yes...misses the point - at that point (😄) in react-i18next sample i wasn't in the mood anylonger to argue about it making sense -> just let them do the export and have that clientside react app ;)

Hey @isaachinman and @jamuhl,

i totally agree with you that the benefits of a static export are very small. Maybe a prominent statement in the README would be enough to make this clear. Feel free to close. Thanks for your discussion.

This is fixed with #15.

Now, doing next export in a next-i18next project will result in a clientside-only React application.

No future plans to support any kind of custom export process with locale subdirs.

commented

If someone full export:
Those two issues contain some hints:
vercel/next.js#2665
vercel/next.js#5509

@isaachinman Is this (particularly getStaticPaths) any help here? vercel/next.js#9524

@balazsorban44 Yes, I believe getStaticPath could be used to aid the static generation of next-i18next apps.

I will try by myself, but if you have a good idea of how this could be achieved, I would be happy to look at your take! 🙂

@balazsorban44 Yes, I believe getStaticPath could be used to aid the static generation of next-i18next apps.

Will be nice to see any example of this!

@isaachinman I have a different problem here. But I think it's related.
When I use next build & next start everything is ok.
But, when I use next export, it builds without exit code thus it has errors on browser console and the translation is not working fine.
While Next is trying to run the export command, logs this:
Exporting (0/15)react-i18next:: i18n.languages were undefined or empty undefined.
Any idea on that?

My workaround for SSG (next export) app with next-i18next (Next v10):

  1. Setup according to the Get Started guide by next-i18next
  2. Remove i18n in next.config.js
  3. Move pages/index.js (or any page except _app and _document) to pages/[[locale]]/index.js
  4. Add getStaticPaths like this:
export async function getStaticPaths() {
  return {
    paths: i18n.locales.map(locale => ({ params: { locale } })),
    fallback: false,
  }
}
  1. Change getStaticProps to be like this:
export async function getStaticProps({ params }) {
  const locale = params?.locale || i18n.defaultLocale
  return {
    props: {
      ...await serverSideTranslations(locale, ['common']),
    },
  }
}
  1. Now it should work on both next dev and next build && next export when you navigate to pathname /en (or any other locale you specified)
  2. To get / redirect to /en on client-side (or any other default locale), add the following pages/index.js:
import { useRouter } from 'next/router'
import { i18n } from '../next-i18next.config'

const HomeFallback = () => {
  const router = useRouter()
  // Make sure we're in the browser
  if (typeof window !== 'undefined')
    // @TODO: Use locale on localStorage / browser preference
    router.replace(`${i18n.defaultLocale}/${router.pathname}`)

  return null 
}

export default HomeFallback 

Checkout my sample repo: michchan/next-i18next-ssg-workaround@0caac9e