Skip to content

Commit

Permalink
fix i18n data pathname resolving
Browse files Browse the repository at this point in the history
  • Loading branch information
ztanner committed Aug 15, 2024
1 parent 162342c commit f7a4e93
Show file tree
Hide file tree
Showing 7 changed files with 134 additions and 36 deletions.
46 changes: 10 additions & 36 deletions packages/next/src/server/lib/router-utils/resolve-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { pathHasPrefix } from '../../../shared/lib/router/utils/path-has-prefix'
import { detectDomainLocale } from '../../../shared/lib/i18n/detect-domain-locale'
import { normalizeLocalePath } from '../../../shared/lib/i18n/normalize-locale-path'
import { removePathPrefix } from '../../../shared/lib/router/utils/remove-path-prefix'
import { getNextPathnameInfo } from '../../../shared/lib/router/utils/get-next-pathname-info'
import { NextDataPathnameNormalizer } from '../../normalizers/request/next-data'
import { BasePathPathnameNormalizer } from '../../normalizers/request/base-path'
import { PostponedPathnameNormalizer } from '../../normalizers/request/postponed'
Expand Down Expand Up @@ -178,54 +179,27 @@ export function getResolveRoutes(
| ReturnType<typeof normalizeLocalePath>
| undefined = undefined

if (config.i18n) {
const hadTrailingSlash = parsedUrl.pathname?.endsWith('/')
const hadBasePath = pathHasPrefix(
parsedUrl.pathname || '',
config.basePath
)
initialLocaleResult = normalizeLocalePath(
removePathPrefix(parsedUrl.pathname || '/', config.basePath),
config.i18n.locales
)
// TODO: This empty pathname fallback mirrors existing handling in this file but it seems
// incorrect that we would ever have an empty pathname here.
const pathnameInfo = getNextPathnameInfo(parsedUrl.pathname || '', {
nextConfig: config,
})

if (config.i18n) {
domainLocale = detectDomainLocale(
config.i18n.domains,
getHostname(parsedUrl, req.headers)
)
defaultLocale = domainLocale?.defaultLocale || config.i18n.defaultLocale

parsedUrl.query.__nextDefaultLocale = defaultLocale
parsedUrl.query.__nextLocale =
initialLocaleResult.detectedLocale || defaultLocale

// ensure locale is present for resolving routes
if (
!initialLocaleResult.detectedLocale &&
!initialLocaleResult.pathname.startsWith('/_next/')
) {
parsedUrl.pathname = addPathPrefix(
initialLocaleResult.pathname === '/'
? `/${defaultLocale}`
: addPathPrefix(
initialLocaleResult.pathname || '',
`/${defaultLocale}`
),
hadBasePath ? config.basePath : ''
)

if (hadTrailingSlash) {
parsedUrl.pathname = maybeAddTrailingSlash(parsedUrl.pathname)
}
}
parsedUrl.query.__nextLocale = pathnameInfo.locale
}

const checkLocaleApi = (pathname: string) => {
if (
config.i18n &&
pathname === urlNoQuery &&
initialLocaleResult?.detectedLocale &&
pathHasPrefix(initialLocaleResult.pathname, '/api')
pathnameInfo.locale &&
pathHasPrefix(pathnameInfo.pathname, '/api')
) {
return true
}
Expand Down
50 changes: 50 additions & 0 deletions test/e2e/i18n-navigations-middleware/i18n-data-route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { nextTestSetup } from 'e2e-utils'

describe('i18n-navigations-middleware', () => {
const { next } = nextTestSetup({
files: __dirname,
})

it('should initially render the default locale', async () => {
const browser = await next.browser('/')
expect(await browser.elementById('current-locale').text()).toBe(
'Current locale: en'
)
})

it('should respect selected locale when navigating to a dynamic route', async () => {
const browser = await next.browser('/')
// change to "de" locale
await browser.elementByCss("[href='/de']").click()
const dynamicLink = await browser.waitForElementByCss(
"[href='/de/dynamic/1']"
)
expect(await browser.elementById('current-locale').text()).toBe(
'Current locale: de'
)

// navigate to dynamic route
await dynamicLink.click()

// the locale should still be "de"
expect(await browser.elementById('dynamic-locale').text()).toBe(
'Locale: de'
)
})

it('should respect selected locale when navigating to a static route', async () => {
const browser = await next.browser('/')
// change to "de" locale
await browser.elementByCss("[href='/de']").click()
const staticLink = await browser.waitForElementByCss("[href='/de/static']")
expect(await browser.elementById('current-locale').text()).toBe(
'Current locale: de'
)

// navigate to static route
await staticLink.click()

// the locale should still be "de"
expect(await browser.elementById('static-locale').text()).toBe('Locale: de')
})
})
6 changes: 6 additions & 0 deletions test/e2e/i18n-navigations-middleware/middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { NextResponse } from 'next/server'

export const config = { matcher: ['/foo'] }
export async function middleware(req) {
return NextResponse.next()
}
9 changes: 9 additions & 0 deletions test/e2e/i18n-navigations-middleware/next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/**
* @type {import('next').NextConfig}
*/
module.exports = {
i18n: {
defaultLocale: 'default',
locales: ['default', 'en', 'de'],
},
}
11 changes: 11 additions & 0 deletions test/e2e/i18n-navigations-middleware/pages/dynamic/[id].js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const getServerSideProps = async ({ locale }) => {
return {
props: {
locale,
},
}
}

export default function Dynamic({ locale }) {
return <div id="dynamic-locale">Locale: {locale}</div>
}
37 changes: 37 additions & 0 deletions test/e2e/i18n-navigations-middleware/pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Link from 'next/link'

export const getServerSideProps = async ({ locale }) => {
return {
props: {
locale,
},
}
}

export default function Home({ locale }) {
return (
<main
style={{
display: 'flex',
flexDirection: 'column',
gap: '20px',
}}
>
<p id="current-locale">Current locale: {locale}</p>
Locale switch:
<Link href="/" locale="default">
Default
</Link>
<Link href="/" locale="en">
English
</Link>
<Link href="/" locale="de">
German
</Link>
<br />
Test links:
<Link href="/dynamic/1">Dynamic 1</Link>
<Link href="/static">Static</Link>
</main>
)
}
11 changes: 11 additions & 0 deletions test/e2e/i18n-navigations-middleware/pages/static.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export const getServerSideProps = async ({ locale }) => {
return {
props: {
locale,
},
}
}

export default function Static({ locale }) {
return <div id="static-locale">Locale: {locale}</div>
}

0 comments on commit f7a4e93

Please sign in to comment.