Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Next.js 10 localization in pathname #721

Closed
katspaugh opened this issue Oct 29, 2020 · 57 comments
Closed

Next.js 10 localization in pathname #721

katspaugh opened this issue Oct 29, 2020 · 57 comments
Assignees
Labels
enhancement New feature or request release-1.19

Comments

@katspaugh
Copy link

The new built-in localization in Next.js 10 allows to have the locale as a path prefix, e.g.:

/about
/de/about
/es/about

All three routes will open pages/about.tsx. This works fine when I run it locally.
When I deploy it using serverless-next.js, it gives a 404 for /de/about and /es/about. Just /about still works.

Is this something that the Serverless Next.js Component doesn't support yet, or am I doing something wrong?
Thanks!

@dphang dphang added the enhancement New feature or request label Oct 29, 2020
@dphang
Copy link
Collaborator

dphang commented Oct 29, 2020

Yeah, Next.js 10 just came out two days ago, so it'll take some time to add those new features, since we have custom routing/rendering logic optimized for Lambda@Edge. I've tagged this with enhancement.

But I've tested the existing end-to-end tests with Next.js 10 and nothing broke, so looks like all the existing features work as expected.

@LuisFros
Copy link

I am also have the same issue 404 on not root pages.

  • On the root page (/en for example) though, there is a strange behaviour when refreshing page that has locale subpath:
    image
  • There are many redirects with 307 and it crashes.
@dphang dphang self-assigned this Nov 5, 2020
@Lunnatica
Copy link

Hi! I was wondering if there are any updates on this?

@dphang
Copy link
Collaborator

dphang commented Dec 31, 2020

Yes, I have not had a chance to look at it yet, been mostly on vacation mode the past few weeks so haven't worked on the code recently. Hoping to get to it once I'm back next week :)

@Lunnatica
Copy link

Thanks for the update! :) If it helps, when I tried deploying my site with the i18n solution it worked well on all locales, except for the default one, which returned 404 for all routes unless I manually added the locale prefix to the URL path.

Hope you enjoy the rest of your holiday! :)

@Arditc
Copy link

Arditc commented Jan 16, 2021

Hi, I was wondering if there was any updates on this issue?

@dphang
Copy link
Collaborator

dphang commented Jan 19, 2021

I am planning to continue on this during this week. Apologies since lately I was the only contributor for this, so haven't had enough time to both triage issues and work on the codebase..

From initial looks, Next.js will generate new pages for each locale specified (for SSG). So then we would need to just create new routes in our manifests to direct the locale-prefixed paths to the right SSG pages. And without a local-prefix, it should use specified defaultLocale instead. For SSR pages, there is only a single JS file.

@benjipott
Copy link
Contributor

related to #830

@dphang
Copy link
Collaborator

dphang commented Jan 25, 2021

