i18next / next-i18next

The easiest way to translate your NextJs apps.

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

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for Serverless

Nelrohd opened this issue · comments

Is your feature request related to a problem? Please describe.

Currently next-i18next does not support serverless. It appears that the i18n-middleware create some troubles when used on lambda #271

Describe the solution you'd like

Not sure exactly what would be the final solution but:

  • Support i18n without needing custom server.
  • Support with custom server like express (note I didn't find an official repo for NextJS V8 serverless + express).

Describe alternatives you've considered

None.

Additional context

Open to suggestion for the work/final solution to be done/achieved.

A few things to consider - just my initial thoughts:

  • Where would locales/translated content live? Seems we are going to have problems with a filesystem approach
  • How would we support locale subpaths, if at all?
  • How would we replace all the functionality that i18next-express-middleware gives us? See #9 (comment)

I 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 (vercel/next.js#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:

  1. Wait for serverless middleware support within NextJs
  2. Fork i18next-express-middleware and refactor out the Express dep, and release a new package, eg i18next-node-middleware
  3. Refactor next-i18next accordingly

If 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 😞

image

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.

  1. I still don't think waiting for middleware is necessary, but thats a personal opinion. If 2 is done ahead of time, its easy enough to implement this step once its available, if the work is already done.
  2. You could very easily roll your own version of that into this repository
  3. Did a little more digging into this, with my comments above.

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 i18next/i18next-express-middleware#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: i18next/i18next-express-middleware#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

  1. 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.
  2. 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.
  3. 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,

@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 vercel/next.js#9081

Hi, just a short update on that issue. The work necessary to fix that issue is

  1. 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.
  2. 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.
  3. 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. :)

commented

@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:

  1. An i18next middleware which does not depend on Express
  2. A nextjs-express-middleware plugin that extends the NextJs middleware req, res, and a few other things

That 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:

  • loading multiple namespaces from remote --> slow processing time for the render
  • CDN does not come for free

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 i18next/i18next-express-middleware#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. gurkerl83/next-i18next-serverless@7b4b1f4 .

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 vercel/next.js#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:

  • Can I just copy the i18n.js file from the example of the temporal save branch?
  • I guess for the above to work I need publicRuntimeConfig: { PROJECT_ROOT: __dirname, },, do I also need the experimental: { 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?

@gurkerl83 hey, that's great news. I have some questions:

  • Can I just copy the i18n.js file from the example of the temporal save branch?
  • I guess for the above to work I need publicRuntimeConfig: { PROJECT_ROOT: __dirname, },, do I also need the experimental: { 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.

project-millipede/millipede-docs@be232a8

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.

Note 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:

  • support on future formats might be limited (i18next now runs in it's 10th year)
  • i18next supports a lot more features (that's a reason for it's size)
  • i18next format is supported in most modern translation management systems
  • we plan to keep moving ;)

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.