Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/next/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ if (hasBasePath(asPath)) {
if (process.env.__NEXT_I18N_SUPPORT) {
const {
normalizeLocalePath,
} = require('../next-server/lib/i18n/normalize-locale-path')
} = require('../next-server/lib/i18n/normalize-locale-path') as typeof import('../next-server/lib/i18n/normalize-locale-path')

const {
detectDomainLocale,
} = require('../next-server/lib/i18n/detect-domain-locale')
} = require('../next-server/lib/i18n/detect-domain-locale') as typeof import('../next-server/lib/i18n/detect-domain-locale')

if (locales) {
const localePathResult = normalizeLocalePath(asPath, locales)
Expand All @@ -106,7 +106,7 @@ if (process.env.__NEXT_I18N_SUPPORT) {

// attempt detecting default locale based on hostname
const detectedDomain = detectDomainLocale(
process.env.__NEXT_I18N_DOMAINS,
process.env.__NEXT_I18N_DOMAINS as any,
window.location.hostname
)

Expand Down
6 changes: 3 additions & 3 deletions packages/next/client/link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export type LinkProps = {
shallow?: boolean
passHref?: boolean
prefetch?: boolean
locale?: string
locale?: string | false
}
type LinkPropsRequired = RequiredKeys<LinkProps>
type LinkPropsOptional = OptionalKeys<LinkProps>
Expand Down Expand Up @@ -127,7 +127,7 @@ function linkClicked(
replace?: boolean,
shallow?: boolean,
scroll?: boolean,
locale?: string
locale?: string | false
): void {
const { nodeName } = e.currentTarget

Expand Down Expand Up @@ -344,7 +344,7 @@ function Link(props: React.PropsWithChildren<LinkProps>) {
childProps.href = addBasePath(
addLocale(
as,
locale || (router && router.locale),
typeof locale !== 'undefined' ? locale : router && router.locale,
router && router.defaultLocale
)
)
Expand Down
29 changes: 24 additions & 5 deletions packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import escapePathDelimiters from './utils/escape-path-delimiters'

interface TransitionOptions {
shallow?: boolean
locale?: string
locale?: string | false
}

interface NextHistoryState {
Expand Down Expand Up @@ -58,7 +58,7 @@ function addPathPrefix(path: string, prefix?: string) {

export function addLocale(
path: string,
locale?: string,
locale?: string | false,
defaultLocale?: string
) {
if (process.env.__NEXT_I18N_SUPPORT) {
Expand Down Expand Up @@ -553,6 +553,7 @@ export default class Router implements BaseRouter {
as,
Object.assign({}, options, {
shallow: options.shallow && this._shallow,
locale: options.locale || this.defaultLocale,
})
)
}
Expand Down Expand Up @@ -600,7 +601,25 @@ export default class Router implements BaseRouter {
window.location.href = url
return false
}
this.locale = options.locale || this.locale

if (process.env.__NEXT_I18N_SUPPORT) {
this.locale = options.locale || this.locale

if (typeof options.locale === 'undefined') {
options.locale = this.locale
}

const {
normalizeLocalePath,
} = require('../i18n/normalize-locale-path') as typeof import('../i18n/normalize-locale-path')

const localePathResult = normalizeLocalePath(as, this.locales)

if (localePathResult.detectedLocale) {
this.locale = localePathResult.detectedLocale
url = localePathResult.pathname
}
}

if (!(options as any)._h) {
this.isSsr = false
Expand All @@ -614,7 +633,7 @@ export default class Router implements BaseRouter {
this.abortComponentLoad(this._inFlightRoute)
}

as = addLocale(as, this.locale, this.defaultLocale)
as = addLocale(as, options.locale, this.defaultLocale)
const cleanedAs = delLocale(
hasBasePath(as) ? delBasePath(as) : as,
this.locale
Expand Down Expand Up @@ -811,7 +830,7 @@ export default class Router implements BaseRouter {
this.changeState(
method,
url,
addLocale(as, this.locale, this.defaultLocale),
addLocale(as, options.locale, this.defaultLocale),
options
)

Expand Down
54 changes: 54 additions & 0 deletions test/integration/i18n-support/pages/locale-false.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import Link from 'next/link'
import { useRouter } from 'next/router'

export default function Page(props) {
const router = useRouter()
const { nextLocale } = router.query

return (
<>
<p id="links">links page</p>
<p id="props">{JSON.stringify(props)}</p>
<p id="router-locale">{router.locale}</p>
<p id="router-locales">{JSON.stringify(router.locales)}</p>
<p id="router-query">{JSON.stringify(router.query)}</p>
<p id="router-pathname">{router.pathname}</p>
<p id="router-as-path">{router.asPath}</p>
<Link href={`/${nextLocale}/another`} locale={false}>
<a id="to-another">to /another</a>
</Link>
<br />
<Link href={`/${nextLocale}/gsp`} locale={false}>
<a id="to-gsp">to /gsp</a>
</Link>
<br />
<Link href={`/${nextLocale}/gsp/fallback/first`} locale={false}>
<a id="to-fallback-first">to /gsp/fallback/first</a>
</Link>
<br />
<Link href={`/${nextLocale}/gsp/fallback/hello`} locale={false}>
<a id="to-fallback-hello">to /gsp/fallback/hello</a>
</Link>
<br />
<Link href={`/${nextLocale}/gsp/no-fallback/first`} locale={false}>
<a id="to-no-fallback-first">to /gsp/no-fallback/first</a>
</Link>
<br />
<Link href={`/${nextLocale}/gssp`} locale={false}>
<a id="to-gssp">to /gssp</a>
</Link>
<br />
<Link href={`/${nextLocale}/gssp/first`} locale={false}>
<a id="to-gssp-slug">to /gssp/first</a>
</Link>
<br />
</>
)
}

// make SSR page so we have query values immediately
export const getServerSideProps = () => {
return {
props: {},
}
}
174 changes: 171 additions & 3 deletions test/integration/i18n-support/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ function runTests(isDev) {
it('should navigate with locale prop correctly', async () => {
const browser = await webdriver(appPort, '/links?nextLocale=fr')
await addDefaultLocaleCookie(browser)
await browser.eval('window.beforeNav = 1')

expect(await browser.elementByCss('#router-pathname').text()).toBe('/links')
expect(await browser.elementByCss('#router-as-path').text()).toBe(
Expand Down Expand Up @@ -208,7 +209,7 @@ function runTests(isDev) {
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/links?nextLocale=fr'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('fr')
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
Expand All @@ -217,7 +218,7 @@ function runTests(isDev) {
).toEqual({ nextLocale: 'fr' })

parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/fr/links')
expect(parsedUrl.pathname).toBe('/links')
expect(parsedUrl.query).toEqual({ nextLocale: 'fr' })

await browser.eval('window.history.forward()')
Expand All @@ -240,6 +241,7 @@ function runTests(isDev) {
parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/fr/another')
expect(parsedUrl.query).toEqual({})
expect(await browser.eval('window.beforeNav')).toBe(1)
})

it('should navigate with locale prop correctly GSP', async () => {
Expand Down Expand Up @@ -286,16 +288,182 @@ function runTests(isDev) {
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/links?nextLocale=nl'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({ nextLocale: 'nl' })

parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/links')
expect(parsedUrl.query).toEqual({ nextLocale: 'nl' })

await browser.eval('window.history.forward()')
await browser.waitForElementByCss('#gsp')

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/gsp/fallback/[slug]'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/gsp/fallback/first'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('nl')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({ slug: 'first' })

parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/nl/gsp/fallback/first')
expect(parsedUrl.query).toEqual({})
})

it('should navigate with locale false correctly', async () => {
const browser = await webdriver(appPort, '/locale-false?nextLocale=fr')
await addDefaultLocaleCookie(browser)
await browser.eval('window.beforeNav = 1')

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/locale-false'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/locale-false?nextLocale=fr'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({ nextLocale: 'fr' })

await browser.elementByCss('#to-another').click()
await browser.waitForElementByCss('#another')

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/another'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/another'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('fr')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({})

let parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/fr/another')
expect(parsedUrl.query).toEqual({})

await browser.eval('window.history.back()')
await browser.waitForElementByCss('#links')

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/locale-false'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/locale-false?nextLocale=fr'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({ nextLocale: 'fr' })

parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/locale-false')
expect(parsedUrl.query).toEqual({ nextLocale: 'fr' })

await browser.eval('window.history.forward()')
await browser.waitForElementByCss('#another')

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/another'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/another'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('fr')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({})

parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/fr/another')
expect(parsedUrl.query).toEqual({})
expect(await browser.eval('window.beforeNav')).toBe(1)
})

it('should navigate with locale false correctly GSP', async () => {
const browser = await webdriver(appPort, '/locale-false?nextLocale=nl')
await addDefaultLocaleCookie(browser)

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/locale-false'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/locale-false?nextLocale=nl'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({ nextLocale: 'nl' })

await browser.elementByCss('#to-fallback-first').click()
await browser.waitForElementByCss('#gsp')

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/gsp/fallback/[slug]'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/gsp/fallback/first'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('nl')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({ slug: 'first' })

let parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/nl/gsp/fallback/first')
expect(parsedUrl.query).toEqual({})

await browser.eval('window.history.back()')
await browser.waitForElementByCss('#links')

expect(await browser.elementByCss('#router-pathname').text()).toBe(
'/locale-false'
)
expect(await browser.elementByCss('#router-as-path').text()).toBe(
'/locale-false?nextLocale=nl'
)
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
expect(
JSON.parse(await browser.elementByCss('#router-locales').text())
).toEqual(locales)
expect(
JSON.parse(await browser.elementByCss('#router-query').text())
).toEqual({ nextLocale: 'nl' })

parsedUrl = url.parse(await browser.eval('window.location.href'), true)
expect(parsedUrl.pathname).toBe('/nl/links')
expect(parsedUrl.pathname).toBe('/locale-false')
expect(parsedUrl.query).toEqual({ nextLocale: 'nl' })

await browser.eval('window.history.forward()')
Expand Down