next-translate
next-translate copied to clipboard
next-translate-plugin breaks SSG in app router
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?
@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.
@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
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
I'm having the same problem
@jakubjanousek Can I share your useTranslation
implementation code?
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.
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 })
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.