Skip to content

Commit 7905403

Browse files
authored
Merge branch 'canary' into patch-1
2 parents 398037c + 854a849 commit 7905403

File tree

6 files changed

+86
-26
lines changed

6 files changed

+86
-26
lines changed

packages/next/build/webpack/loaders/next-serverless-loader.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,10 +241,10 @@ const nextServerlessLoader: loader.Loader = function () {
241241
}
242242
243243
const denormalizedPagePath = denormalizePagePath(parsedUrl.pathname || '/')
244-
const detectedDefaultLocale = !detectedLocale || detectedLocale === defaultLocale
244+
const detectedDefaultLocale = !detectedLocale || detectedLocale.toLowerCase() === defaultLocale.toLowerCase()
245245
const shouldStripDefaultLocale =
246246
detectedDefaultLocale &&
247-
denormalizedPagePath === \`/\${defaultLocale}\`
247+
denormalizedPagePath.toLowerCase() === \`/\${defaultLocale.toLowerCase()}\`
248248
const shouldAddLocalePrefix =
249249
!detectedDefaultLocale && denormalizedPagePath === '/'
250250

packages/next/client/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ if (process.env.__NEXT_i18n_SUPPORT) {
9292
const localePathResult = normalizeLocalePath(asPath, locales)
9393

9494
if (localePathResult.detectedLocale) {
95-
asPath = asPath.substr(localePathResult.detectedLocale.length + 1)
95+
asPath = asPath.substr(localePathResult.detectedLocale.length + 1) || '/'
9696
} else {
9797
// derive the default locale if it wasn't detected in the asPath
9898
// since we don't prerender static pages with all possible default
Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,10 @@
11
import { IncomingMessage } from 'http'
22

33
export function detectLocaleCookie(req: IncomingMessage, locales: string[]) {
4-
let detectedLocale: string | undefined
5-
64
if (req.headers.cookie && req.headers.cookie.includes('NEXT_LOCALE')) {
75
const { NEXT_LOCALE } = (req as any).cookies
8-
9-
if (locales.some((locale: string) => NEXT_LOCALE === locale)) {
10-
detectedLocale = NEXT_LOCALE
11-
}
6+
return locales.find(
7+
(locale: string) => NEXT_LOCALE.toLowerCase() === locale.toLowerCase()
8+
)
129
}
13-
14-
return detectedLocale
1510
}

packages/next/next-server/lib/i18n/normalize-locale-path.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export function normalizeLocalePath(
1010
const pathnameParts = pathname.split('/')
1111

1212
;(locales || []).some((locale) => {
13-
if (pathnameParts[1] === locale) {
13+
if (pathnameParts[1].toLowerCase() === locale.toLowerCase()) {
1414
detectedLocale = locale
1515
pathnameParts.splice(1, 1)
1616
pathname = pathnameParts.join('/') || '/'

packages/next/next-server/server/next-server.ts

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -324,9 +324,11 @@ export default class Server {
324324

325325
const denormalizedPagePath = denormalizePagePath(pathname || '/')
326326
const detectedDefaultLocale =
327-
!detectedLocale || detectedLocale === defaultLocale
327+
!detectedLocale ||
328+
detectedLocale.toLowerCase() === defaultLocale.toLowerCase()
328329
const shouldStripDefaultLocale =
329-
detectedDefaultLocale && denormalizedPagePath === `/${defaultLocale}`
330+
detectedDefaultLocale &&
331+
denormalizedPagePath.toLowerCase() === `/${defaultLocale.toLowerCase()}`
330332
const shouldAddLocalePrefix =
331333
!detectedDefaultLocale && denormalizedPagePath === '/'
332334

@@ -1148,6 +1150,13 @@ export default class Server {
11481150
const isDataReq = !!query._nextDataReq && (isSSG || isServerProps)
11491151
delete query._nextDataReq
11501152

1153+
const locale = query.__nextLocale as string
1154+
const locales = query.__nextLocales as string[]
1155+
// const defaultLocale = query.__nextDefaultLocale as string
1156+
delete query.__nextLocale
1157+
delete query.__nextLocales
1158+
// delete query.__nextDefaultLocale
1159+
11511160
let previewData: string | false | object | undefined
11521161
let isPreviewMode = false
11531162

@@ -1176,7 +1185,7 @@ export default class Server {
11761185
}
11771186

11781187
if (this.nextConfig.experimental.i18n) {
1179-
return normalizeLocalePath(path, this.renderOpts.locales).pathname
1188+
return normalizeLocalePath(path, locales).pathname
11801189
}
11811190
return path
11821191
}
@@ -1188,13 +1197,6 @@ export default class Server {
11881197
urlPathname = stripNextDataPath(urlPathname)
11891198
}
11901199

1191-
const locale = query.__nextLocale as string
1192-
const locales = query.__nextLocales as string[]
1193-
// const defaultLocale = query.__nextDefaultLocale as string
1194-
delete query.__nextLocale
1195-
delete query.__nextLocales
1196-
// delete query.__nextDefaultLocale
1197-
11981200
const ssgCacheKey =
11991201
isPreviewMode || !isSSG
12001202
? undefined // Preview mode bypasses the cache

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

Lines changed: 67 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,46 @@ let appPort
2626

2727
const locales = ['en-US', 'nl-NL', 'nl-BE', 'nl', 'fr-BE', 'fr', 'en']
2828

29-
function runTests() {
29+
function runTests(isDev) {
30+
it('should update asPath on the client correctly', async () => {
31+
for (const check of ['en', 'En']) {
32+
const browser = await webdriver(appPort, `/${check}`)
33+
34+
expect(await browser.elementByCss('html').getAttribute('lang')).toBe('en')
35+
expect(await browser.elementByCss('#router-locale').text()).toBe('en')
36+
expect(
37+
JSON.parse(await browser.elementByCss('#router-locales').text())
38+
).toEqual(locales)
39+
expect(await browser.elementByCss('#router-as-path').text()).toBe('/')
40+
expect(await browser.elementByCss('#router-pathname').text()).toBe('/')
41+
}
42+
})
43+
44+
if (!isDev) {
45+
it('should handle fallback correctly after generating', async () => {
46+
const browser = await webdriver(
47+
appPort,
48+
'/en/gsp/fallback/hello-fallback'
49+
)
50+
51+
// wait for the fallback to be generated/stored to ISR cache
52+
browser.waitForElementByCss('#gsp')
53+
54+
// now make sure we're serving the previously generated file from the cache
55+
const html = await renderViaHTTP(
56+
appPort,
57+
'/en/gsp/fallback/hello-fallback'
58+
)
59+
const $ = cheerio.load(html)
60+
61+
expect($('#gsp').text()).toBe('gsp page')
62+
expect($('#router-locale').text()).toBe('en')
63+
expect(JSON.parse($('#router-locales').text())).toEqual(locales)
64+
expect($('#router-pathname').text()).toBe('/gsp/fallback/[slug]')
65+
expect($('#router-as-path').text()).toBe('/gsp/fallback/hello-fallback')
66+
})
67+
}
68+
3069
it('should use correct default locale for locale domains', async () => {
3170
const res = await fetchViaHTTP(appPort, '/', undefined, {
3271
headers: {
@@ -173,6 +212,15 @@ function runTests() {
173212
expect($('#router-as-path').text()).toBe('/gsp')
174213
expect($('#router-pathname').text()).toBe('/gsp')
175214
expect(JSON.parse($('#router-locales').text())).toEqual(locales)
215+
216+
// make sure locale is case-insensitive
217+
const html2 = await renderViaHTTP(appPort, `/${locale.toUpperCase()}/gsp`)
218+
const $2 = cheerio.load(html2)
219+
expect($2('html').attr('lang')).toBe(locale)
220+
expect($2('#router-locale').text()).toBe(locale)
221+
expect($2('#router-as-path').text()).toBe('/gsp')
222+
expect($2('#router-pathname').text()).toBe('/gsp')
223+
expect(JSON.parse($2('#router-locales').text())).toEqual(locales)
176224
}
177225
})
178226

@@ -193,6 +241,21 @@ function runTests() {
193241

194242
expect(parsedUrl.pathname).toBe('/')
195243
expect(parsedUrl.query).toEqual({})
244+
245+
// make sure locale is case-insensitive
246+
const res2 = await fetchViaHTTP(appPort, '/eN-Us', undefined, {
247+
redirect: 'manual',
248+
headers: {
249+
'Accept-Language': 'en-US;q=0.9',
250+
},
251+
})
252+
253+
expect(res2.status).toBe(307)
254+
255+
const parsedUrl2 = url.parse(res.headers.get('location'), true)
256+
257+
expect(parsedUrl2.pathname).toBe('/')
258+
expect(parsedUrl2.query).toEqual({})
196259
})
197260

198261
it('should load getStaticProps page correctly SSR (default locale no prefix)', async () => {
@@ -391,8 +454,8 @@ function runTests() {
391454
it('should navigate client side for default locale with no prefix', async () => {
392455
const browser = await webdriver(appPort, '/')
393456
// make sure default locale is used in case browser isn't set to
394-
// favor en-US by default
395-
await browser.manage().addCookie({ name: 'NEXT_LOCALE', value: 'en-US' })
457+
// favor en-US by default, (we use all caps to ensure it's case-insensitive)
458+
await browser.manage().addCookie({ name: 'NEXT_LOCALE', value: 'EN-US' })
396459
await browser.get(browser.initUrl)
397460

398461
const checkIndexValues = async () => {
@@ -705,7 +768,7 @@ describe('i18n Support', () => {
705768
})
706769
afterAll(() => killApp(app))
707770

708-
runTests()
771+
runTests(true)
709772
})
710773

711774
describe('production mode', () => {

0 commit comments

Comments
 (0)