Currently next-i18next does not support serverless. It appears that the i18n-middleware create some troubles when used on lambda #271
Not sure exactly what would be the final solution but:
None.
Open to suggestion for the work/final solution to be done/achieved.
A few things to consider - just my initial thoughts:
i18next-express-middleware gives us? See https://github.com/isaachinman/next-i18next/issues/9#issuecomment-443274069I am open to any/all suggestions on this topic, but in general regard it as a major refactor of the project from the ground up. If we can remove our dependency on Express/i18next-express-middleware, I think the package would become a lot more versatile.
However, I am not (currently) doing any work whatsoever with serverless NextJs, and have very little input to add here.
I've gotten next-i18next working in a serverless environment for one of our sites we're building right now (no full source available unfortunately), but it's pretty hacky because we're basically stitching together various parts from next-i18next in a more vanilla i18next setup.
Our approach is that we basically ship the JSON files once to a CDN (with an assetPrefix) and once inside the Lambda "executables". We reference them via import which makes them real Webpack chunks for the CDN and also allows it to pick them up and include them when packaging the serverless file and we're also running express infront of the bundles so the middleware can just be dropped. I can't really recommend this approach, but it can definitely work.
@beheh Sounds like you had some fun. Are there any lessons or approaches you'd like to bring back to next-i18next? Being able to support serverless is the eventual goal.
Stumbled upon this issue because I'm researching for a new NextJS project that should have i18n and is planned to be deployed to Now 2.0. I've not used next-i18next yet, nor am I a serverless/now expert, but if someone has some smart ideas I'm willing to help with the implementation.
@yoeran I think the right place to start is rewriting/adapting i18next-express-middleware to use vanilla NodeJs HTTP interfaces instead of relying on Express.
Would also appreciate it if someone has the knowledge to optimize the package for serverless solutions.
[RFC] serverless is still open (https://github.com/zeit/next.js/issues/7208). The last entry mentions that a routing middleware is still missing in the current version of Next. Tracking the progress there is a merge request with the title "Example for API routes with middleware" https://github.com/zeit/next.js/pull/7958/files . I do not know anything about the internal of the express middleware currently utilized by next-i18next, but maybe the example shown in the merge request is enough to start a migration.
@gurkerl83 That example appears to show how one could use middleware on an API route, not a UI route.
My request sounds different from the original title but I assume it's related cause it's also about reusing the module outside of next execution context. Sorry if I'm wrong though.
We have a successfully working Next.js project using your next-i18next (thanks!).
Now I _also_ want to create a stand-alone node.js script that would reuse the entire infrastructure we already have and do some interpolations (in the static HTML files if you're curious).
For some reason (I have my brain kinda broken after hours of trying) it doesn't work.
Here's what I'm doing:
const nextConfig = require('next/config');
nextConfig.setConfig(require('./next.config'));
const { i18n } = require('./i18n');
And then trying to use i18n.t directly. I see that it's getting _all_ the proper configs but does not load the data from the JSON files.
And thus an attempt to translate any key returns the key itself.
I'm trying to figure out what else next is doing behind the scene that makes your module fetch the needed JSON data and that I'm missing.
For ref, ./i18n is pretty standard:
const NextI18Next = require('next-i18next').default;
const i18nHelper = require('./lib/i18nHelper');
module.exports = new NextI18Next({
localePath: 'static-src/locales',
defaultLanguage: i18nHelper.getDefaultLanguage(),
otherLanguages: i18nHelper.getOtherLanguages(),
fallbackLng: i18nHelper.getDefaultLanguage(),
defaultNS: i18nHelper.getDefaultNamespace(),
fallbackNS: i18nHelper.getAllNamespaces(),
ns: i18nHelper.getAllNamespaces(),
localeSubpaths: 'foreign'
});
And I can confirm that all the i18nHelper methods are returning what expected.
@emirotin That's not something we're going to support. Unfortunately you'll need to go it alone. I would suggest simply initialising a normal i18next instance. Note that you can pass your identical next-i18next config object into the i18next.init function.
Let's keep this discussion on topic.
Sorry for offtopic then. I truly assumed it's about the same root.
Just curious what's wrong with my current setup that makes it unusable?
P.S. ~barebones i18next doesn't work for me (yet) too~ normal i18next works!
It seems possible to spoof this with the following in a custom _app.js
import {handle} from 'i18next-express-middleware';
import {i18n, config} from '../i18n';
export default extends App {
// ...
static async getInitialProps(context) {
if (context.ctx.req && context.ctx.res) {
res.set = res.setHeader;
req.path = context.ctx.asPath;
const i18nHandler = handle(i18n, {ignoreRoutes: config.ignoreRoutes});
await new Promise((resolve, reject) => {
try {
i18nHandler(req as any, res as any, resolve);
} catch (e) {
reject(e);
}
});
}
}
// ...
}
Hopefully ZEIT follows through with adding middleware capabilities, and we can easily add this that way
If this is something you are cool with (and actually works? I'm still testing this), I can throw up a PR to introduce a helper function (plus some documentation)
@aequasi Not sure that'd work. The req and res objects that come off Next's context are vanilla HTTP interfaces, not Express req and res interfaces. What have you seen in your testing?
Because there are so many diverse use cases for this package, I'd rather we proceed in the least hacky way possible. We do have support from the Next team and they're aware of the request for serverless middleware.
The two express specific things (set and path) can easily be "mocked"
set actually needs to be:
req.set = (key, value) => {
if (value !== undefined) {
res.setHeader(key, value);
}
}
From my testing, this works. I'm not having any issues with server-rendered content
To reiterate, I'd rather we proceed in the least hacky way possible. This means we need to:
i18next-node-middlewarenext-i18next accordinglyIf people want to roll their own serverless solutions in the meantime, feel free.
@aequasi nice temporary solution 🤔 But I guess locale subpaths is not working, right?
UPD: yes, server-side locale subpaths is not working (naturally), but it seems fine on the client. I got client-side translations working so far without particularly critical bugs, but it can't work on Zeit Now serverless 🤔
Monkey patching all incoming requests in _app.jsx is not a best way to get things working, so as @isaachinman mentioned - we need to wait for serverless middlware support in Next.js 😞

Zeit compiles everything that it can find from static analysis into a single file. If i had to make an educated guess, the locales are not making it to the deployment, causing the fs.readdirSync to fail. You could look into: https://zeit.co/docs/v2/advanced/builders/overview#including-additional-files
@aequasi I experienced the same error when a deployment with now get executed. With your last comment, do you mean specifying i18n-resource files within the includeFiles section of now deployment configuration (now.json) will resolve the fs.readdirSync error?
@gurkerl83 nope, just tested it with both static and custom folder with custom localePath. Tried to use include in now.json, but no luck.
Regardless of whether or not you want to get this done in a hacky way, doing this research ahead of time makes refactoring take less time, as you know what will have to change.
includeFiles added the locales to the deployed code, but you need to go a step further.
On now deployments, process.cwd() isnt the right directory to pull from, and the now team has said to use __dirname instead.
Setting localePath to path.join(__dirname, '/static/locales') (or whatever your path is), seems to fix that initial fs.readdirSync issue. This could also be mitigated by forcing the developer to define all namespaces by hand, instead of grabbing it automatically.
After i got past that error, i got stuck on another one for a bit that was a little harder to debug, due to the evals in the repo
Unable to import module 'now__launcher': Error
at Function.Module._resolveFilename (module.js:547:15)
at Function.Module._load (module.js:474:25)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at eval (eval at _default (/var/task/page.js:52306:32), <anonymous>:1:1)
at _default (/var/task/page.js:52306:32)
at new NextI18Next (/var/task/page.js:201598:51)
at Object.<anonymous> (/var/task/page.js:56634:27)
at Object.KbPy (/var/task/page.js:56793:30)
at __webpack_require__ (/var/task/page.js:23:31)
The eval thats at the line above is:
var _default = function _default(config) {
if (!_i18next["default"].isInitialized) {
if (_detectNode["default"]) {
+ var i18nextNodeBackend = eval("require('i18next-node-fs-backend')");
var i18nextMiddleware = eval("require('i18next-express-middleware')");
_i18next["default"].use(i18nextNodeBackend);
if (config.serverLanguageDetection) {
var serverDetectors = new i18nextMiddleware.LanguageDetector();
config.customDetectors.forEach(function (detector) {
return serverDetectors.addDetector(detector);
});
_i18next["default"].use(serverDetectors);
}
// ...
Something about now doesn't like the eval("require('i18next-node-fs-backend')");.
@aequasi Do you have a fork of next-18next to share respectively an example which demonstrates/summarises the changes you described.
About your last comment, maybe deploying next in serverless mode does not understand the result of eval statements in combination with loading resources through require. Are those statements replaceable through dynamic import statements?
It will be awesome if this library is useable in a serverless deployment mode without the requirement to have a middleware provided by next in the short term. Regular observations of both middlewares (next serverless - for several months in the RFC state) and express i18next-express-middleware (migration to support pure Http instead of express) have currently zero attention.
I dont. Was able to get there with this:
import * as common from '@static/locales/en/common.json'; // Wherever you have your common locale
export default new NextI18Next({
browserLanguageDetection: false,
serverLanguageDetection: false,
partialBundledLanguages: false,
defaultLanguage: 'en',
ns: ['common'],
defaultNS: 'common',
otherLanguages: ['en'],
resources: {
en: {common},
},
localeSubpaths: 'none',
localePath: path.join(__dirname, 'static', 'locales'), // Wherever you have your common locale
});
For anyone wanting to help: @jamuhl has let us know in https://github.com/i18next/i18next-express-middleware/issues/186 that it should be fairly easy to refactor out the dependency on Express.
This would be a great first step, and will benefit the greater i18next community, not just next-i18next.
I've taken a look myself and submitted a PR to remove Express as a dependency from i18next-express-middleware here: https://github.com/i18next/i18next-express-middleware/pull/191.
Reviews, manual QA, and feedback would be much appreciated.
It's kind of strange to retain "middleware" in a vanilla NodeJs environment, but I do think it's the best way forward.
Once this is ready to merge, I think we'll need to deploy an entirely new repo called i18next-middleware (or similar).
From there, the next piece of work will be refactoring the Express dependency out of next-i18next itself. At that point, serverless as well as use with Koa/Hapi should be possible with a little bit of added work from users.
Am struggling with this issue and wondering when this will get fixed.
What's the workaround ?
@rdewolff The problem, approach, and work necessary are all quite well-documented in this issue and the related ones in i18next repos. You can feel free to contribute!
Hi, just a short update on that issue. The work necessary to fix that issue is
Further experiments have to be conducted to identify pathways around some limitations currently introduced. Some topics have to be discussed, such as the express session handling, integrated into the i18next-express-middleware library we have to loose in a vanilla Http based setup.
What is next? Some investigation in open issues, code cleanup. I will push the changes I have made to i18next-express-middleware and next-18next to different repositories. The naming of repositories was changed because of publishings to Npm required for testing. As soon those things are up, I will prepare those merge requests.
With those adjustments I was able to deploy next-18next example with now V2 in serverless mode (Production build). Some prove...
https://millipede-docs-simple-29i7s3up8.now.sh/
Thx,
@rdewolff The problem, approach, and work necessary are all quite well-documented in this issue and the related ones in i18next repos. You can feel free to contribute!
I have tried the solutions provided here and I could not make it work. Tried applying the the i18n config, localeSubpaths seems complaining for not having an object but a string. When commenting that out, I get one step further, but the following error occurs :
/[...]/web/node_modules/next-i18next/dist/commonjs/config/create-config.js:54
throw new Error("Default namespace not found at ".concat(defaultNSPath));
^
Error: Default namespace not found at /[...]/dev/static/locales/en/common.json
at _default (/[...]/node_modules/next-i18next/dist/commonjs/config/create-config.js:54:15)
at new NextI18Next (/[...]/node_modules/next-i18next/dist/commonjs/index.js:52:46)
at Object.<anonymous> (/[...]/i18n.ts:5:14)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Module.m._compile (/[...]/node_modules/ts-node/src/index.ts:473:23)
at Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Object.require.extensions.(anonymous function) [as .ts] ([...]/node_modules/ts-node/src/index.ts:476:12)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
Is there a fallback to run it without serverless? Am searching the next.js doc but cannot find the info. Even when commenting out target: "serverless" in next-config.js I get the same results.
Tried all the combination I could think of but 👎 - not working. Anyone could provide the source code / sandbox of the working version ? That'd be of great help! Thanks in advance!
Is there any update, another issue to follow status, or package alternative? Thank you!
@michaviehauser Still need to get the middleware bit done first. There is no alternative whatsoever, to my knowledge. Feel free to contribute.
👀 [RFC] Custom Routes https://github.com/zeit/next.js/issues/9081
Hi, just a short update on that issue. The work necessary to fix that issue is
- Port the dependency i18next-express-middleware from express to vanilla Http (Node). I have a local branch on which I have worked on for some time.
- Small portions of next-18next have to be adjusted, including the file next-i18next-middleware.ts and some others. We can keep the example next application, which is built on top of express or provide a new one. On a local branch of next-18next, those adjustments, including the example, are made. The example supports NextJs in serverless deployment mode, especially for production build with now V2.
- Middleware support from Next. I have adjusted the example of next-18next by including a _document file which accesses the document middleware of NextJs which they already provide. The next-18next middleware gets consumed there.
Further experiments have to be conducted to identify pathways around some limitations currently introduced. Some topics have to be discussed, such as the express session handling, integrated into the i18next-express-middleware library we have to loose in a vanilla Http based setup.
What is next? Some investigation in open issues, code cleanup. I will push the changes I have made to i18next-express-middleware and next-18next to different repositories. The naming of repositories was changed because of publishings to Npm required for testing. As soon those things are up, I will prepare those merge requests.
With those adjustments I was able to deploy next-18next example with now V2 in serverless mode (Production build). Some prove...
https://millipede-docs-simple-29i7s3up8.now.sh/
Thx,
@gurkerl83
Could you please share how you got it running on Now2.0? Sample repo link to your site would be great
👀 [RFC] Custom Routes zeit/next.js#9081
is this middlewares,but with another name, or will it not be possible with this RFC ?
I made Next.js (serverless mode v9.1.2) work with Locize and documented it there:
https://stackoverflow.com/questions/55994799/how-to-integrate-next-i18next-nextjs-locize/58782594#58782594
Hey @Vadorequest, nice!
However, lots of people use next-i18next with translations that are loaded over network from another CDN/API, and you could also bundle your translations into your serverless deployment, etc.
It's certainly possible with next-i18next, we just need someone to take the lead!
Also, I think it would be great if you wrote about your experience in an article on Medium.
+1 for the article on Medium. Thought the same while reading your post on SO.
Hear you, we've got a tech blog on medium at https://medium.com/unly-org/tech/home where you may find some interesting stuff already. But I've got very little time for a medium article right now.
I'm in the process of releasing a Next+Now boilerplate with Locize (and tons of other stuff) production-grade for very quick start, it's not yet ready, been working on it for 2w+. I'll drop the link here when it's released, if you're interested. :)
@gurkerl83 seems to have a working solution. Is there an ETA for the release of his solution and how can others help out to speed up the process?
Also wondering if there is already work being done towards creating a next.js plugin of this to have a clean support for serverless?
@BjoernRave It's been a week or two since I checked on the plugins RFC but as far as I know, it's nowhere near ready for third party dev.
Did you have something in mind?
Indeed, a plugin is probably the future of this package, but that doesn't solve the i18next-express-middleware dependency issue.
@isaachinman ah, so at first we need to port i18next-express-middleware to a version which is not depending on express to have a next.js plugin?
Yea, true I guess it's not yet ready for third-party devs, I just can't wait anymore, so I thought maybe someone is already playin around with what the next.js team is providing at this point. There is already a first version of it under an experimental flag
Yes, basically we either need:
req, res, and a few other thingsThat being said, I know Tim did prioritise maintaining at least a little bit of parity with commonly-used Express features, so it might end up being pretty much drop-in.
@BjoernRave If you'd like to work on this together, please feel free to email directly.
okay, yea not sure I am much of a help here.
@Vadorequest but that means we need to use locize, right? why is it working with locize, but not without, since your are still using i18next?
@gurkerl83 I would also be very interested if you got something, please share it with us :)
@BjoernRave It's working with Locize and not without because of the backend implementation. I won't go too far into the technicals, but let's just say the Locize implementation was easier to work with. (yet, wasn't THAT easy either, hence the SO post)
But, definitely usable with any tool, the main "difficulty" at hand is to build a universal backend, because Next needs universal compatibility. (node + browser)
I would assume that the most desirable way to consume localisation data in serverless deployments is via a third-party CDN, where caching occurs both at the CDN and server levels.
@isaachinman @Vadorequest there is a big "drawback" with serverless -> the serverless function does not cache the loaded translations like a hosted express server can -> this means every time the serverless function is called to render a page all the namespaces get loaded from the CDN:
that's why we got that "FAT" warning here: https://github.com/locize/i18next-node-locize-backend#important-advice-for-serverless-environments---aws-lambda-google-cloud-functions-azure-functions-etc
is zeit now not caching the translations with SPR ? BUt yeah as stated in the docs, it probably makes the most sense to just keep the translations inside the build, like it's already done with next-i18next(? I think :D)
@BjoernRave never looked into that...the drawback I described applies if there is no page level caching done (which seems to be the case for zeit now)
In my opinion, a server which hopes to perform server-side localisation should hold translation data in memory wherever possible. It makes no difference if that data is loaded into memory from a filesystem or CDN, but if neither option is available then you have a problem.
@BjoernRave The next-18next package makes no assumptions about that, it just exposes the full i18next ecosystem/options. Using the filesystem is the default behaviour though, yes.
Yeah, I can tell the calls from the server are done quite frequently without any caching from my next server.
I wonder what viable alternatives are available.
@Vadorequest I am desperately looking for any solution so I can finally enjoy the easiness of deploying to now again :D sad that your solution involves having to pay for locize. I am hoping for gurkler83 to awake from the dead again :D
Well, at least it's not so expensive.
But you could also just use something else, like airtable, basically hit a free 3rd party API to fetch your data so that it doesn't cost you anything. Locize isn't too expensive if you don't have much translation, and their in-context editor is a must-have for proper translation work.
Update: following https://github.com/i18next/i18next-express-middleware/pull/199, it should be possible to run next-i18next without any dependency on Express.
@isaachinman that's great news, did you already try it?
@BjoernRave Yes, I was able to get the simple example running without Express installed.
@isaachinman ah, but you still have the custom server? Shouldn't this make it possible to support serverless?
@isaachinman so we need to release a new package without the express dependency? it's not possible with the current one, although express is not needed anymore, since it's still a dependency right? (Sorry, I am not a super expert in all this, but I try to learn)
Hi, I have pushed my changed onto a different repo, very dirty right now, sorry! My plans for the upcoming weekend are to re-create the following commit from scratch fully. https://github.com/gurkerl83/next-i18next-serverless/commit/7b4b1f4d76e18bfbba7d74516f65506d5d975110 .
Right now, the commit has a typescript version of i18next-express-middleware in vanilla http and middleware applied to next-i18next. Maybe this helps a bit. A deployed version is next-i18next-serverless.
Fully applied it looks like https://github.com/project-millipede/millipede-docs
@gurkerl83 at the moment I am using your next-i18next-serverless library. What is the status on this?
@jamuhl Serverless doesn't spawn a new container on every page request. If it did, there would be cold starts on every request.
Its still definitely possible to cache in memory with serverless infrastructure.
Simple proof:
https://test-is88j4mop.now.sh/api
/api/index.js
var counter = 0;
module.exports = function (req, res) {
counter++;
res.send(counter);
};
@aequasi but you got no control over container life duration or amount of containers spawned...at least that is the case for AWS lambda...must not cause issues - but can.
The problems you would get with next-i18next serverless are then exactly the same than the ones of serverless: from times to times, it can be slower.
So I guess it should be perfectly fine as this is a known trade-off (serverless does not improve speed, but server management). Unless I am missing something?
@gurkerl83 Hey, how are you doing with this? Is there anything I could maybe help you with? I mean it's kind of usable in the current state, would just love it if you wouldnt see the translation keys during loading
Just finding the thread now and I appreciate a lot of work has already taken place. Is anyone rolling with a stable-ish tactical solution that avoids the express dependency?
@gurkerl83 Hey, how are you doing with this? Is there anything I could maybe help you with? I mean it's kind of usable in the current state, would just love it if you wouldnt see the translation keys during loading
Started to work on this again, so far translation keys are gone, see http://millipede.me. This week Next made runtime config (publicRuntimeConfig and serverRuntimeConfig) to serverless target. See https://github.com/zeit/next.js/issues/10395
With these changes, it is possible to pass the project's root directory path in the next-18next config and replace process.cwd() with it. This approach resolves the mentioned problem from above with fs.existsSync
publicRuntimeConfig: {
rootDir: __dirname
}
A very interesting finding is that wrapping a next application (extending from Next App) in next-18next appWithTranslation hoc converts each page in a dedicated Lambda function. In theory, higher-order components are lamdas but in the wild and what Now is doing when deploying an application, just crazy!
@gurkerl83 hey, that's great news. I have some questions:
i18n.js file from the example of the temporal save branch?publicRuntimeConfig: {
PROJECT_ROOT: __dirname,
},, do I also need the experimental: { documentMiddleware: true }, ?@gurkerl83 hey, that's great news. I have some questions:
- Can I just copy the
i18n.jsfile from the example of thetemporal savebranch?- I guess for the above to work I need
publicRuntimeConfig: { PROJECT_ROOT: __dirname, },, do I also need theexperimental: { documentMiddleware: true },?- What is the status on language detection? You disabled everything related to it, is it because it's not working or because you don't want to use it?
I have to push my changes to the branch first (it will be there in two hours).
If you want this working In your project you need the following dependencies.
"next": "^9.2.2-canary.12",
"next-i18next-serverless": "^1.1.123",
Installation:
npm i next-i18next-serverless ~@canary~ next@canary --save
or yarn add next-i18next-serverless ~@canary~ next@canary --save
NOTE: If you want to try serverless version, which is certainly not stable please install without the canary tag!!!
Remove document middleware and configuration for it because it is not required anymore.
See the following commit which applies those changes in my project.
https://github.com/project-millipede/millipede-docs/commit/be232a85584f6bd5f2c38a3835af738f4e81f495
For language detection I have to do more tests, especially the middleware part.
Hope this helps
@gurkerl83 yeah, that helps a lot, thanks I will wait until tomorrow then.
I think you need to clean up _document.js in milipede-docs then.
Thanks again for all your work, appreciate it :)
Glad to see this getting picked up again. If anyone needs anything from me at all, please do just let me know!
It is already clean. Even the document middleware is not used for this anymore you have to take the middleware into action in getInitialProps of _document. The reason switching from document middleware is that it is not stable and will be removed/replaced with something different. Most importantly, in my tests, those new runtimeConfigs are not passed to this method but is only available in _document itself.
export const composeTestMiddleware = (
req: IncomingMessage,
res: ServerResponse
) => (middlewares: Array<Handler<IncomingMessage, ServerResponse>>) => {
const handler: RequestHandler<IncomingMessage, ServerResponse> = compose(
middlewares
);
const done = () => {
Logger.log('done');
};
handler(req, res, _next => {
return done();
});
return handler;
};
export const instantiateTestMiddleware = (
req: IncomingMessage,
res: ServerResponse
) => {
composeTestMiddleware(req, res)(nextI18NextMiddleware(NextI18NextInstance));
};
MillipedeDocument.getInitialProps = async (
ctx: DocumentContext
): Promise<InitialProps> => {
instantiateTestMiddleware(ctx.req, ctx.res);
// Resolution order
...
I don’t understand why this is so complicated to work.
Most of the people just needs basic i18n features. I have been able to build a simple component with very basic features to translate my application, with serverless feature and SSR.
Reading that ongoing thread, I’m wondering if there are any people interested in a package that anyone could easily use in next.js.
Lemme know!
@rdewolff We'd be very happy for you to share your insight and approaches in this package, as well. Eventually next-i18next will be rewritten as NextJs plugin, once official plugin support drops.
I have implemented my own solution using I18next, react-i18n and Locize provider, see my SO answer:
https://stackoverflow.com/a/58782594/2391795
Maybe it'll help those who need it now. _Note that it doesn't use next-i18next._
As for detecting the language itself, we recently released https://github.com/UnlyEd/universal-language-detector, with a Next.js example.
@gurkerl83 Hey, I tried to install the latest version. What I did is install canary next.js and the 1.1.135 of your lib, add publicRuntimeConfig: {
rootDir: __dirname
}, to next.config.js and copy the i18n.ts file from milipede-docs/master. For the default language it works fine, but when I want to switch language it tells me Error: Invalid configuration: Current language is not included in all languages array and the i18n.languages array is empty
Edit: If I use my own config, and only pass the getConfig() as first arg it works, but still only the current language is in the i18n.languages array, so I think something is wrong around there
@BjoernRave Can you share the repository, or send the setup so I can have a look?
@gurkerl83 sure, I will do it on your repo to not further spam this issue :D
@rdewolff I would really appreciate it, I actually just need the basic things
Hi Guys, not sure if i've missed this but how would i get this running on now 2.0 without serverless?
@gurkerl83 I have your version up and running but my selected language gets forgotten when I visit a nested route, any idea why this would be? ps. sorry for the spam
@smorris1709 About questions and problems regarding the branch mentioned above, I ask you to create an issue at the repo where it gets hosted https://github.com/gurkerl83/next-i18next-serverless. Also, please note that the work is more an experiment and certainly not for production use. Depending on the complexity of a project e.g., using multiple higher-order components on _app, which specifies custom server-side rendering requirements might be incompatible with the current state.
Instead of file system, why not adding option for http/api or BaaS like Locize?
We just released our newest Next.js/Zeit boilerplate at https://github.com/UnlyEd/next-right-now
It is compatible with Zeit and their "lambda/serverless" mode.
It features the usage of react-i18next, alongside Locize.
_app.tsxt usageNote that it doesn't use next-i18next, but react-i18next and other packages, see https://github.com/UnlyEd/next-right-now/blob/master/README_DEPENDENCIES.md#i18n-i18next-and-locize
@Vadorequest Nice, looks cool! That's a very opinionated boilerplate though, are there any findings you can bring back to the next-i18next user base?
I've never used next-i18next, because I got stuck right away because I was using a serverless approach and it wasn't compatible with it. So, I'm not sure what could be re-used for next-i18next itself.
The one thing that has the most value (IMHO) is https://github.com/UnlyEd/next-right-now/blob/master/src/utils/i18nextLocize.ts, for those interested by Locize. I believe this configuration file could be re-used by anyone working with Locize, (or other backends based on i18next specifications). And it was quite complicated to get it right, considering all environments, workflows and options available.
As far as I know, next-i18next is still stuck because of some Express dependencies, and I don't believe the boilerplate will bring anything valuable about that.
Also, it's definitely opinionated but at some point I believe one must have its opinion to build anything with JS, because there are just too many options out there and even experienced developers get lost. It's well documented and I tried to make it as flexible as possible though, so that anyone can just remove pieces that don't fit its use-cases.
We're currently migrating from create-react-app to NextJS, mainly because of the static optimization, and the great integration with now.sh (even if it's still "just" static). We're not planning to user SSR in the foreseeable future. I'm really struggling to solve this issue with i18next. What is the recommended way to handle this use case? (like we would do with CRA)
ps: we're using the new version (9.3) of NextJS and I'm wondering if it's possible eg. to load the translation files in getStaticProps 🤔
@matepapp You can definitely load your locales through getStaticProps from a remote endpoint. I'm planning on updating the Next Right Now boilerplate to use SSG instead of SSR as well.
You will most likely not use next-i18next though, as I don't believe it'd be needed at all, just use react-i18next should be sufficient.
@Vandorequest I’m planning to use only react-i18next as well. To be more precise, we don’t need to use any backend translation provider at all. We only want to read the translation files from /public/locales/en/*.json
Then just load your locales from your getStaticProps and that's it. (and I don't think your issue is related to this issue, so you should rather open a new one, and probably on react-i18next or stackoverflow if you need more help)
Is there anyway to use next-i18next and prerender / SSG?
I don’t understand why this is so complicated to work.
Most of the people just needs basic i18n features. I have been able to build a simple component with very basic features to translate my application, with serverless feature and SSR.
Reading that ongoing thread, I’m wondering if there are any people interested in a package that anyone could easily use in next.js.
Lemme know!
@rdewolff We did something similar. We are using Preact in our project and after seeing that this i18n lib is much bigger than Preact itself, we did a 1kb alternative lib with the basics i18n support. Also with support to serverless, getStaticProps, getStaticPaths, etc 🙂 https://github.com/vinissimus/next-translate
I can recommend next-tranlsate. I am using it since some weeks and it's working pretty well serverless
@aralroca regarding next-translate - I highly recommend at least fixing the plurals rule to support plurals correctly...pluralforms are not just a _{count} - it is a little complexer (suggestion use the cldr plural forms available in Intl API).
Beside that - nice work - devs should just be aware before deciding just for smaller size:
If you just need a smaller solution - next-translate could be a good option
Hey @aralroca, nice work! There are some cool ideas in next-translate that could potentially be used in next-i18next as well, especially the way you've handled things via useContext. On a side note, I'd be curious to see if/how this actually deals with concurrency in SSR.
Indeed next-translate looks like a good solution for a subset of users who require a reduced feature set and are OK with locking into a specific approach to locale subpaths.
However, I would be very wary of the approach of gitignoring the pages dir and procedurally manipulating the filesystem to create locale subpaths. This is not how the NextJs team expects users to be interacting with NextJs, and I assume it will cause issues in the future.
I think some form of proxying is the way forward - whether that be running a single app behind a proxy, or running multiple instances of the same app, again behind a proxy.
Again to reiterate, once a few things (namely redirect/rewrites and first class plugin support) drop in the NextJs core, the next-i18next package will be rewritten to fully support serverless and static sites. We've been waiting quite awhile on the NextJs team to finalise those things, and still don't have a clear timeline.
@isaachinman @jamuhl thanks for your suggestions and comments. Of course behind i18next there is big work. I fully recommend using next-i18next for advanced i18n features.
However, I would be very wary of the approach of gitignoring the pages dir and procedurally manipulating the filesystem to create locale subpaths. This is not how the NextJs team expects users to be interacting with NextJs, and I assume it will cause issues in the future.
Yep 😅I neither like it... I implemented as a temporal workaround to work with static pages. The original idea (not implemented yet but maybe for 1.0.0) is to change the CLI for a Webpack plugin/loader, but I don't know how feasible is it yet. But again, it's another workaround, maybe better than a CLI, but it's a workaround.
If you have the opportunity to be part of the Next.js core rewriting this on a plugin, feel free to take all the ideas from next-translate.
I've spoken to Tim via Slack and have been told that plugin support won't be out for awhile, but the routes (redirect/rewrite) work is in progress. So we may have a phased approach to rewriting next-i18next.
One of the problem I'm aware of is that rewrites only work server-side, so a workaround will have to be implemented for client-side with <Link>
@martpie We've already wrapped Link to support this.
I just got an email that informs us that Now v1 is now deprecated and will be out of service by august, witch means that, we won't be able to deploy a next-i18next project with now anymore... Hard to find a reasonable approach to this :( next-right-now is full of locize specific code, and not easy to replicate.
@isaachinman do you know where we can follow the redirect/rewrite progress on nextjs part ?
https://spectrum.chat/zeit/now/cannot-create-now-v1-deployments~d206a0d4-5835-4af5-bb5c-a17f0171fb25 regarding deprecation, it's "old".
Basically removes support for Docker.
Yes you're right it's been deprecated for a long time, but now it's going to be shut down.
Some quotes from the email they sent :
Important Dates
- 3rd of April 2020: ZEIT announces the deprecation of the ZEIT Now 1.0 platform.
- 1st of May 2020: Creating new ZEIT Now 1.0 deployments will be prevented.
- 7th of August 2020: All ZEIT Now 1.0 deployments will be deleted.
And the part that talks about projects with a custom server :
- A Next.js project with a custom server: If you've deployed a Next.js project that uses a custom server file, it can be refactored to use the
pages/apidirectory with dynamic routes, allowing defined routes to be split into multiple files.
... does not seem to solve the issue here 😅
@Vadorequest thanks for the work on next-right-now, will try to learn from it as well
The best thing people can make right now, is to make some noise in Next.js/Now/ZeitHQ communities so things like Global Middlewares get shipped to Next.js.
The fact Now v2 brings regressions in terms of what is technically feasible to ship IS a real problem, and should probably not be fixed at the next-i18next level.
For next-i18next to be rewritten in its current manifestation and support serverless in a first class way, we still need a version of i18next-express-middleware that does not depend on express.
From there, the package could be rewritten to depend on getServerSideProps for server-side language detection, and rewrites/redirects - loosely speaking.
I don't exactly get why we need the i18n middleware, if we need a custom instance, can't we just call i18n.cloneInstance inside the custom _app.js ? Is it also used for routing / detecting the language ?
Yes, i18next-express-middleware handles detection. Not routing.
All other comments will be marked as off-topic to reduce noise.
Update: @adrai has been generous enough to write i18next-http-middleware for us. I am reviewing the repo and testing the functionality. If all looks good, we'll be able to move next-i18next off its Express dependency, and then rewrite the internals to use built-in NextJs data fetching methods instead of a custom server.
i18next-http-middleware.Initial PR to refactor custom servers in next-i18next to use of rewrites and middleware inside getInitialProps: #689.
Would be appreciative of any comments or feedback!
If I released #689 on a beta, would any of you be interested/willing to test it in real apps?
I would love to, unfortunately pretty busy right now, I hope to find some time and look at it next week. Thanks a lot for the effort !
@isaachinman i'd be happy to test it on our WIP production app, thank you for the great work!
Initially I didn't like the custom express server middleware idea, wanted to migrate to other implementation, but it seems right now this is the simplest way to i18n ones apps while using next :)
Serverless beta has been released under next-i18next@beta. Please help out by testing in your apps!
I had to switch from node 13 to node 10 to avoid this error
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: node_modules/i18next-http-backend/lib/index.js
Do you have some reproducable repo?
i18next is designed to be used in esm and commonjs for all node.js versions.
How does your setup look like? Are you transpiling?
btw. To force commonjs you can also import/require ‘i18next-http-backend/cjs’
@Accumulative @adrai As i18next-http-backend has been merged into master of next-i18next, that's not actually a serverless-specific issue. If it's a genuine bug can someone please open a new issue?
@Accumulative please ping me, if you have something 👍
Sorry, you're right; not related to this change. The "Expected version >=10" message (which isn't in v4.4.0) caused me to switch from node v8 to v13 and get the error. My project is the same as the example which doesn't work out of the box with node v13, I'll raise an issue.
Hi,
I removed the middleware in my server.js.
Now the when I load the home page, the redirection to the default language is ok but I have 404 error, page not found. Do you have any idea ?
@laitlhadj Please post a reproducible example. It sounds like you haven't added rewrites to your config.
Yes, it's ok with the rewrites in config 👌
Now, when I'm deploying to Zeit, I have the following error :
{
"errorType":"Error",
"errorMessage":"Must use import to load ES Module: /var/task/node_modules/i18next-http-backend/cjs/index.js\nrequire() of ES modules is not supported.\nrequire() of /var/task/node_modules/i18next-http-backend/cjs/index.js from /var/task/node_modules/next-i18next/dist/commonjs/create-i18next-client.js is an ES module file as it is a .js file whose nearest parent package.json contains \"type\": \"module\" which defines all .js files in that package scope as ES modules.\nInstead rename index.js to end in .cjs, change the requiring code to use import(), or remove \"type\": \"module\" from /var/task/node_modules/i18next-http-backend/package.json.\n",
"code":"ERR_REQUIRE_ESM",
"stack":[
"Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /var/task/node_modules/i18next-http-backend/cjs/index.js",
"require() of ES modules is not supported.",
"require() of /var/task/node_modules/i18next-http-backend/cjs/index.js from /var/task/node_modules/next-i18next/dist/commonjs/create-i18next-client.js is an ES module file as it is a .js file whose nearest parent package.json contains \"type\": \"module\" which defines all .js files in that package scope as ES modules.",
"Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove \"type\": \"module\" from /var/task/node_modules/i18next-http-backend/package.json.",
"",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:1174:13)",
" at Module.load (internal/modules/cjs/loader.js:1002:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:901:14)",
" at Module.require (internal/modules/cjs/loader.js:1044:19)",
" at require (internal/modules/cjs/helpers.js:77:18)",
" at Object.(/var/task/node_modules/next-i18next/dist/commonjs/create-i18next-client.js:18:50)",
" at Module._compile (internal/modules/cjs/loader.js:1158:30)",
" at Object.Module._extensions..js (internal/modules/cjs/loader.js:1178:10)",
" at Module.load (internal/modules/cjs/loader.js:1002:32)",
" at Function.Module._load (internal/modules/cjs/loader.js:901:14)"
]
}
@adrai Can you address this as necessary? Looks like the cjs target is being pulled in, but the Vercel platform is unhappy due to module declaration in the package.json.
@isaachinman like here: https://github.com/locize/i18next-locize-backend/issues/323#issuecomment-619625571
any advice is welcome
currently I would import 'i18next-http-backend/cjs' until Varcel does not respect node standard
@adrai Well, it seems like Vercel is doing something non-standard in terms of module resolution. A fix should be as simple as writing a separate cjs package.json into the cjs dist dir - not sure exactly how your compilation process works, but I think that'd be the approach necessary.
writing a separate
cjspackage.jsoninto thecjsdist dir
this is already the case... this is why importing 'i18next-http-backend/cjs' works
@adrai Ah yeah, I saw that just seconds after posting above. I suppose we'll just point the import within next-i18next to the cjs dir explicitly.
at least as long as they are not fixing this 🤷♂️
I would help, but I have no clue about Vercel, sorry
Vercel: 
https://github.com/zeit/now/issues/3337#issuecomment-556141731
Okay, I've changed imports from i18next to point explicitly at the cjs subdir, and can confirm the beta release will build on Vercel now. However, I'm still getting the fs error:
"ENOENT: no such file or directory, scandir '/var/task/public/static/locales/en'"
How have users gotten around this?
@isaachinman, I've been using dynamic imports instead of direct fs calls successfully. It can then be bundled by webpack, during the ~now~ vercel serverless compilation step
@nassimbenkirane Can you provide an example?
Sure, I'm doing something like this this in _app.js
(Didn't take the time to refactor the namespace since we only use one)
if (isServer && i18nextInstance.language !== initialLanguage) {
if (!i18nextInstance.hasResourceBundle(initialLanguage, 'translation')) {
let newtranslation = await import(`../public/locales/${initialLanguage}/translation.json`)
i18nextInstance.addResourceBundle(initialLanguage, 'translation', newtranslation)
}
i18nextInstance.changeLanguage(initialLanguage)
}
I had tried using i18next-fs-backend (with the initImmediate option) before with no success. To do this in a clean way we would probably need to create a "dynamic import" backend I guess
I don't think writing a new plugin should be necessary. Let's just take advantage of what NextJs/Vercel offer out of the box: the translation data is already available at:
${VERCEL_URL}/static/locales/{{lng}}/{{ns}}.json
@adrai Are we able to use i18next-http-backend to load resources from a "remote" source in the NodeJs environment (in addition to browser), as opposed to filesystem in NodeJs and remote in browser? In this case, remote is in quotes because it'd actually be the same host.
Also, we would need to ensure that caching is set up - if this resulted in a new network request for each route request, that would be unacceptable.
@isaachinman sorry, probably I missed part of the discussion...
what is the actual problem with i18next-fs-backend?
@adrai There's no problem with i18next-fs-backend - the problem is with Vercel's platform. Their serverless approach results in there not really being a "filesystem" at all.
Can't the files just be included in the vercel build like public assets?
btw: i18next-http-backend works also in node.js environment, not just in the browser
There is an option in other builders for manually including files, but right now it doesn't seem to be included in now/next builder https://github.com/zeit/now/issues/3083
There is an option in other builders for manually including files, but right now it doesn't seem to je included in now/next builder zeit/now#3083
ok, thx
so yes, just use i18next-http-backend on client and serverside... should work the same
node.js example: https://github.com/i18next/i18next-http-backend/blob/master/example/node/app.js
there's also a reloadInterval option (but probably not useful in serverless environments)
for a customized handling of the http request, for example to do some caching etc... the request option could be used
but I suggest to do this only if (onServer && !onClient) 😉
I'm using serverless-next.js with AWS. I just made sure the public/locales folder is included in the lambda. The translations are working for me.
@Accumulative Do you mean with the current beta release, or just in general?
@isaachinman With the beta release. I'm guessing it wouldn't work without it because of the express dependency, but I haven't tried it.
@Accumulative Hi, I am also trying to use serverless-next.js with AWS, and stepped into this thread.
How do you make sure to include the public/locales directory?
@gianpaolom I just copied it manually and uploaded to lambda.
Edit: removed suggested idea as it doesn't work
@Accumulative thank you for your answer. Unfortunately I realised now I am using the most recent version of serverless-next which uses components, and what it does is using a component for lambda@edge, which copies a fixed number of files/dirs from .next/serverless
I tried a horrible hack of the code of the component to add the public/locales dir, so that it ships the directory to the lambda. However, even using the latest 4.4.1 version of next-i18next ( @isaachinman ) what I get is now a different error:
{
"errorType": "Error",
"errorMessage": "Cannot find module 'i18next-fs-backend/cjs'",
"code": "MODULE_NOT_FOUND",
"stack": [
"Error: Cannot find module 'i18next-fs-backend/cjs'",
" at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)",
" at Function.Module._load (internal/modules/cjs/loader.js:562:25)",
" at Module.require (internal/modules/cjs/loader.js:692:17)",
" at require (internal/modules/cjs/helpers.js:25:18)",
" at eval (eval at _default (/var/task/pages/_error.js:12680:30), <anonymous>:1:1)",
" at _default (/var/task/pages/_error.js:12680:30)",
" at new NextI18Next (/var/task/pages/_error.js:65279:66)",
" at Object.k7Sn (/var/task/pages/_error.js:54005:18)",
" at __webpack_require__ (/var/task/pages/_error.js:23:31)",
" at Module.IlR1 (/var/task/pages/_error.js:12385:12)"
]
}
@gianpaolom Can you verify if i18next-fs-backend v1.0.2 is installed?
@adrai yes, it's in my package.json and inside my node_modules directory in the tree.
@gianpaolom Can you create a reproducable example?
@adrai the steps I have done are:
- npm install --save-dev serverless-next.js
- npm install --save next-i18next@beta
- npm install --save [email protected]
Hack lambda-at-edge component:
${HOME}/.serverless/components/registry/npm/serverless-next.js@${VERSION}/node_modules/@sls-next/lambda-at-edge/dist/build.js
to include the public/locales dir
buildDefaultLambda(buildManifest) {
return Promise.all([
fs_extra_1.copy(require.resolve("@sls-next/lambda-at-edge/dist/default-handler.js"), path_1.join(this.outputDir, exports.DEFAULT_LAMBDA_CODE_DIR, "index.js")),
fs_extra_1.writeJson(path_1.join(this.outputDir, exports.DEFAULT_LAMBDA_CODE_DIR, "manifest.json"), buildManifest),
fs_extra_1.copy(require.resolve("next-aws-cloudfront"), path_1.join(this.outputDir, exports.DEFAULT_LAMBDA_CODE_DIR, "node_modules/next-aws-cloudfront/index.js")),
fs_extra_1.copy(path_1.join(this.nextConfigDir, ".next/serverless/pages"), path_1.join(this.outputDir, exports.DEFAULT_LAMBDA_CODE_DIR, "pages"), {
filter: file => {
const isHTMLPage = path_2.default.extname(file) === ".html";
return pathToPosix_1.default(file).indexOf("pages/api") === -1 && !isHTMLPage;
}
}),
fs_extra_1.copy(path_1.join(this.nextConfigDir, ".next/serverless/public"), path_1.join(this.outputDir, exports.DEFAULT_LAMBDA_CODE_DIR, "public")) <========
]);
}
My serverless.yml:
# serverless.yml
myApp:
component: serverless-next.js
inputs:
build:
cmd: /bin/sh
args: ["build.sh"]
env:
VAR_1:
VAR_2:
...
where build.sh:
npm run build
mkdir -p .next/serverless/public
cp -r public/locales .next/serverless/public
Deploy with:
AWS_ACCESS_KEY_ID=<value> AWS_SECRET_ACCESS_KEY=<value> serverless
@gianpaolom Sorry, I'm not familiar with serverless-next.js
So isn't this reproducable locally?
Something I can git clone... && npm i && npm start ?
Or @isaachinman do you can help?
@adrai I'm afraid not. This happens when the code is already at AWS Lambda
Hi all - I know it's frustrating but let's keep this discussion to _general_ support of serverless, not the intricacies of individual platforms.
Hi there, I've been following the discussion since yesterday because I'm facing the same problem: trying to deploy my app to now and getting an error, since now doesn't support ESM files.
I was trying to figure out how I could change the imports to automatically point at cjs subdir (as suggested by @adrai). I've just realized @isaachinman released it in the 4.4.1 version. Thanks a lot for the support, guys :pray: .
At the moment, I'm facing the same problem as you did, Isaac:
"ENOENT: no such file or directory, scandir '/var/task/public/static/locales/en'"
Have you found a workaround for this? btw, Is it the right place to have this discussion or should I look somewhere else?
Thanks in advance!
@lcnogueira If you want to deploy a next-i18next project on now, the best thing to do is make sure the Vercel team are aware! https://github.com/zeit/now/issues/3083 seems to track the problem, but in general this is down to Vercel's proprietary/opinionated platform.
Ok, @isaachinman . Thanks for the clarification :+1: .
@isaachinman @adrai @gianpaolom
I had the same issue. I had to copy the i18next-fs-backend and i18next-http-middleware into the default-lambda/node_modules folder to get rid of this error.
I think the problem is that when we run next build it creates these two lines in the .next/serverless/pages bundles:
var i18nextFSBackend = eval("require('i18next-fs-backend/cjs')");
var i18nextMiddleware = eval("require('i18next-http-middleware/cjs')");
rather than including the code for these packages in the bundle itself.
@Accumulative Those evals are a nasty hack-solution to splitting deps out of client side bundles. I've just rerun two builds, one with eval and one without.
With eval:

Without eval:

I am more than happy for anyone to suggest or contribute a better fix for this. Use of eval will likely cause problems in many serverless setups.
If I released #689 on a beta, would any of you be interested/willing to test it in real apps?
We are running the fix in production and so far it works well. Thank you for this! Saved our branch deployments. 🔥
@janhesters What platform are you running on?
@isaachinman Sorry, it looks it didn't fix it for our serverless deployments. (Our production runs on Heroku 🙈 ).
Our branch deployments are on Vercel. And this is the error.
2020-05-06T09:12:11.529Z undefined ERROR Uncaught Exception {"errorType":"Error","errorMessage":"ENOENT: no such file or directory, scandir '/var/task/public/static/locales/en'","code":"ENOENT","errno":-2,"syscall":"scandir","path":"/var/task/public/static/locales/en","stack":["Error: ENOENT: no such file or directory, scandir '/var/task/public/static/locales/en'"," at Object.readdirSync (fs.js:871:3)"," at getAllNamespaces (/var/task/node_modules/next-i18next/dist/commonjs/config/create-config.js:111:19)"," at createConfig (/var/task/node_modules/next-i18next/dist/commonjs/config/create-config.js:116:27)"," at new NextI18Next (/var/task/node_modules/next-i18next/dist/commonjs/index.js:53:48)"," at Object.k7Sn (/var/task/.next/serverless/pages/events/[eventSlug].js:21824:29)"," at __webpack_require__ (/var/task/.next/serverless/pages/events/[eventSlug].js:31:31)"," at Object.IlR1 (/var/task/.next/serverless/pages/events/[eventSlug].js:9808:67)"," at __webpack_require__ (/var/task/.next/serverless/pages/events/[eventSlug].js:31:31)"," at Module.GpDZ (/var/task/.next/serverless/pages/events/[eventSlug].js:9392:12)"," at __webpack_require__ (/var/task/.next/serverless/pages/events/[eventSlug].js:31:31)"]}
Unknown application error occurred
Error
@janhesters Yes, same error all deployments on Vercel end up with. Please let the Vercel team know if this is something you'd like to be able to deploy.
@isaachinman How would you recommend to reach out to them?
@janhesters Via https://github.com/zeit/now/issues/3083, or by opening new issue(s) specific to next-i18next usage on either the now repo or the next repo.
@janhesters, I have opened up a discussion on zeitjs now platform: https://github.com/zeit/now/discussions/4271. Let's keep the discussion there :+1: .
What version of next are you running?
There was an issue in next with process.cwd() in older versions of next more precise before 9.2.3-canary.21. This function gets used in next-i18next in create-config.ts to locate the base folder. It seemed that previous to this version, when a page got wrapped in a lambda process.cwd() returned, not the correct folder where the process got launched. Before that, it was necessary to use publicRuntimeConfig and serve __dirname (as a directory offset) at application start end extract it in create-config.ts. I was able to track this a month ago here https://github.com/project-millipede/millipede-docs/commit/86bf7d679504f27a58d9084b6d9acd62feb91658 .
Note: Do not use the dependency which you see in this commit because that is entirely based on a document middleware, which will be not supported anymore because from next version 9.3.7-canary.0 they removed this option entirely. Those things are super frustrating in next; they introduce APIs others build libraries around, which later get silently removed, great job next!
@gurkerl83 It's nothing to do with process.cwd. I've tested both ways.
Not questioning anything here, but next behaves differently on a local machine (both for dev / prod config) compared to deploying it through now deploy.
My modifications in create-config.ts was. I experienced that the public folder is sometimes available. I cannot remember the exact constellation anymore but maybe the following code snippet is helpful, hopefully it is nor direct in the wrong direction.
let localePathPublic = ``;
// LOCAL
// dev / prod mode (next dev vs next start) and deployment through
// NOW
// build phase / serving phase
// differentiate somehow.
const locales = !isBrowser ?
fs.existsSync(path.join(rootDir, './locales/en/common.json')) :
false;
const publicLocales = !isBrowser ?
fs.existsSync(path.join(rootDir, './public/locales/en/common.json')) :
false;
// Needed for NOW serving phase
if (locales) {
localePathPublic = localePath;
}
// Needed for LOCAL dev / prod mode as well as for NOW build phase
if (publicLocales) {
localePathPublic = `/public/${localePath}`;
}
The variable localePathPublic is then used further down also as an argument to getAllNamespaces where you see the problem others report.
Maybe it helps, unfortunately I have no cycles left to help anytime soon.
I tried to use the new rewrites version on a new app, but kept running into this error during configuration after following the simple example repository.
Error: Cannot find module './dist/commonjs/utils/generate-rewrites'
@SpicyPete Have you definitely installed next-i18next@beta?
@isaachinman 🤦 I was on beta, but using the full URL version like git://github.com/isaachinman/next-i18next.git#beta
Using the shorter version got passed that issue. Thanks.
I am using my previous experience with Gatsby and build below example that works for SSG dev and deployed to Vercel. Please advice.
So basically in each page's getStaticProps, I create an i18next instance just to read local json translations.
// i18nextInstance.js
import i18next from 'i18next'
import Backend from 'i18next-fs-backend'
export default async function i18nextInstance (locale, namespaces) {
const i18n = i18next.createInstance().use(Backend)
await new Promise(resolve =>
i18n.init(
{
lng: locale,
ns: namespaces,
interpolation: {
escapeValue: false
},
backend: { loadPath: 'locales/{{lng}}/{{ns}}.json' }
},
resolve
)
)
return i18n.services.resourceStore.data
}
Then in each page's getStaticPaths as my pages are all located inside [locale]/page.js
export async function getStaticPaths () {
return {
paths: LOCALES.map(locale => ({
params: { locale: locale }
})),
fallback: false
}
}
Then in getStaticProps.
export async function getStaticProps ({ params }) {
const i18nextResources = await i18nextInstance(params.locale, ['common'])
return {
props: {
i18n: {
locale: params.locale,
resources: i18nextResources
}
}
}
}
And finally my _app.js
import React from 'react'
import i18next from 'i18next'
import { initReactI18next, I18nextProvider } from 'react-i18next'
import LanguageDetector from 'i18next-browser-languagedetector'
function App ({ Component, pageProps }) {
const i18n = i18next
.createInstance({
lng: pageProps.i18n.locale,
interpolation: {
escapeValue: false
},
resources: pageProps.i18n.resources
})
.use(initReactI18next)
.use(LanguageDetector)
i18n.init({
fallbackLng: 'en',
react: {
useSuspense: false
},
detection: {
order: ['localStorage', 'cookie', 'navigator', 'path'],
lookupLocalStorage: 'localstorage_name',
lookupCookie: 'cookie_name',
lookupFromPathIndex: 0,
caches: ['localStorage', 'cookie'],
excludeCacheFor: ['cimode'],
}
})
return (
<I18nextProvider i18n={i18n}>
<Component {...pageProps} />
</I18nextProvider>
)
}
export default App
And in all my pages and components I can use translation without problem.
```
import { useTranslation } from 'react-i18next'
export default function myPage () {
const { t } = useTranslation()
t('common:test')
}
hey @isaachinman,
I tried to use the serverless translate with the next-js with-antd-less example and updated packages and it seems like it can't export to a static website. I stumbled across this error:
Error occurred prerendering page "/{name_of_page}". Read more: https://err.sh/next.js/prerender-error:
TypeError: res.writeHead is not a function
Exporting (1/x)
The only thing changed is the next-js config to this:
/* eslint-disable */
const withLess = require('@zeit/next-less')
const lessToJS = require('less-vars-to-js')
const withSass = require('@zeit/next-sass')
const withPlugins = require('next-compose-plugins');
const fs = require('fs')
const path = require('path')
// Where your antd-custom.less file lives
const themeVariables = lessToJS(
fs.readFileSync(path.resolve(__dirname, './assets/antd-custom.less'), 'utf8')
)
const { nextI18NextRewrites } = require('next-i18next/rewrites')
const localeSubpaths = {fr: 'fr', en: 'en'}
const nextConfig = {
publicRuntimeConfig: {
localeSubpaths,
},
experimental: {
async rewrites() {
return [
...nextI18NextRewrites(localeSubpaths)
]
}
},
webpack: (config, { isServer }) => {
if (isServer) {
const antStyles = /antd\/.*?\/style.*?/
const origExternals = [...config.externals]
config.externals = [
(context, request, callback) => {
if (request.match(antStyles)) return callback()
if (typeof origExternals[0] === 'function') {
origExternals[0](context, request, callback)
} else {
callback()
}
},
...(typeof origExternals[0] === 'function' ? [] : origExternals),
]
config.module.rules.unshift({
test: antStyles,
use: 'null-loader',
})
}
return config
},
}
module.exports = withPlugins([
[withSass, {}],
[withLess, {
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables,
}
}]], nextConfig
)
I update my next-i18next to the beta Version 5.0.0-beta.2 and it's working but i have to issues
1- the link for the Website no longer have the Language prefix
before was like this:
website.com/language/page
and after update become
website.com/page
2- both. req.i18n and i18n.language in getinitialprops is coming undefined
Request variable don't have i18n anymore and i18n don't have language any more in the getinitialprops if i used in for example useEffect it has .language normally
@sebastienlabine Correct. Serverless is not the same as static - we _do_ need a runtime to do language detection and conditional routing.
@amr3ssam Can you create a minimal repro for me to take a look?
I think @amr3ssam is talking about this part of the README: https://github.com/isaachinman/next-i18next/tree/beta#accessing-the-current-language
We have released our own i18n integration on NRN v2.
The demo features use of i18next, react-i18next and Locize vendor (translations are stored on Locize, and fetched through Locize API)
The demo works with SSG and SSR pages, using the latest 9.4.4 Next.js version.
It doesn't require any extra server, it relies on a Serverless function to detect the browser locale, when the locale isn't part of the url.
It supports both lang/locale (AKA "nested locale") approach (e.g: using fr or fr-FR, it's up to you).
The demo showcases GraphCMS for content localisation (translation of dynamic content).
Demo:
https://nrn-v2-mst-aptd-gcms-lcz-sty-c1.now.sh
Code:
https://github.com/UnlyEd/next-right-now/tree/v2-mst-aptd-gcms-lcz-sty
Let us know what you think, I'm currently updating the official docs at https://unlyed.github.io/next-right-now/, see https://github.com/UnlyEd/next-right-now/pull/69
Please keep all discussion in this issue to the topic at hand.
@sebastienlabine Correct. Serverless is not the same as static - we _do_ need a runtime to do language detection and conditional routing.
Does that mean that static components aren't compatible with using localeSubpaths in the beta (at all)?
@isaachinman LocaleSubpaths doesn't seems to be working when using getStaticPaths, because getStaticPaths and publicRuntimeConfig don't work together (See the issue in the NextJS Repo).
The npm run build command results in the same output of here.
Is there any way we could rewrite to LocaleSubpaths to use env instead of publicRuntimeConfig?
[slug].tsx
// I want [lang]/blog/postId if exists else 404
export async function getStaticPaths() {
const paths = posts.map((post) => ({
params: { slug: post.id },
}))
return { paths, fallback: false }
}
export async function getStaticProps({ params }) {
var post = posts.find(x => x.id == params.slug)
return { props: { post } }
}
next.config.js
const { nextI18NextRewrites } = require('next-i18next/rewrites')
const localeSubpaths = { fr: 'fr', en: 'en' }
module.exports = {
publicRuntimeConfig: {
localeSubpaths,
},
experimental: {
async rewrites() {
return [
...nextI18NextRewrites(localeSubpaths)
]
}
}
}
i18n.ts
import NextI18Next from 'next-i18next';
const { localeSubpaths } = require('next/config').default().publicRuntimeConfig
const i18next = new NextI18Next({
defaultLanguage: "en",
otherLanguages: ['fr'],
localeSubpaths,
})
The use of publicRuntimeConfig is mostly to facilitate e2e tests internally. How you propagate localeSubpaths is entirely up to you.
Understood. However, anything related to getStaticPaths / getStaticProps doesn't work. Can't create a simple dynamic translated page.
The use of
publicRuntimeConfigis mostly to facilitate e2e tests internally. How you propagatelocaleSubpathsis entirely up to you.
@isaachinman is there an alternate way (you can think of) to propagate localeSubpaths that's compatible with getStaticPaths?
@janhesters, I have opened up a discussion on zeitjs
nowplatform: vercel/vercel#4271. Let's keep the discussion there +1 .
I opened a new issue on the next.js repo on the deployment problem to now/vercel, because it seems like it's not working due to a framework limitation of next.js. In case you always wanted to state how important this fix is to you, or discuss a workaround, now you have the opportunity to.
Hi, they seem to have removed dependency to Express in i18next-express-middleware to be more versatile, see https://github.com/i18next/i18next-http-middleware.
Could it mean an easier serverless implementation? A year ago you seemed to think that this dependency was a blocker to serverless i18n in Next.
Edit: I notice that you already udpated next-i18next to use it, so my question is more what are the blocker for serverless now?
Hi, they seem to have removed dependency to Express in
i18next-express-middlewareto be more versatile, see https://github.com/i18next/i18next-http-middleware.Could it mean an easier serverless implementation? A year ago you seemed to think that this dependency was a blocker to serverless i18n in Next.
Edit: I notice that you already udpated next-i18next to use it, so my question is more what are the blocker for serverless now?
Hey Eric,
The only blocker is a bug with next.js that prevents the serverless vercel lambda from recognizing the json language files, see this issue. It would be nice if you would participate over there to give this problem more attention.
They've just added your issue in the backlog so I guess they take it into serious consideration.Thanks a lot for the boilerplate you linked in the issue. After a day of work, it eventually helped me to install next-i18next in half an hour, without needing to setup a custom server already. That's awesome!
To bypass this, why not replacing the file-system read by an HTTP request in the meantime? Maybe the file loading has to be synchronous? If it's asynchronous, is there something else preventing you to do an HTTP request? Eg not knowing the app URL at runtime?
When doing SSR with Apollo for instance, that's what we do when you can't load the schema from a local file, we just use an Apollo Client with HTTP link server side. It sounds very ugly but that does the job, and is not worse than an HTTP request client-side.
Sorry if it's unclear, I haven't used Vercel at this point, and I am not sure where this file load happens in the code, so that's very theoretical.
Edit: thought about it a bit more, the problem is that using an HTTP call would need the public/ folder to be available before the lambda that needs i18n is build. I don't know how Vercel works, but I imagine that builds of the api routes and normal routes, + publishing the public folder are kind of parallel operations? So you may not be able to wait for "public" to be online before requiring the locales happens?
This comment: https://github.com/vercel/next.js/issues/13624#issuecomment-655326365 potentially sheds some light on how to get Vercel to pick up filesystem deps.
@adrai I'm back to running into i18next module resolution issues:
2020-07-08T09:30:10.473Z 4e8d3e9a-1479-4f9d-b650-e1ab625ea951 ERROR Unhandled error during request: Error: Cannot find module 'i18next-fs-backend/cjs'
Require stack:
- /var/task/node_modules/next-i18next/dist/commonjs/create-i18next-client.js
- /var/task/node_modules/next-i18next/dist/commonjs/index.js
Fairly sure this was previously working. Any ideas?
I'm back to running into i18next module resolution issues:
strange... is this reproducable with the example in the repo? Can't reproduce it.
@adrai I have been deploying this repo to Vercel. Feel free to fork and deploy. This issue isn't reproducible locally – it's definitely something to do with their strict module resolution.
I'm back to running into i18next module resolution issues:
strange... is this reproducable with the example in the repo? Can't reproduce it.
It only occurs when deploying to vercel. Here is a project that basically runs minimal configuration and has the filepath already included: https://github.com/borispoehland/next-i18next-boilerplate
Edit: Take Isaac's version
It only occurs when deploying to vercel.
Then they changed something again... 🤷♂️
Maybe now requiring /cjs is not needed anymore?
Seems eval('require...') is ignored by their bundler.... there are also others having this problem: https://github.com/saltyshiomix/nextron/issues/78
https://github.com/vercel/next.js/issues/13736
Probably adding something like this would force to bundle it:
const path = require('path');
path.resolve('./node_modules/i18next-fs-backend/')
🤷♂️
Probably adding something like this would force to bundle it:
const path = require('path'); path.resolve('./node_modules/i18next-fs-backend/')🤷♂️
Sorry for the newbie question, but what stops you from importing the modules with the regular import syntax (instead of the eval(require...))?
Because with require they are handled as node modules?
I imagine importing them would bundle these dependencies also for the client...
Alternatively a dynamic import could work... but then that function would have been rewritten to be async...
@isaachinman is this correct?
Guess what? I just deployed a serverless next-i18next project successfully on Vercel:
https://next-i18next-vercel.now.sh/
Can we get some early adopters, of users both:
next-i18next@betanext-i18next@betaWe want to make sure that both options are supported well and free of any major bugs.
Yeah, that suggestion works @borispoehland. The
evalusage there is a nasty hack to exclude those deps from client bundles. I've always been open to other solutions, but no one has come forward.Guess what? I just deployed a serverless
next-i18nextproject successfully on Vercel:https://next-i18next-vercel.now.sh/
Can we get some early adopters, of users both:
- Deploying serverless projects with
next-i18next@beta- Deploying custom server (Express) projects with
next-i18next@betaWe want to make sure that both options are supported well and free of any major bugs.
I thought custom server deploys to vercel are not possible, which was the reason for creating the serverless beta in the first place?
I thought custom server deploys to vercel are not possible, which was the reason for creating the serverless beta in the first place?
I wasn't talking about Vercel. This project needs to support deployment on various platforms, and needs to maintain support for users that rely on custom servers.
I thought custom server deploys to vercel are not possible, which was the reason for creating the serverless beta in the first place?
I wasn't talking about Vercel. This project needs to support deployment on various platforms, and needs to maintain support for users that rely on custom servers.
I understand
@isaachinman the updated beta is not pushed yet, right?
@borispoehland What updates to the beta release are you expecting? I'm not convinced that platform-specific hacks like using path.resolve belong in the next-i18next source.
Are you able to share the source code for how you solved the issue? The path.resolve('./node_modules/i18next-fs-backend/') "hack" does not tell me a lot.
The source code is here: https://github.com/isaachinman/next-i18next-vercel
@borispoehland What updates to the beta release are you expecting? I'm not convinced that platform-specific hacks like using
path.resolvebelong in thenext-i18nextsource.
Your're absolutely right. Better put it in the i18n.js.
Update: I've spoken to Joe in the NextJs team, and we've identified fixes for both the locales dir path, and i18next-fs-backend. I will be updating next-i18next@beta such that no path.resolve tricks will be necessary at all – should have this done by the end of the week.
Update: I've spoken to Joe in the NextJs team, and we've identified fixes for both the locales dir path, and
i18next-fs-backend. I will be updatingnext-i18next@betasuch that nopath.resolvetricks will be necessary at all – should have this done by the end of the week.
Cool, let me know if there is something that need to be done for other i18next modules...
So, I’ve undertaken the following changes:
localePath to be an absolute path (requirement), which users can pass via path.resolve. This is to get around bundling technologies used by Vercel, and other serverless platforms. The way that path.resolve falls back in browser envs is critical.create-client code to have two entry points: one for Node, and one for browsers. This way we can stop using eval hacks, and allow tools to properly analyse our dependencies (fixes the various i18next dep issues).Changes here: https://github.com/isaachinman/next-i18next/commit/826a9a58d15bde153223e1f45181c99ffaa5af7d.
I then released [email protected] and updated my example repo:
https://github.com/isaachinman/next-i18next-vercel
It's running smoothly on Vercel here:
https://next-i18next-vercel.now.sh/
So: we can now release next-i18next projects on Vercel (and other serverless platforms) without any compromises or hacks, straight out of the box. The main breaking change will be the requirement of path.resolve for localePath.
Please do let me know if anyone has any questions, or if any of you are able to beta test this release. I've been told by the NextJs team that rewrites will be stable very soon, so in the very near future this functionality will be available without the experimental flag.
I am going to (finally) close this issue in the near future, as serverless support is genuinely here. If anyone encounters bugs/problems with the serverless beta release, please open new issues as you normally would.
Thanks everyone!
So, I’ve undertaken the following changes:
- Refactor
localePathto be an absolute path (requirement), which users can pass viapath.resolve. This is to get around bundling technologies used by Vercel, and other serverless platforms. The way thatpath.resolvefalls back in browser envs is critical.- Refactor the
create-clientcode to have two entry points: one for Node, and one for browsers. This way we can stop usingevalhacks, and allow tools to properly analyse our dependencies (fixes the variousi18nextdep issues).Changes here: 826a9a5.
I then released
[email protected]and updated my example repo:https://github.com/isaachinman/next-i18next-vercel
It's running smoothly on Vercel here:
https://next-i18next-vercel.now.sh/
So: we can now release
next-i18nextprojects on Vercel (and other serverless platforms) without any compromises or hacks, straight out of the box. The main breaking change will be the requirement ofpath.resolveforlocalePath.Please do let me know if anyone has any questions, or if any of you are able to beta test this release. I've been told by the NextJs team that
rewriteswill be stable very soon, so in the very near future this functionality will be available without theexperimentalflag.I am going to (finally) close this issue in the near future, as serverless support is genuinely here. If anyone encounters bugs/problems with the serverless beta release, please open new issues as you normally would.
Thanks everyone!
Hey, thanks for coming up with an equally straightforward solution for the serverless option as well.
I'm trying to implement the update into my new project, however, I'm finding the following issue when importing the i18n file into any page-level component:
Error was not caught TypeError: path.resolve is not a function
I'm not a veteran with Next.js, but I don't see any obvious problem with my code.
my i18n.js:
const path = require('path')
const NextI18Next = require('next-i18next').default
const { localeSubpaths } = require('next/config').default().publicRuntimeConfig
module.exports = new NextI18Next({
defaultLanguage: 'en',
otherLanguages: ['es'],
localeSubpaths,
localePath: path.resolve('./public/locales'),
})
My "/test" page-level component:
import React from 'react'
import PropTypes from 'prop-types'
import { i18n, withTranslation } from '../i18n'
const Test = ({ t, namespacesRequired }) => {
return (
<React.Fragment>
<main>
<div>
<button
type="button"
onClick={() => {
console.log(i18n)
i18n.changeLanguage(i18n.language === 'en' ? 'de' : 'en')
}}
>
Change
</button>
<h1>{t('title')}</h1>
</div>
</main>
</React.Fragment>
)
}
Test.getInitialProps = async () => ({
namespacesRequired: ['common'],
})
Test.propTypes = {
t: PropTypes.func.isRequired,
}
export default withTranslation('common')(Test)
My next.config.js:
const withPlugins = require('next-compose-plugins');
const withOptimizedImages = require('next-optimized-images');
const withFonts = require('next-fonts');
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin');
const { nextI18NextRewrites } = require('next-i18next/rewrites')
const localeSubpaths = {
es: 'es'
}
const nextConfig = {
env: {
GOOGLE_API_KEY: 'API_KEY',
REACT_APP_GOOGLE_MAP_API_KEY:
'https://maps.googleapis.com/maps/api/js?v=3.exp&key=API_KEY&libraries=geometry,drawing,places',
SERVER_API: `http://localhost:3001`,
},
webpack: (config, { isServer }) => {
config.plugins.push(
new FilterWarningsPlugin({
exclude: /mini-css-extract-plugin[^]*Conflicting order between:/,
})
);
config.resolve.modules.push(__dirname);
return config;
},
publicRuntimeConfig: {
localeSubpaths,
},
experimental: {
async rewrites() {
return [
...nextI18NextRewrites(localeSubpaths)
]
}
}
};
module.exports = withPlugins(
[
[
withOptimizedImages,
{
mozjpeg: {
quality: 90,
},
webp: {
preset: 'default',
quality: 90,
},
},
],
withFonts,
],
nextConfig
);
If you have any other question, I'll be glad to provide more information if possible.
Thanks in advance! :muscle:
Thanks a ton @isaachinman , was able to deploy the 5.0.0-beta.3 to netlify so just wanted to chime in that other serverless type hosts seem to be working. I did have to explicitly list out my namespaces in the ns value to the NextI18Next constructor, otherwise it would call getAllNamespaces and try to read from the filesystem which failed in a serverless environment. Not sure if this was the intended behavior, or I misconfigured something, or it's a bug but listing out NSs isn't too bad and it's great to be able to run under the serverless target.
Thanks a ton @isaachinman , was able to deploy the 5.0.0-beta.3 to netlify so just wanted to chime in that other serverless type hosts seem to be working. I did have to explicitly list out my namespaces in the
nsvalue to the NextI18Next constructor, otherwise it would callgetAllNamespacesand try to read from the filesystem which failed in a serverless environment. Not sure if this was the intended behavior, or I misconfigured something, or it's a bug but listing out NSs isn't too bad and it's great to be able to run under the serverless target.
I just deployed to Netlify and it seems to return 404 when accessing the locale URL directly.
The demo is at: https://eager-shannon-a9d1c4.netlify.app/
If you access this URL, it shows 404
https://eager-shannon-a9d1c4.netlify.app/de/second-page
The repository for the demo is forked from @isaachinman with adding target: "serverless" https://github.com/welrn/next-i18next-vercel
@Progressandro @Lanny @lazidoca – as I wrote, please open separate issues.
Hey all – NextJs v9.5 came out today, and rewrites are no longer experimental. I've therefore just released [email protected], which supports serverless. Enjoy!
Most helpful comment
So, I’ve undertaken the following changes:
localePathto be an absolute path (requirement), which users can pass viapath.resolve. This is to get around bundling technologies used by Vercel, and other serverless platforms. The way thatpath.resolvefalls back in browser envs is critical.create-clientcode to have two entry points: one for Node, and one for browsers. This way we can stop usingevalhacks, and allow tools to properly analyse our dependencies (fixes the variousi18nextdep issues).Changes here: https://github.com/isaachinman/next-i18next/commit/826a9a58d15bde153223e1f45181c99ffaa5af7d.
I then released
[email protected]and updated my example repo:https://github.com/isaachinman/next-i18next-vercel
It's running smoothly on Vercel here:
https://next-i18next-vercel.now.sh/
So: we can now release
next-i18nextprojects on Vercel (and other serverless platforms) without any compromises or hacks, straight out of the box. The main breaking change will be the requirement ofpath.resolveforlocalePath.Please do let me know if anyone has any questions, or if any of you are able to beta test this release. I've been told by the NextJs team that
rewriteswill be stable very soon, so in the very near future this functionality will be available without theexperimentalflag.I am going to (finally) close this issue in the near future, as serverless support is genuinely here. If anyone encounters bugs/problems with the serverless beta release, please open new issues as you normally would.
Thanks everyone!