Vercel: Unable to load translations using getServerSideProps/loadTranslations
atanaskanchev opened this issue ยท 10 comments
While the setup works fine running locally, the deployed to vercel app returns empty translations by loadTranslations in getServerSideProps
GET | https://app.vercel.app/_next/data/HZ7wajlS0AuNQGjuW_9so/en/app/dashboard.json
{"pageProps":{"__ni18n_server__":{"resources":{"en":{"dashboard":{},"common":{}}},"ns":["dashboard","common"]}},"__N_SSP":true}
ni18n.config.ts
import ChainedBackend from 'i18next-chained-backend'
import HttpBackend from 'i18next-http-backend'
import LocalStorageBackend from 'i18next-localstorage-backend'
const isBrowser = typeof window !== 'undefined'
const isRunningOnLocalhost = !!process.env['NEXT_PUBLIC_IS_RUNNING_ON_LOCALHOST']
const localePath = '{{lng}}/{{ns}}.json'
export const ni18nConfig = {
supportedLngs: ['en'],
ns: ['common', 'auth', 'dashboard'],
use: isBrowser ? [ChainedBackend] : undefined,
defaultNS: 'common',
fallbackLng: 'en',
backend: isBrowser
? {
backends: [LocalStorageBackend, HttpBackend],
backendOptions: [{ expirationTime: 24 * 60 * 60 * 1000 }, { loadPath: `locales/${localePath}` }]
}
: isRunningOnLocalhost
? { loadPath: `apps/ui-web-app/public/locales/${localePath}` }
: { loadPath: `locales/${localePath}` },
interpolation: {
format: (value, format, lng, options) => {
...
}
}
}
next.config.js
// eslint-disable-next-line @typescript-eslint/no-var-requires
const withNx = require('@nrwl/next/plugins/with-nx')
"i18next": "^21.6.5",
"i18next-chained-backend": "^3.0.2",
"i18next-http-backend": "^1.3.1",
"i18next-localstorage-backend": "^3.1.3",
"next": "12.0.7",
"ni18n": "^1.0.3-rc.0",
/**
* @type {import('@nrwl/next/plugins/with-nx').WithNxOptions}
**/
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true'
})
const nextConfig = {
nx: {
// Set this to true if you would like to to use SVGR
// See: https://github.com/gregberge/svgr
svgr: false
},
images: {
domains: ['cdn.nordigen.com']
},
i18n: {
defaultLocale: 'en',
locales: ['en', 'es']
}
}
module.exports = withBundleAnalyzer(withNx(nextConfig))
const Dashboard: NextPage = () => (
<AuthGuard>
<RoutePermissionsGuard>
<SubscriptionGuard>
<DashboardLayout>
<DashboardPage />
</DashboardLayout>
</SubscriptionGuard>
</RoutePermissionsGuard>
</AuthGuard>
)
export const getServerSideProps = async ({ locale }) => {
const something = {
...(await loadTranslations(ni18nConfig, locale, ['dashboard']))
}
console.log('file: index.tsx ~ line 25 ~ getServerSideProps ~ something', JSON.stringify(something))
return {
props: something
}
}
export default Dashboard
{"i18next": "^21.6.5",
"i18next-chained-backend": "^3.0.2",
"i18next-http-backend": "^1.3.1",
"i18next-localstorage-backend": "^3.1.3",
"next": "12.0.7",
"ni18n": "^1.0.3-rc.0"}
Hi @atanaskanchev, if the prebuilt JSON
is empty it probably means the issue is on the build
step.
I would start looking at the path's configuration after the isRunningOnLocalhost
conditional.
It is possible you don't need the conditional at all, can you try one of the following solutions?
- use
undefined
- use
{ loadPath: `apps/ui-web-app/public/locales/${localePath}` }
- use
{ loadPath: `locales/${localePath}` }
If none of these work, would you mind creating a repository where with the reproducible behaviour where I can try to find a solution?
Hi @JCQuintas thanks for the quick response.
I've recreated the issue here https://github.com/atanaskanchev/ni18n-nx-issue and it's deployed to https://ni18n-nx-issue-9y6puo3xe-atanaskanchev.vercel.app/dashboard
In the config, if !isRunningOnLocalhost
I am setting the locales path { loadPath: locales/${localePath}
} and it seems it matches the vercel workspace
backend: isBrowser
? {
backends: [LocalStorageBackend, HttpBackend],
backendOptions: [
{ expirationTime: 24 * 60 * 60 * 1000 },
{ loadPath: `locales/${localePath}` },
],
}
: isRunningOnLocalhost
? { loadPath: `apps/ni18n-nx-issue/public/locales/${localePath}` }
: { loadPath: `locales/${localePath}` },
So it seems when deploying to vercel, we don't have access to the public
folder from the getServerSideProps
. :(
The current behaviour work if you are deploying using a docker
container though... I've opened a bug issue on nextjs
repo and will keep you posted.
A quick solution for your case right now would be to use getStaticProps
instead for the time being, or use clientNamespaces
to have the translations loaded on the client only.
Hi @JCQuintas I've had a try with v1.0.4-rc.3
but it seems the issue with Vercel still persist.
Indeed, it didn't work. Looking at it deeper, it seems that the issue is on the https://github.com/vercel/nft packager that doesn't allow a "third party module" to flag a file as "necessary" out of its scope. So at the moment we can't really fix that automatically without creating a patch to the nft package and then waiting for vercel to update it.
In the meantime, one workaround would be to create a function on your repository to do that for us
// force-locales-packing.js
import path from 'path'
export const forceLocalesPacking = () => path.join('./public/locales')
Then you should be able to run that inside your getServerSideProps
and it will "tag" the files to be bundled. I intend on creating a documentation for this as well as soon as I have time. Then I try to work on a fix on the nft
package itself.
Let me know if it works for you, else I can update the repo you linked above with the steps necessary to make it work.
This worked for me.
import type { NamespacesNeeded, Ni18nOptions } from 'ni18n';
import { loadTranslations as ni18nLoadTranslations } from 'ni18n';
import path from 'path';
import { i18n } from '../../next.config';
export const namespaces = [
'common',
'register',
'dashboard',
'sidebar',
] as const;
export const ni18nConfig: Ni18nOptions = {
supportedLngs: i18n?.locales,
ns: namespaces,
};
export const loadTranslations = async (
initialLocale?: string | undefined,
namespacesNeeded?: NamespacesNeeded | undefined
) => {
const locales = path.resolve('./', './public/locales');
return await ni18nLoadTranslations(
ni18nConfig,
initialLocale,
namespacesNeeded
);
};
Has anyone found a solution to this?
Has anyone found a solution to this?
This solved my problem #49 (comment)
const locales = path.resolve('./', './public/locales');
Hi @zaniluca, the main issue is on how the nft
package decides which file to bundle or not. A discussion regarding that can be found here: vercel/nft#77
I haven't had the time to look at that more in depth and propose a solution, but in the meantime, the solution provided by @RodriguesCosta should work.
Any solution on that?