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

Add locale false handling #18115

Merged
merged 3 commits into from Oct 22, 2020
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/next/client/index.tsx
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
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
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
@@ -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
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