From 115251bdf9ffb8921c40b3d347562c51ca085645 Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 10:32:32 -0500 Subject: [PATCH 1/9] add i18n --- next.config.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 next.config.js diff --git a/next.config.js b/next.config.js new file mode 100644 index 0000000..490aae3 --- /dev/null +++ b/next.config.js @@ -0,0 +1,19 @@ +module.exports = { + i18n: { + defaultLocale: 'en', + locales: ['en', 'es', 'fr'] + }, + async headers() { + return [ + { + source: '/', + headers: [ + { + key: 'Accept-Language', + value: 'fr;q=0.9', + } + ], + }, + ] + } +} From 8443476cdc4bc0f6230af954f6573211ad9181a4 Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 13:29:07 -0500 Subject: [PATCH 2/9] chore: add manual redirects --- next.config.js | 20 ++++++++++++++------ pages/index.js | 6 +++++- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/next.config.js b/next.config.js index 490aae3..9c784a7 100644 --- a/next.config.js +++ b/next.config.js @@ -3,16 +3,24 @@ module.exports = { defaultLocale: 'en', locales: ['en', 'es', 'fr'] }, - async headers() { + async redirects() { return [ { - source: '/', - headers: [ + source: '/:path*', + has: [ { - key: 'Accept-Language', - value: 'fr;q=0.9', - } + type: 'header', + key: 'Accepted-Language', + value: '(?en|es|fr)', + }, + { + type: 'cookie', + key: 'NEXT_LOCALE', + value: '(?en|es|fr)', + }, ], + permanent: false, + destination: '/:path*', }, ] } diff --git a/pages/index.js b/pages/index.js index 809d0de..4b1f46e 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,8 +1,11 @@ import Head from 'next/head' import Header from '@components/Header' import Footer from '@components/Footer' +import { useRouter } from 'next/router'; export default function Home() { + const { locale } = useRouter(); + return (
@@ -12,8 +15,9 @@ export default function Home() {
+

In v3 of the next plugin, the NEXT_LOCALE and the `Accept-Language` header is not detected. This is fixed in v4. The workaround is manually detecting if the cookie and header exist and changing the behavior of your site in consequence.

- Get started by editing pages/index.js + Locale: {locale}

From f76fcd08066b9e5e4cb19ac0887bf724eb602a6f Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 13:34:34 -0500 Subject: [PATCH 3/9] chore: expand redirect --- next.config.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/next.config.js b/next.config.js index 9c784a7..0a1a81f 100644 --- a/next.config.js +++ b/next.config.js @@ -11,12 +11,12 @@ module.exports = { { type: 'header', key: 'Accepted-Language', - value: '(?en|es|fr)', + value: '(?.*)', }, { type: 'cookie', key: 'NEXT_LOCALE', - value: '(?en|es|fr)', + value: '(?.*)', }, ], permanent: false, From ad496e4f2174f8c82778cfb63d08a69d6677e92b Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 13:52:41 -0500 Subject: [PATCH 4/9] chore: try with middleware --- next.config.js | 21 --------------------- pages/_middleware.js | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 21 deletions(-) create mode 100644 pages/_middleware.js diff --git a/next.config.js b/next.config.js index 0a1a81f..09a50f1 100644 --- a/next.config.js +++ b/next.config.js @@ -2,26 +2,5 @@ module.exports = { i18n: { defaultLocale: 'en', locales: ['en', 'es', 'fr'] - }, - async redirects() { - return [ - { - source: '/:path*', - has: [ - { - type: 'header', - key: 'Accepted-Language', - value: '(?.*)', - }, - { - type: 'cookie', - key: 'NEXT_LOCALE', - value: '(?.*)', - }, - ], - permanent: false, - destination: '/:path*', - }, - ] } } diff --git a/pages/_middleware.js b/pages/_middleware.js new file mode 100644 index 0000000..70c2a38 --- /dev/null +++ b/pages/_middleware.js @@ -0,0 +1,22 @@ +import { NextResponse } from 'next/server' + +const PUBLIC_FILE = /\.(.*)$/ + +export function middleware(request) { + const acceptLanguageHeader = request.headers.get('Accept-Language') + const nextLocaleCookie = request.cookies && request.cookies.NEXT_LOCALE + + if ( + PUBLIC_FILE.test(request.nextUrl.pathname) + || (!acceptLanguageHeader && !nextLocaleCookie) + || (request.nextUrl.pathname.includes(`/${acceptLanguageHeader}/`) || request.nextUrl.pathname.includes(`/${nextLocaleCookie}/`)) + ) { + return undefined + } + + if (nextLocaleCookie) { + return NextResponse.redirect(`/${nextLocaleCookie}${request.nextUrl.href}`) + } + + return NextResponse.redirect(`/${acceptLanguageHeader}${request.nextUrl.href}`) +} \ No newline at end of file From bda2e3a088b6208cd4cbd894f59fafad45330973 Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 13:55:13 -0500 Subject: [PATCH 5/9] chore: fix loop --- pages/_middleware.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pages/_middleware.js b/pages/_middleware.js index 70c2a38..1fd962a 100644 --- a/pages/_middleware.js +++ b/pages/_middleware.js @@ -9,14 +9,20 @@ export function middleware(request) { if ( PUBLIC_FILE.test(request.nextUrl.pathname) || (!acceptLanguageHeader && !nextLocaleCookie) - || (request.nextUrl.pathname.includes(`/${acceptLanguageHeader}/`) || request.nextUrl.pathname.includes(`/${nextLocaleCookie}/`)) ) { return undefined } if (nextLocaleCookie) { + if (request.nextUrl.pathname.includes(`/${nextLocaleCookie}`)) { + return undefined + } return NextResponse.redirect(`/${nextLocaleCookie}${request.nextUrl.href}`) } + if (request.nextUrl.pathname.includes(`/${acceptLanguageHeader}`)) { + return undefined + } + return NextResponse.redirect(`/${acceptLanguageHeader}${request.nextUrl.href}`) } \ No newline at end of file From e3712ac9a8ac59e4e765c91e2ddc53cf1fb61633 Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 14:04:59 -0500 Subject: [PATCH 6/9] chore: test --- pages/_middleware.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pages/_middleware.js b/pages/_middleware.js index 1fd962a..f29a11f 100644 --- a/pages/_middleware.js +++ b/pages/_middleware.js @@ -6,6 +6,7 @@ export function middleware(request) { const acceptLanguageHeader = request.headers.get('Accept-Language') const nextLocaleCookie = request.cookies && request.cookies.NEXT_LOCALE + console.log(request.headers) if ( PUBLIC_FILE.test(request.nextUrl.pathname) || (!acceptLanguageHeader && !nextLocaleCookie) @@ -14,6 +15,7 @@ export function middleware(request) { } if (nextLocaleCookie) { + console.log(request.nextUrl.pathname, request.nextUrl.pathname.includes(`/${nextLocaleCookie}`)) if (request.nextUrl.pathname.includes(`/${nextLocaleCookie}`)) { return undefined } From 6c48481a7c8964ed7c6e725b531ef5db02e01c78 Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 14:36:50 -0500 Subject: [PATCH 7/9] chore: try server side props --- pages/_middleware.js | 30 ------------------------------ pages/index.js | 21 +++++++++++++++++---- 2 files changed, 17 insertions(+), 34 deletions(-) delete mode 100644 pages/_middleware.js diff --git a/pages/_middleware.js b/pages/_middleware.js deleted file mode 100644 index f29a11f..0000000 --- a/pages/_middleware.js +++ /dev/null @@ -1,30 +0,0 @@ -import { NextResponse } from 'next/server' - -const PUBLIC_FILE = /\.(.*)$/ - -export function middleware(request) { - const acceptLanguageHeader = request.headers.get('Accept-Language') - const nextLocaleCookie = request.cookies && request.cookies.NEXT_LOCALE - - console.log(request.headers) - if ( - PUBLIC_FILE.test(request.nextUrl.pathname) - || (!acceptLanguageHeader && !nextLocaleCookie) - ) { - return undefined - } - - if (nextLocaleCookie) { - console.log(request.nextUrl.pathname, request.nextUrl.pathname.includes(`/${nextLocaleCookie}`)) - if (request.nextUrl.pathname.includes(`/${nextLocaleCookie}`)) { - return undefined - } - return NextResponse.redirect(`/${nextLocaleCookie}${request.nextUrl.href}`) - } - - if (request.nextUrl.pathname.includes(`/${acceptLanguageHeader}`)) { - return undefined - } - - return NextResponse.redirect(`/${acceptLanguageHeader}${request.nextUrl.href}`) -} \ No newline at end of file diff --git a/pages/index.js b/pages/index.js index 4b1f46e..5ebfd7c 100644 --- a/pages/index.js +++ b/pages/index.js @@ -1,11 +1,8 @@ import Head from 'next/head' import Header from '@components/Header' import Footer from '@components/Footer' -import { useRouter } from 'next/router'; - -export default function Home() { - const { locale } = useRouter(); +export default function Home({locale}) { return (
@@ -25,3 +22,19 @@ export default function Home() {
) } + +export async function getServerSideProps(context) { + const acceptLanguageHeader = context?.req?.headers['accept-language'] + const nextLocaleCookie = context.req.cookies?.NEXT_LOCALE + const locale = nextLocaleCookie + ? nextLocaleCookie + : acceptLanguageHeader + ? acceptLanguageHeader + : context?.req?.locale || ""; + + return { + props: { + locale + }, // will be passed to the page component as props + } +} \ No newline at end of file From 9f1b11624bf661d354176f643deee6990548bcb5 Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 14:46:30 -0500 Subject: [PATCH 8/9] chore: doublecheck that this works --- pages/index.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pages/index.js b/pages/index.js index 5ebfd7c..f3d2511 100644 --- a/pages/index.js +++ b/pages/index.js @@ -2,7 +2,7 @@ import Head from 'next/head' import Header from '@components/Header' import Footer from '@components/Footer' -export default function Home({locale}) { +export default function Home() { return (
@@ -14,7 +14,7 @@ export default function Home({locale}) {

In v3 of the next plugin, the NEXT_LOCALE and the `Accept-Language` header is not detected. This is fixed in v4. The workaround is manually detecting if the cookie and header exist and changing the behavior of your site in consequence.

- Locale: {locale} + Locale in url

@@ -33,8 +33,6 @@ export async function getServerSideProps(context) { : context?.req?.locale || ""; return { - props: { - locale - }, // will be passed to the page component as props + props: {}, } } \ No newline at end of file From 90b96d11df364d50db701f3e509ed5526398fd18 Mon Sep 17 00:00:00 2001 From: Tiffany Le-Nguyen Date: Fri, 12 Nov 2021 15:02:53 -0500 Subject: [PATCH 9/9] chore: add testing steps --- pages/index.js | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/pages/index.js b/pages/index.js index f3d2511..c7baeb5 100644 --- a/pages/index.js +++ b/pages/index.js @@ -2,7 +2,7 @@ import Head from 'next/head' import Header from '@components/Header' import Footer from '@components/Footer' -export default function Home() { +export default function Home({locale}) { return (
@@ -12,9 +12,31 @@ export default function Home() {
-

In v3 of the next plugin, the NEXT_LOCALE and the `Accept-Language` header is not detected. This is fixed in v4. The workaround is manually detecting if the cookie and header exist and changing the behavior of your site in consequence.

- Locale in url + Locale: {locale} +

+

(you should see it appended to this site's url if your browser does not use the default one, en )

+

In v3 of the next plugin, the NEXT_LOCALE and the `Accept-Language` header is not detected. This is fixed in v4. The workaround is manually detecting if the cookie and header exist and changing the behavior of your site in consequence.

+ See GitHub Issue for full context +

+ Test steps for this page: +

    +
  1. + Change your default browser language to french. In Chrome: language to french (Settings -> Advanced -> Language -> Add French -> Move to top) +
  2. +
  3. + Refresh this page, you should see it appended with /fr, and the text on the page should change to show fr +
  4. +
  5. + Open the dev tools to the console +
  6. +
  7. + Enter document.cookie="NEXT_LOCALE=es" +
  8. +
  9. + Refresh this page. You should see it appended with /es +
  10. +

@@ -25,7 +47,8 @@ export default function Home() { export async function getServerSideProps(context) { const acceptLanguageHeader = context?.req?.headers['accept-language'] - const nextLocaleCookie = context.req.cookies?.NEXT_LOCALE + const nextLocaleCookie = context.req?.cookies?.NEXT_LOCALE + // Force the locale to be either the NEXT_LOCALE cookie or the Accept-Language header const locale = nextLocaleCookie ? nextLocaleCookie : acceptLanguageHeader @@ -33,6 +56,8 @@ export async function getServerSideProps(context) { : context?.req?.locale || ""; return { - props: {}, + props: { + locale + }, } } \ No newline at end of file