Have published @sls-next/serverless-component@1.19.0-alpha.29 which should have locale subpath routing working. Note that you do need to add Accept-Language header for the root-level locale redirect (it's added by default in default behavior, but if you override it, you will have to add it yourself).

I haven't extensively tested it nor added complete tests for it yet, so please treat it as a preview for now and report any issues by opening a bug report. Thanks!

Note: domain-based routing will be a separate issue

@testreen
Copy link

Thanks for the update, everything is working as expected for us, except for the index.js page when using getStaticProps.

For all locales, the base path returns an AccessDenied error due to index.html not being exported properly to the static-pages folder in S3. All other static routes are being exported properly. Using the trailingSlash config does not solve this issue, and changing getStaticProps to getServerSideProps renders the index path as expected. Let me know if you need more information!

@dphang
Copy link
Collaborator

dphang commented Jan 25, 2021

@testreen thanks! Let me take a look and fix that today. I might have missed testing getStaticProps on index page (only with getServerSideProps.

@Arditc
Copy link

Arditc commented Jan 25, 2021

Hey, many thanks for your update!

I've bumped my app to the latest serverless version, and I seem to experience these issues:

  • The root index page still returns 404 even though I'm sending a accept-lang header via my browser.
  • The localised path e.g. /es returns an s3 error (I wasn't experiencing in the previous version of the serverless alpha release)

Any ideas what could be causing this?

How to possibly reproduce this:
my current next.config.js

module.exports = {
    i18n: {
        locales: ['en', 'es'],
        defaultLocale: 'en',
      },
}

this is my serverless config:

allthemeasurements:
  component: "@sls-next/serverless-component@1.19.0-alpha.29"
  inputs:
    bucketName: xxx
    domain: "xxx.xxx" # sub-domain defaults to www
    roleArn: arn:aws:iam::xxxx
    name:
      defaultLambda: UI
    cloudfront:
      distributionId: xxxx
      defaults:
        forward:
          cookies: "none"

image
image

@dphang
Copy link
Collaborator

dphang commented Jan 25, 2021

Yea, I will rework some of the changes today. Basically with locales then data files and pages would be put into locale-prefixed paths e.g /en/, however for locale index pages it is stored in root as en.html or en.json if you have made it statically generated, instead of index.json or index.html as expected. So it is why there is a 403 access denied.

As fix we need to copy en.html en.json files correctly and reference those instead. Probably easier to rewrite / -> /en internally so that is can reference the en.html page.

Also if using locales, we can just have locale directories e.g /en, /nl and then just rewrite all non-locale-prefixed URLs to add the default locale prefix. E.g / -> /en, /another -> /en/another, so we don't have to maintain default locale pages at the root level too. And also makes fallback page generation easier, since Next.js requests data file using locale path, e.g _next/data/build-id/en/not-yet-generated.json and we just need to generate a page /en/not-yet-generate.html.

@benjipott
Copy link
Contributor

benjipott commented Jan 29, 2021

@dphang all's good for me in production , but
i have the same issue mentioned here #646
all SSG routes with getStaticPaths` fail with 503

all i18n sub routes with SSG are not uploaded to S3 with local path like /_next/data/buildID/fr/auth/signin.json

probably a problem with dataRoutes and 'dataRoutes` in routes-manifest

@dphang
Copy link
Collaborator

dphang commented Feb 4, 2021

Thanks @benjipott for reporting, for that issue #646 I didn't have luck making progress on it. But will look at the other issue.

@benjipott
Copy link
Contributor

@dphang with my latest pr approved and merged, i test only the upload to s3 but i think an other method filter this file because /fr/path/file.json is correctly present in next folder ... no idea why.
I can check it in your related issue, thks @dphang

@dphang
Copy link
Collaborator

dphang commented Feb 10, 2021

@johnaxe not sure, I did not change anything client-side, so perhaps it might be Next.js converting the link component to wrong href? Is that the same behavior on the local dev server?

@krish-dev
Copy link

krish-dev commented Feb 16, 2021

I have noticed one use case that SSG with nextjs i18n only working from the root page (index.jsx). I put the same code on all pages for testing.

/              => working
/en            => working
/ssg-home.     => not working
/en/ssg-home   => not working

Here is my serverless.yml configuration

pocOptim:
    component: '@sls-next/serverless-component@1.19.0-alpha.31'
    inputs:
        memory: 512
        useServerlessTraceTarget: true

This is my i18n config for next.config.js

i18n: {
     localeDetection: false,
     locales: ['en', 'de'],
     defaultLocale: 'en'
},
@dphang
Copy link
Collaborator

dphang commented Feb 16, 2021

@krish-dev thanks, I will take a look, not sure if it's due to serverless trace target (I have only tested without it)

@krish-dev
Copy link

You are correct @dphang, I did some testing without useServerlessTraceTarget: true then it works, but with useServerlessTraceTarget the behavior is the same as I described. However, useServerlessTraceTarget: true is very crucial for the application which has a very long list of SSR pages.

I have noticed one use case that SSG with nextjs i18n only working from the root page (index.jsx). I put the same code on all pages for testing.

/              => working
/en            => working
/ssg-home.     => not working
/en/ssg-home   => not working
@rmulder
Copy link

rmulder commented Apr 2, 2021

@dphang - You are absolutely correct. I re-ran the deploy with alpha.42 version (which is now out) - and that problem has been resolved. My code deploys, and thus far the i18n issues I had been experiencing have been resolved. Thanks!

@rhoiyds
Copy link

rhoiyds commented Apr 20, 2021

@poppein @dphang I'm currently experiencing the next-i18next.config.js non-bundling error as well.
Error: Cannot find module '/builds/<project>/next-i18next.config.js' at webpackEmptyContext (/builds/<project>/.next/serverless/pages/index.js:45452:10) at /builds/<project>/.next/serverless/pages/index.js:803:90

Can either of you share a solution which might help address this? I tried adding a postBuildScipts which looks like this
fs.copySync('./next-i18next.config.js', '/builds/<project>/next-i18next.config.js', { recursive: true }); but no dice.

Any suggestions?

@poppein
Copy link

poppein commented Apr 20, 2021

@rhoiyds I unfortunately revert back to using plain react i18next and not next-18next as i couldn't get it to bundle properly

@rhoiyds
Copy link

rhoiyds commented Apr 20, 2021

@poppein Thank you for letting me know - however that is sad to hear. I'm afraid I might have to do the same, unless @dphang has found a solution.

@gouroujo
Copy link

@rhoiyds I ve managed to make it work by copying my next-i18next.config.js in both the root of my project (alongside next-config) and in my /src folder. I hope it will work for you.

@pawelphilipczyk
Copy link

Great to hear that @gouroujo! Did you manually copied this or do you have some task that you could share?

@rhoiyds
Copy link

rhoiyds commented Apr 20, 2021

@gouroujo Thanks for sharing your solution! I had really high hopes for it, however, unfortunately still no dice. The same error as always. If there's anything else you can share that might help, it would be greatly appreciated.

@rhoiyds
Copy link

rhoiyds commented Apr 26, 2021

Hi all, after days of headaches I've managed to find a workaround which seems to work for me.
Here's some notable configs that managed to work for me, no guarantees for anyone else I suppose.

Removed target: 'serverless' from next.config.js. Also added i18n configs manually.

module.exports = {
  i18n: {
    defaultLocale: 'ja',
    locales: ['en', 'ja']
  }
};

Changed the next-i18next.config file from a .js to a .ts
Updated the contents of the next-i18next.config.ts file to a duplication of what is defined in the next.config.js i18n field.

export const i18n = {
    defaultLocale: 'ja',
    locales: ['en', 'ja']
}

In tsconfig.json (root of the project) I included the newly created next-i18next.config.ts file.

{
  "compilerOptions": {
    "rootDirs": ["src/", "types/", "pages/", "lib/", "components/"],
    "target": "esnext",
    "module": "esnext",
    "jsx": "preserve",
    "lib": ["dom", "es2017"],
    "moduleResolution": "node",
    "allowJs": true,
    "noEmit": true,
    "strict": true,
    "allowSyntheticDefaultImports": true,
    "skipLibCheck": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "removeComments": false,
    "preserveConstEnums": true,
    "sourceMap": true,
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "exclude": ["node_modules"],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", "next-i18next.config.ts"]
}

In _app.tsx, when wrapping the application with the appWithTranslation function, I imported the variable from previously made next-i18next.config.ts config, and passed it as a second parameter to the appWithTranslation function call.

import React, {FC} from 'react';
import {AppProps} from 'next/app';
import { appWithTranslation } from 'next-i18next'
import i18n from '../next-i18next.config'

const WrappedApp: FC<AppProps> = ({ Component, pageProps }) => {

  return (
        <Component {...pageProps} />
  )
}

export default appWithTranslation(WrappedApp, {i18n})

And did so similarly with any page that needs getStaticProps, example page below:

import { serverSideTranslations } from 'next-i18next/serverSideTranslations'
import { useTranslation } from 'next-i18next'
import i18n from '../next-i18next.config'

const TestPage = ({}: Props) => {

const { t } = useTranslation('common')

  return (
      <>
        {t('test')}
        </>
  )
}

export const getStaticProps = async ({ locale } : any) => ({
    props: {
      ...await serverSideTranslations(locale, ['common'], {i18n}),
    }
  })

export default TestPage

What an absolute pain that was. I hope this helps anyone out there with the same issue. Also hope this gets resolved and that serverless next.js can properly locate the module without needing to duplicate the configs.

Just some musings: It seems when you run serverless it duplicates the next-i18next.config.js file and creates another file like next-i18next.config.original<hash>.js not sure if that's the issue or not...

Can provide more details of my projects configs if necessary. Good luck all.

@dphang
Copy link
Collaborator

dphang commented Apr 28, 2021

Thanks all for the help, let me look into it next. Unfortunately I am not using next-i18next myself yet and don't have enough time to look at various integrations (being the primary contributor to this) so I will take a look and try to repro & fix for the next minor version

@thisismydesign
Copy link

@rhoiyds' approach worked. You can see the same conclusion here: i18next/next-i18next#990 (comment)

@ignaciolarranaga
Copy link

Guys, is the automatic locale selection working for you guys in AWS/LambdaEdge?
I can access the routes by directly pointing to them but the locale selection/redirection is not working (i.e. it just stays in english, the default).

@dphang
Copy link
Collaborator

dphang commented May 15, 2021

Guys, is the automatic locale selection working for you guys in AWS/LambdaEdge?

I can access the routes by directly pointing to them but the locale selection/redirection is not working (i.e. it just stays in english, the default).

Are you forwarding the Accept-Language header in CloudFront configuration? This is needed to detect the user's locale

@ignaciolarranaga
Copy link

Yes, that seems to be the problem, I'm checking how to change the Cloudfront behavior (I thought it was done :) )

@Arditc
Copy link

Arditc commented May 15, 2021

Guys, is the automatic locale selection working for you guys in AWS/LambdaEdge?
I can access the routes by directly pointing to them but the locale selection/redirection is not working (i.e. it just stays in english, the default).

Are you forwarding the Accept-Language header in CloudFront configuration? This is needed to detect the user's locale

So I tried this, and things sadly didn't work as expected.

I added Accept-Language to the nextjs serverless configuration.
When my Language is 'es' and I land on mywebsite.com/
I get redirected to mywebsite.com/es
and then I notice an infinite 307 redirects to /es after this

After I removed the Accept-Language Header in the serverless configuration, I still see it in Cloudfront (see screenshot) for the Path Pattern Default (*). (Not sure what I need to add in the serverless config so I stop seeing it appear in Cloudfront😞 )

Screenshot 2021-05-15 at 19 45 10

Update: I ended up putting headers: "none" for the time being.

@ignaciolarranaga
Copy link

ignaciolarranaga commented May 15, 2021

On my case it is working as expected, weird.

Leaving the CDK code just in case it is useful for someone:

    const cachePolicy = new CachePolicy(this, `DefaultCachePolicy${capitalize(env)}`, {
      cachePolicyName: `DefaultCachePolicy${capitalize(env)}`,
      comment: 'The default policy to be used in the cache',
      cookieBehavior: CacheCookieBehavior.all(),
      headerBehavior: CacheHeaderBehavior.allowList('Accept-Language'),
      queryStringBehavior: CacheQueryStringBehavior.all(),
      enableAcceptEncodingGzip: true,
      enableAcceptEncodingBrotli: true, // spellchecker: disable-line
    });

    const nextLambdaEdge = new NextJSLambdaEdge(this, `Cloudfront${capitalize(env)}`, {
      ...
      defaultBehavior: {
        cachePolicy
      }
    });
@Lunnatica
Copy link

Guys, is the automatic locale selection working for you guys in AWS/LambdaEdge?
I can access the routes by directly pointing to them but the locale selection/redirection is not working (i.e. it just stays in english, the default).

Are you forwarding the Accept-Language header in CloudFront configuration? This is needed to detect the user's locale

So I tried this, and things sadly didn't work as expected.

I added Accept-Language to the nextjs serverless configuration.
When my Language is 'es' and I land on mywebsite.com/
I get redirected to mywebsite.com/es
and then I notice an infinite 307 redirects to /es after this

After I removed the Accept-Language Header in the serverless configuration, I still see it in Cloudfront (see screenshot) for the Path Pattern Default (*). (Not sure what I need to add in the serverless config so I stop seeing it appear in Cloudfront😞 )

Screenshot 2021-05-15 at 19 45 10

Update: I ended up putting headers: "none" for the time being.

It was giving me this error too when using the latest version @sls-next/serverless-component@1.19.1-alpha.7 - but I managed to fix it by downgrading to the latest stable version (@sls-next/serverless-component@1.19.0) and now it works fine.

@ignaciolarranaga
Copy link

By the way, somebody found how to fallback to the most approximate locale?

Example:

// next.config.js
module.exports = {
  i18n: {
    locales: ['en', 'es''],
    defaultLocale: 'en',
  },
}

When I hit with Accept-Language: 'es-ES' instead of falling back to 'es' it falls back to 'en' (which is a little bit awkward since locale='es' would be much more appropriate). Does it needs to be custom made?, or is there some trick we can use?

@Lunnatica
Copy link

Lunnatica commented May 15, 2021

@ignaciolarranaga I'm having the same problem. It works fine locally, but not after deploying to production.

Update: it seems to be an issue with Next.js vercel/next.js#20488

@ignaciolarranaga
Copy link

ignaciolarranaga commented May 22, 2021

Hey, just migrated to 1.9.0-alpha.4 and keeps in loop when not correctly recognize the locale.
For example, My browser by default sends: accept-language: es-419,es;q=0.9, this forces the jump to /es but later keeps looping over that.

@dphang
Copy link
Collaborator

dphang commented Jun 9, 2021

I think most of the major issues (locale redirection, precedence etc.) should be fixed now in the latest versions, so I'll close this and please open a new issue so it's easier to track specific issues. Thanks!

@dphang dphang closed this as completed Jun 9, 2021
@rhoiyds
Copy link

rhoiyds commented Jun 10, 2021

Sorry to continue the discussion, but I reverted all of my previously mentioned changes, updated to the latest version of serverless component as well as nexti18next and tested a serverless deployment. It successfully deploys, however all I get is 404's on all of my routes.

@dphang
Copy link
Collaborator

dphang commented Jun 10, 2021

Sorry to continue the discussion, but I reverted all of my previously mentioned changes, updated to the latest version of serverless component as well as nexti18next and tested a serverless deployment. It successfully deploys, however all I get is 404's on all of my routes.

Can you post any more details of .serverless_nextjs directory / manifests and also if there is any reproduction you can share. Might be good to open a new issue so it's easier to isolate the problem?

@sedagulkesen
Copy link

Hey, I was wondering if there were any updates on this issue?

@dphang
Copy link
Collaborator

dphang commented Jul 8, 2021

@sedagulkesen sorry, not sure specifically what update you were looking for? What issue are you facing? Since this one was closed and I did not get any other responses after the latest comments.

I would say to better isolate any issues, please open a new issue with specific details.

@sedagulkesen
Copy link

sedagulkesen commented Jul 9, 2021

@sedagulkesen sorry, not sure specifically what update you were looking for? What issue are you facing? Since this one was closed and I did not get any other responses after the latest comments.

I would say to better isolate any issues, please open a new issue with specific details.

I am using Nextjs version 11.
I have implemented i18n solution and this is my next.config.ts :

 i18n: {
    locales: ['en', 'fr', 'nl', 'de'],
    defaultLocale: 'en',
  },

With this configuration, all the routes are available. It is working on my locale perfectly. However, when I deploy it using serverless-next.js it gives 404 for all the routes by default. Unless I manually add the locale prefix to the URL path, it is not working. So initially /overview.tsx doesn't work if I add en/overview.tst it works then when I refresh it is gone.

Could you please help me out with this?

update: it was about the Dockerfile, copying next.config.js file in the Dockerfile, to where i18n config did the trick.

COPY ./next.config.js /app/next.config.js
@dphang
Copy link
Collaborator

dphang commented Jul 9, 2021

Thanks @sedagulkesen for the update, glad to hear you managed to solve it. For reference if you have further problems, it would be good to try to repro the problem using our test app: https://github.com/serverless-nextjs/serverless-next.js/tree/master/packages/e2e-tests/next-app-with-locales (this is the one we run tests on, so if something is broken and you can repro here, it will make it easier to fix and add test coverage on).

@engelmav
Copy link

This threw me into a panic for several hours. I am very grateful for your sharing the solution as it resolved the issue for me as well.

Specifically see this example - vercel/next.js#16995 (comment)

@jose-fmeyer
Copy link
Contributor

jose-fmeyer commented Sep 4, 2021

Note: domain-based routing will be a separate issue

Hey @dphang, was an issue related to domain-based routing created? I’m trying to use internationalized routing based on domain in the latest version and I could manage only on the default locale or when I explicitly set the locale in the path.

I saw this issue but was not sure it is the one addressing the problem I described #1283

Thanks for the support

@moonston
Copy link

@sedagulkesen sorry, not sure specifically what update you were looking for? What issue are you facing? Since this one was closed and I did not get any other responses after the latest comments.
I would say to better isolate any issues, please open a new issue with specific details.

I am using Nextjs version 11. I have implemented i18n solution and this is my next.config.ts :

 i18n: {
    locales: ['en', 'fr', 'nl', 'de'],
    defaultLocale: 'en',
  },

With this configuration, all the routes are available. It is working on my locale perfectly. However, when I deploy it using serverless-next.js it gives 404 for all the routes by default. Unless I manually add the locale prefix to the URL path, it is not working. So initially /overview.tsx doesn't work if I add en/overview.tst it works then when I refresh it is gone.

Could you please help me out with this?

update: it was about the Dockerfile, copying next.config.js file in the Dockerfile, to where i18n config did the trick.

COPY ./next.config.js /app/next.config.js

@sedagulkesen

Thank you for the fix, :)
For me i added 2 more lines, then it works :D
COPY --from=builder /app/i18n.json ./i18n.json
COPY --from=builder /app/pages ./pages

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment