next-translate icon indicating copy to clipboard operation
next-translate copied to clipboard

next-translate-plugin breaks SSG in app router

Open jakubjanousek opened this issue 1 year ago • 7 comments

What version of this package are you using? 2.6.0

What operating system, Node.js, and npm version? node v20.4.0

What happened? Once next-translate-plugin is used in next.config.js, pages cannot be statically generated in app router. There is nothing dynamic on the page or layout

module.exports = nextTranslate(); results in ┌ λ / 5.35 kB 85.8 kB module.exports = {} results in ┌ ○ / 5.25 kB 85.6 kB

λ  (Server)  server-side renders at runtime (uses getInitialProps or getServerSideProps)
○  (Static)  automatically rendered as static HTML (uses no initial props)

i18n.json is

{
  "locales": ["en"],
  "defaultLocale": "en",
  "pages": {
    "*": ["common"]
  }
}

Any ideas why this is happening? You can check a minimal example at https://github.com/jakubjanousek/next-translate-ssg-issue

What did you expect to happen? Pages without getServerSideProps will be statically generated with yarn build

Are you willing to submit a pull request to fix this bug?

jakubjanousek avatar Oct 10 '23 15:10 jakubjanousek

@aralroca I found the same issue recently when I started to migrate pages from pages to app. The first page I migrated was a static page so I simply used a export const dynamic = "force-static"; to deal with it.

Right now I started to migrate pages with translations and this is definitely a bigger issue given that any page I migrate will be dynamic because of next-translate. Are we missing something with the next-translate configuration?

Edit: I found the culprit, I tried to remove props.searchParams?.lang by hand and the problem was gone.

The usage of searchParams will make all the pages dynamic, searchParams is a Dynamic API whose values cannot be known ahead of time. Using it will opt the page into dynamic rendering at request time.

I don't know what would be the alternative given that I'm not deep into the possible ramifications.

hensansi avatar Oct 12 '23 10:10 hensansi

@jakubjanousek @aralroca this is not a (final) solution but it displays where the problem is with the given repo, https://github.com/hensansi/next-translate-ssg-issue/commit/f1d1aad454b046d749568c4ff1b2f9a2ca739d48

   Creating an optimized production build  .Route (app)                              Size     First Load JS
┌ ○ /                                    5.35 kB        85.8 kB
└ ○ /_not-found                          884 B          81.3 kB
+ First Load JS shared by all            80.4 kB
  ├ chunks/738-70faf364855414b4.js       27.5 kB
  ├ chunks/fd9d1056-9c5946da9b5f2b9d.js  51 kB
  ├ chunks/main-app-ab8e99cf22ecae19.js  230 B
  └ chunks/webpack-396734a053f7bdbb.js   1.75 kB

hensansi avatar Oct 12 '23 12:10 hensansi

good catch @hensansi, unfortunately I am not familiar with the reasons why searchParams is there

for now, we have removed next-translate-plugin and created custom useTranslation that just directly calls transCore with statically imported translation file

this allows us to have SSG by default while keeping all of the next-translate interface, but it is a very specific use case, since each of our languages is a single site that knows its locale at build time

jakubjanousek avatar Oct 13 '23 07:10 jakubjanousek

I'm having the same problem

@jakubjanousek Can I share your useTranslation implementation code?

kkak10 avatar Oct 13 '23 09:10 kkak10

for now, we have removed next-translate-plugin and created custom useTranslation that just directly calls transCore with statically imported translation file

@jakubjanousek Could you please share the code snippet or implementation details for this? It would be greatly helpful to understand how you integrated this into your setup.

astorozhevsky avatar Dec 12 '23 11:12 astorozhevsky

Our situation is a bit specific that we have several deployment, but each has only a single translation. Therefore we are able to copy only the necessary translation before starting the server into current

a simplified version is something like this

import transCore from 'next-translate/transCore'
import currentLocale from 'locales/current/main.json'
import { Translate } from 'next-translate'

const lang = process.env.LOCALE || 'en'

const tWithoutNs = transCore({
  lang,
  config: {
    locales: [locale],
    defaultLocale: locale,
    defaultNS: 'main',
    loader: false,
    pages: {
      '*': ['main'],
    },
  },
  pluralRules: new Intl.PluralRules(lang),
  allNamespaces: { main: currentLocale as any },
})

export const getTranslate = () =>
  ({
    t: (key: string, query?: any, options = {}) => {
      return tWithoutNs(key, query, { ns: 'main', ...options })
    },
  } as { t: Translate })

jakubjanousek avatar Jan 05 '24 20:01 jakubjanousek

Our situation is a bit specific that we have several deployment, but each has only a single translation. Therefore we are able to copy only the necessary translation before starting the server into current

a simplified version is something like this

import transCore from 'next-translate/transCore'
import currentLocale from 'locales/current/main.json'
import { Translate } from 'next-translate'

const lang = process.env.LOCALE || 'en'

const tWithoutNs = transCore({
  lang,
  config: {
    locales: [locale],
    defaultLocale: locale,
    defaultNS: 'main',
    loader: false,
    pages: {
      '*': ['main'],
    },
  },
  pluralRules: new Intl.PluralRules(lang),
  allNamespaces: { main: currentLocale as any },
})

export const getTranslate = () =>
  ({
    t: (key: string, query?: any, options = {}) => {
      return tWithoutNs(key, query, { ns: 'main', ...options })
    },
  } as { t: Translate })

@jakubjanousek Thank you so much for sharing your code and approach. In the end, we switched to using next-intl which solved our problems.

astorozhevsky avatar Jan 08 '24 04:01 astorozhevsky