Skip to content

Commit 3aa622f

Browse files
committed
Add locale false handling
1 parent 4af3611 commit 3aa622f

File tree

5 files changed

+255
-14
lines changed

5 files changed

+255
-14
lines changed

packages/next/client/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,11 +86,11 @@ if (hasBasePath(asPath)) {
8686
if (process.env.__NEXT_I18N_SUPPORT) {
8787
const {
8888
normalizeLocalePath,
89-
} = require('../next-server/lib/i18n/normalize-locale-path')
89+
} = require('../next-server/lib/i18n/normalize-locale-path') as typeof import('../next-server/lib/i18n/normalize-locale-path')
9090

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

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

107107
// attempt detecting default locale based on hostname
108108
const detectedDomain = detectDomainLocale(
109-
process.env.__NEXT_I18N_DOMAINS,
109+
process.env.__NEXT_I18N_DOMAINS as any,
110110
window.location.hostname
111111
)
112112

packages/next/client/link.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ export type LinkProps = {
2626
shallow?: boolean
2727
passHref?: boolean
2828
prefetch?: boolean
29-
locale?: string
29+
locale?: string | false
3030
}
3131
type LinkPropsRequired = RequiredKeys<LinkProps>
3232
type LinkPropsOptional = OptionalKeys<LinkProps>
@@ -127,7 +127,7 @@ function linkClicked(
127127
replace?: boolean,
128128
shallow?: boolean,
129129
scroll?: boolean,
130-
locale?: string
130+
locale?: string | false
131131
): void {
132132
const { nodeName } = e.currentTarget
133133

@@ -344,7 +344,7 @@ function Link(props: React.PropsWithChildren<LinkProps>) {
344344
childProps.href = addBasePath(
345345
addLocale(
346346
as,
347-
locale || (router && router.locale),
347+
typeof locale !== 'undefined' ? locale : router && router.locale,
348348
router && router.defaultLocale
349349
)
350350
)

packages/next/next-server/lib/router/router.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import escapePathDelimiters from './utils/escape-path-delimiters'
2929

3030
interface TransitionOptions {
3131
shallow?: boolean
32-
locale?: string
32+
locale?: string | false
3333
}
3434

3535
interface NextHistoryState {
@@ -58,7 +58,7 @@ function addPathPrefix(path: string, prefix?: string) {
5858

5959
export function addLocale(
6060
path: string,
61-
locale?: string,
61+
locale?: string | false,
6262
defaultLocale?: string
6363
) {
6464
if (process.env.__NEXT_I18N_SUPPORT) {
@@ -553,6 +553,7 @@ export default class Router implements BaseRouter {
553553
as,
554554
Object.assign({}, options, {
555555
shallow: options.shallow && this._shallow,
556+
locale: options.locale || this.defaultLocale,
556557
})
557558
)
558559
}
@@ -600,7 +601,25 @@ export default class Router implements BaseRouter {
600601
window.location.href = url
601602
return false
602603
}
603-
this.locale = options.locale || this.locale
604+
605+
if (process.env.__NEXT_I18N_SUPPORT) {
606+
this.locale = options.locale || this.locale
607+
608+
if (typeof options.locale === 'undefined') {
609+
options.locale = this.locale
610+
}
611+
612+
const {
613+
normalizeLocalePath,
614+
} = require('../i18n/normalize-locale-path') as typeof import('../i18n/normalize-locale-path')
615+
616+
const localePathResult = normalizeLocalePath(as, this.locales)
617+
618+
if (localePathResult.detectedLocale) {
619+
this.locale = localePathResult.detectedLocale
620+
url = localePathResult.pathname
621+
}
622+
}
604623

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

617-
as = addLocale(as, this.locale, this.defaultLocale)
636+
as = addLocale(as, options.locale, this.defaultLocale)
618637
const cleanedAs = delLocale(
619638
hasBasePath(as) ? delBasePath(as) : as,
620639
this.locale
@@ -811,7 +830,7 @@ export default class Router implements BaseRouter {
811830
this.changeState(
812831
method,
813832
url,
814-
addLocale(as, this.locale, this.defaultLocale),
833+
addLocale(as, options.locale, this.defaultLocale),
815834
options
816835
)
817836

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import Link from 'next/link'
2+
import { useRouter } from 'next/router'
3+
4+
export default function Page(props) {
5+
const router = useRouter()
6+
const { nextLocale } = router.query
7+
8+
return (
9+
<>
10+
<p id="links">links page</p>
11+
<p id="props">{JSON.stringify(props)}</p>
12+
<p id="router-locale">{router.locale}</p>
13+
<p id="router-locales">{JSON.stringify(router.locales)}</p>
14+
<p id="router-query">{JSON.stringify(router.query)}</p>
15+
<p id="router-pathname">{router.pathname}</p>
16+
<p id="router-as-path">{router.asPath}</p>
17+
<Link href={`/${nextLocale}/another`} locale={false}>
18+
<a id="to-another">to /another</a>
19+
</Link>
20+
<br />
21+
<Link href={`/${nextLocale}/gsp`} locale={false}>
22+
<a id="to-gsp">to /gsp</a>
23+
</Link>
24+
<br />
25+
<Link href={`/${nextLocale}/gsp/fallback/first`} locale={false}>
26+
<a id="to-fallback-first">to /gsp/fallback/first</a>
27+
</Link>
28+
<br />
29+
<Link href={`/${nextLocale}/gsp/fallback/hello`} locale={false}>
30+
<a id="to-fallback-hello">to /gsp/fallback/hello</a>
31+
</Link>
32+
<br />
33+
<Link href={`/${nextLocale}/gsp/no-fallback/first`} locale={false}>
34+
<a id="to-no-fallback-first">to /gsp/no-fallback/first</a>
35+
</Link>
36+
<br />
37+
<Link href={`/${nextLocale}/gssp`} locale={false}>
38+
<a id="to-gssp">to /gssp</a>
39+
</Link>
40+
<br />
41+
<Link href={`/${nextLocale}/gssp/first`} locale={false}>
42+
<a id="to-gssp-slug">to /gssp/first</a>
43+
</Link>
44+
<br />
45+
</>
46+
)
47+
}
48+
49+
// make SSR page so we have query values immediately
50+
export const getServerSideProps = () => {
51+
return {
52+
props: {},
53+
}
54+
}

test/integration/i18n-support/test/index.test.js

Lines changed: 171 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ function runTests(isDev) {
167167
it('should navigate with locale prop correctly', async () => {
168168
const browser = await webdriver(appPort, '/links?nextLocale=fr')
169169
await addDefaultLocaleCookie(browser)
170+
await browser.eval('window.beforeNav = 1')
170171

171172
expect(await browser.elementByCss('#router-pathname').text()).toBe('/links')
172173
expect(await browser.elementByCss('#router-as-path').text()).toBe(
@@ -208,7 +209,7 @@ function runTests(isDev) {
208209
expect(await browser.elementByCss('#router-as-path').text()).toBe(
209210
'/links?nextLocale=fr'
210211
)
211-
expect(await browser.elementByCss('#router-locale').text()).toBe('fr')
212+
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
212213
expect(
213214
JSON.parse(await browser.elementByCss('#router-locales').text())
214215
).toEqual(locales)
@@ -217,7 +218,7 @@ function runTests(isDev) {
217218
).toEqual({ nextLocale: 'fr' })
218219

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

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

245247
it('should navigate with locale prop correctly GSP', async () => {
@@ -286,16 +288,182 @@ function runTests(isDev) {
286288
expect(await browser.elementByCss('#router-as-path').text()).toBe(
287289
'/links?nextLocale=nl'
288290
)
291+
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
292+
expect(
293+
JSON.parse(await browser.elementByCss('#router-locales').text())
294+
).toEqual(locales)
295+
expect(
296+
JSON.parse(await browser.elementByCss('#router-query').text())
297+
).toEqual({ nextLocale: 'nl' })
298+
299+
parsedUrl = url.parse(await browser.eval('window.location.href'), true)
300+
expect(parsedUrl.pathname).toBe('/links')
301+
expect(parsedUrl.query).toEqual({ nextLocale: 'nl' })
302+
303+
await browser.eval('window.history.forward()')
304+
await browser.waitForElementByCss('#gsp')
305+
306+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
307+
'/gsp/fallback/[slug]'
308+
)
309+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
310+
'/gsp/fallback/first'
311+
)
312+
expect(await browser.elementByCss('#router-locale').text()).toBe('nl')
313+
expect(
314+
JSON.parse(await browser.elementByCss('#router-locales').text())
315+
).toEqual(locales)
316+
expect(
317+
JSON.parse(await browser.elementByCss('#router-query').text())
318+
).toEqual({ slug: 'first' })
319+
320+
parsedUrl = url.parse(await browser.eval('window.location.href'), true)
321+
expect(parsedUrl.pathname).toBe('/nl/gsp/fallback/first')
322+
expect(parsedUrl.query).toEqual({})
323+
})
324+
325+
it('should navigate with locale false correctly', async () => {
326+
const browser = await webdriver(appPort, '/locale-false?nextLocale=fr')
327+
await addDefaultLocaleCookie(browser)
328+
await browser.eval('window.beforeNav = 1')
329+
330+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
331+
'/locale-false'
332+
)
333+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
334+
'/locale-false?nextLocale=fr'
335+
)
336+
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
337+
expect(
338+
JSON.parse(await browser.elementByCss('#router-locales').text())
339+
).toEqual(locales)
340+
expect(
341+
JSON.parse(await browser.elementByCss('#router-query').text())
342+
).toEqual({ nextLocale: 'fr' })
343+
344+
await browser.elementByCss('#to-another').click()
345+
await browser.waitForElementByCss('#another')
346+
347+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
348+
'/another'
349+
)
350+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
351+
'/another'
352+
)
353+
expect(await browser.elementByCss('#router-locale').text()).toBe('fr')
354+
expect(
355+
JSON.parse(await browser.elementByCss('#router-locales').text())
356+
).toEqual(locales)
357+
expect(
358+
JSON.parse(await browser.elementByCss('#router-query').text())
359+
).toEqual({})
360+
361+
let parsedUrl = url.parse(await browser.eval('window.location.href'), true)
362+
expect(parsedUrl.pathname).toBe('/fr/another')
363+
expect(parsedUrl.query).toEqual({})
364+
365+
await browser.eval('window.history.back()')
366+
await browser.waitForElementByCss('#links')
367+
368+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
369+
'/locale-false'
370+
)
371+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
372+
'/locale-false?nextLocale=fr'
373+
)
374+
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
375+
expect(
376+
JSON.parse(await browser.elementByCss('#router-locales').text())
377+
).toEqual(locales)
378+
expect(
379+
JSON.parse(await browser.elementByCss('#router-query').text())
380+
).toEqual({ nextLocale: 'fr' })
381+
382+
parsedUrl = url.parse(await browser.eval('window.location.href'), true)
383+
expect(parsedUrl.pathname).toBe('/locale-false')
384+
expect(parsedUrl.query).toEqual({ nextLocale: 'fr' })
385+
386+
await browser.eval('window.history.forward()')
387+
await browser.waitForElementByCss('#another')
388+
389+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
390+
'/another'
391+
)
392+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
393+
'/another'
394+
)
395+
expect(await browser.elementByCss('#router-locale').text()).toBe('fr')
396+
expect(
397+
JSON.parse(await browser.elementByCss('#router-locales').text())
398+
).toEqual(locales)
399+
expect(
400+
JSON.parse(await browser.elementByCss('#router-query').text())
401+
).toEqual({})
402+
403+
parsedUrl = url.parse(await browser.eval('window.location.href'), true)
404+
expect(parsedUrl.pathname).toBe('/fr/another')
405+
expect(parsedUrl.query).toEqual({})
406+
expect(await browser.eval('window.beforeNav')).toBe(1)
407+
})
408+
409+
it('should navigate with locale false correctly GSP', async () => {
410+
const browser = await webdriver(appPort, '/locale-false?nextLocale=nl')
411+
await addDefaultLocaleCookie(browser)
412+
413+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
414+
'/locale-false'
415+
)
416+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
417+
'/locale-false?nextLocale=nl'
418+
)
419+
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
420+
expect(
421+
JSON.parse(await browser.elementByCss('#router-locales').text())
422+
).toEqual(locales)
423+
expect(
424+
JSON.parse(await browser.elementByCss('#router-query').text())
425+
).toEqual({ nextLocale: 'nl' })
426+
427+
await browser.elementByCss('#to-fallback-first').click()
428+
await browser.waitForElementByCss('#gsp')
429+
430+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
431+
'/gsp/fallback/[slug]'
432+
)
433+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
434+
'/gsp/fallback/first'
435+
)
289436
expect(await browser.elementByCss('#router-locale').text()).toBe('nl')
290437
expect(
291438
JSON.parse(await browser.elementByCss('#router-locales').text())
292439
).toEqual(locales)
440+
expect(
441+
JSON.parse(await browser.elementByCss('#router-query').text())
442+
).toEqual({ slug: 'first' })
443+
444+
let parsedUrl = url.parse(await browser.eval('window.location.href'), true)
445+
expect(parsedUrl.pathname).toBe('/nl/gsp/fallback/first')
446+
expect(parsedUrl.query).toEqual({})
447+
448+
await browser.eval('window.history.back()')
449+
await browser.waitForElementByCss('#links')
450+
451+
expect(await browser.elementByCss('#router-pathname').text()).toBe(
452+
'/locale-false'
453+
)
454+
expect(await browser.elementByCss('#router-as-path').text()).toBe(
455+
'/locale-false?nextLocale=nl'
456+
)
457+
expect(await browser.elementByCss('#router-locale').text()).toBe('en-US')
458+
expect(
459+
JSON.parse(await browser.elementByCss('#router-locales').text())
460+
).toEqual(locales)
293461
expect(
294462
JSON.parse(await browser.elementByCss('#router-query').text())
295463
).toEqual({ nextLocale: 'nl' })
296464

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

301469
await browser.eval('window.history.forward()')

0 commit comments

Comments
 (0)