@@ -363,35 +363,41 @@ describe('prefix-based routing', () => {
363
363
describe ( 'localized pathnames' , ( ) => {
364
364
const middlewareWithPathnames = createIntlMiddleware ( {
365
365
defaultLocale : 'en' ,
366
- locales : [ 'en' , 'de' ] ,
366
+ locales : [ 'en' , 'de' , 'de-AT' ] ,
367
367
localePrefix : 'as-needed' ,
368
368
pathnames : {
369
369
'/' : '/' ,
370
370
'/about' : {
371
371
en : '/about' ,
372
- de : '/ueber'
372
+ de : '/ueber' ,
373
+ 'de-AT' : '/ueber'
373
374
} ,
374
375
'/users' : {
375
376
en : '/users' ,
376
- de : '/benutzer'
377
+ de : '/benutzer' ,
378
+ 'de-AT' : '/benutzer'
377
379
} ,
378
380
'/users/[userId]' : {
379
381
en : '/users/[userId]' ,
380
- de : '/benutzer/[userId]'
382
+ de : '/benutzer/[userId]' ,
383
+ 'de-AT' : '/benutzer/[userId]'
381
384
} ,
382
385
'/news/[articleSlug]-[articleId]' : {
383
386
en : '/news/[articleSlug]-[articleId]' ,
384
- de : '/neuigkeiten/[articleSlug]-[articleId]'
387
+ de : '/neuigkeiten/[articleSlug]-[articleId]' ,
388
+ 'de-AT' : '/neuigkeiten/[articleSlug]-[articleId]'
385
389
} ,
386
390
'/products/[...slug]' : {
387
391
en : '/products/[...slug]' ,
388
- de : '/produkte/[...slug]'
392
+ de : '/produkte/[...slug]' ,
393
+ 'de-AT' : '/produkte/[...slug]'
389
394
} ,
390
395
'/categories/[[...slug]]' : {
391
396
en : '/categories/[[...slug]]' ,
392
- de : '/kategorien/[[...slug]]'
397
+ de : '/kategorien/[[...slug]]' ,
398
+ 'de-AT' : '/kategorien/[[...slug]]'
393
399
}
394
- } satisfies Pathnames < ReadonlyArray < 'en' | 'de' > >
400
+ } satisfies Pathnames < ReadonlyArray < 'en' | 'de' | 'de-AT' > >
395
401
} ) ;
396
402
397
403
it ( 'serves requests for the default locale at the root' , ( ) => {
@@ -531,6 +537,66 @@ describe('prefix-based routing', () => {
531
537
) ;
532
538
} ) ;
533
539
540
+ it ( 'redirects uppercase locale requests to case-sensitive defaults at the root' , ( ) => {
541
+ middlewareWithPathnames ( createMockRequest ( '/EN' , 'de' ) ) ;
542
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
543
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
544
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
545
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
546
+ 'http://localhost:3000/en/'
547
+ ) ;
548
+ } ) ;
549
+
550
+ it ( 'redirects uppercase locale requests to case-sensitive defaults for nested paths' , ( ) => {
551
+ middlewareWithPathnames ( createMockRequest ( '/EN/about' , 'de' ) ) ;
552
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
553
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
554
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
555
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
556
+ 'http://localhost:3000/en/about'
557
+ ) ;
558
+ } ) ;
559
+
560
+ it ( 'redirects uppercase locale requests for non-default locales at the root' , ( ) => {
561
+ middlewareWithPathnames ( createMockRequest ( '/DE-AT' , 'de-AT' ) ) ;
562
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
563
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
564
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
565
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
566
+ 'http://localhost:3000/de-AT/'
567
+ ) ;
568
+ } ) ;
569
+
570
+ it ( 'redirects uppercase locale requests for non-default locales and nested paths' , ( ) => {
571
+ middlewareWithPathnames ( createMockRequest ( '/DE-AT/ueber' , 'de-AT' ) ) ;
572
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
573
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
574
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
575
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
576
+ 'http://localhost:3000/de-AT/ueber'
577
+ ) ;
578
+ } ) ;
579
+
580
+ it ( 'redirects lowercase locale requests for non-default locales to case-sensitive format at the root' , ( ) => {
581
+ middlewareWithPathnames ( createMockRequest ( '/de-at' , 'de-AT' ) ) ;
582
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
583
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
584
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
585
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
586
+ 'http://localhost:3000/de-AT/'
587
+ ) ;
588
+ } ) ;
589
+
590
+ it ( 'redirects lowercase locale requests for non-default locales to case-sensitive format for nested paths' , ( ) => {
591
+ middlewareWithPathnames ( createMockRequest ( '/de-at/ueber' , 'de-AT' ) ) ;
592
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
593
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
594
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
595
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
596
+ 'http://localhost:3000/de-AT/ueber'
597
+ ) ;
598
+ } ) ;
599
+
534
600
it ( 'sets alternate links' , ( ) => {
535
601
function getLinks ( request : NextRequest ) {
536
602
return middlewareWithPathnames ( request )
@@ -541,55 +607,65 @@ describe('prefix-based routing', () => {
541
607
expect ( getLinks ( createMockRequest ( '/' , 'en' ) ) ) . toEqual ( [
542
608
'<http://localhost:3000/>; rel="alternate"; hreflang="en"' ,
543
609
'<http://localhost:3000/de>; rel="alternate"; hreflang="de"' ,
610
+ '<http://localhost:3000/de-AT>; rel="alternate"; hreflang="de-AT"' ,
544
611
'<http://localhost:3000/>; rel="alternate"; hreflang="x-default"'
545
612
] ) ;
546
613
expect ( getLinks ( createMockRequest ( '/de' , 'de' ) ) ) . toEqual ( [
547
614
'<http://localhost:3000/>; rel="alternate"; hreflang="en"' ,
548
615
'<http://localhost:3000/de>; rel="alternate"; hreflang="de"' ,
616
+ '<http://localhost:3000/de-AT>; rel="alternate"; hreflang="de-AT"' ,
549
617
'<http://localhost:3000/>; rel="alternate"; hreflang="x-default"'
550
618
] ) ;
551
619
expect ( getLinks ( createMockRequest ( '/about' , 'en' ) ) ) . toEqual ( [
552
620
'<http://localhost:3000/about>; rel="alternate"; hreflang="en"' ,
553
621
'<http://localhost:3000/de/ueber>; rel="alternate"; hreflang="de"' ,
622
+ '<http://localhost:3000/de-AT/ueber>; rel="alternate"; hreflang="de-AT"' ,
554
623
'<http://localhost:3000/about>; rel="alternate"; hreflang="x-default"'
555
624
] ) ;
556
625
expect ( getLinks ( createMockRequest ( '/de/ueber' , 'de' ) ) ) . toEqual ( [
557
626
'<http://localhost:3000/about>; rel="alternate"; hreflang="en"' ,
558
627
'<http://localhost:3000/de/ueber>; rel="alternate"; hreflang="de"' ,
628
+ '<http://localhost:3000/de-AT/ueber>; rel="alternate"; hreflang="de-AT"' ,
559
629
'<http://localhost:3000/about>; rel="alternate"; hreflang="x-default"'
560
630
] ) ;
561
631
expect ( getLinks ( createMockRequest ( '/users/1' , 'en' ) ) ) . toEqual ( [
562
632
'<http://localhost:3000/users/1>; rel="alternate"; hreflang="en"' ,
563
633
'<http://localhost:3000/de/benutzer/1>; rel="alternate"; hreflang="de"' ,
634
+ '<http://localhost:3000/de-AT/benutzer/1>; rel="alternate"; hreflang="de-AT"' ,
564
635
'<http://localhost:3000/users/1>; rel="alternate"; hreflang="x-default"'
565
636
] ) ;
566
637
expect ( getLinks ( createMockRequest ( '/de/benutzer/1' , 'de' ) ) ) . toEqual ( [
567
638
'<http://localhost:3000/users/1>; rel="alternate"; hreflang="en"' ,
568
639
'<http://localhost:3000/de/benutzer/1>; rel="alternate"; hreflang="de"' ,
640
+ '<http://localhost:3000/de-AT/benutzer/1>; rel="alternate"; hreflang="de-AT"' ,
569
641
'<http://localhost:3000/users/1>; rel="alternate"; hreflang="x-default"'
570
642
] ) ;
571
643
expect (
572
644
getLinks ( createMockRequest ( '/products/apparel/t-shirts' , 'en' ) )
573
645
) . toEqual ( [
574
646
'<http://localhost:3000/products/apparel/t-shirts>; rel="alternate"; hreflang="en"' ,
575
647
'<http://localhost:3000/de/produkte/apparel/t-shirts>; rel="alternate"; hreflang="de"' ,
648
+ '<http://localhost:3000/de-AT/produkte/apparel/t-shirts>; rel="alternate"; hreflang="de-AT"' ,
576
649
'<http://localhost:3000/products/apparel/t-shirts>; rel="alternate"; hreflang="x-default"'
577
650
] ) ;
578
651
expect (
579
652
getLinks ( createMockRequest ( '/de/produkte/apparel/t-shirts' , 'de' ) )
580
653
) . toEqual ( [
581
654
'<http://localhost:3000/products/apparel/t-shirts>; rel="alternate"; hreflang="en"' ,
582
655
'<http://localhost:3000/de/produkte/apparel/t-shirts>; rel="alternate"; hreflang="de"' ,
656
+ '<http://localhost:3000/de-AT/produkte/apparel/t-shirts>; rel="alternate"; hreflang="de-AT"' ,
583
657
'<http://localhost:3000/products/apparel/t-shirts>; rel="alternate"; hreflang="x-default"'
584
658
] ) ;
585
659
expect ( getLinks ( createMockRequest ( '/unknown' , 'en' ) ) ) . toEqual ( [
586
660
'<http://localhost:3000/unknown>; rel="alternate"; hreflang="en"' ,
587
661
'<http://localhost:3000/de/unknown>; rel="alternate"; hreflang="de"' ,
662
+ '<http://localhost:3000/de-AT/unknown>; rel="alternate"; hreflang="de-AT"' ,
588
663
'<http://localhost:3000/unknown>; rel="alternate"; hreflang="x-default"'
589
664
] ) ;
590
665
expect ( getLinks ( createMockRequest ( '/de/unknown' , 'de' ) ) ) . toEqual ( [
591
666
'<http://localhost:3000/unknown>; rel="alternate"; hreflang="en"' ,
592
667
'<http://localhost:3000/de/unknown>; rel="alternate"; hreflang="de"' ,
668
+ '<http://localhost:3000/de-AT/unknown>; rel="alternate"; hreflang="de-AT"' ,
593
669
'<http://localhost:3000/unknown>; rel="alternate"; hreflang="x-default"'
594
670
] ) ;
595
671
} ) ;
@@ -940,7 +1016,7 @@ describe('prefix-based routing', () => {
940
1016
describe ( 'localePrefix: never' , ( ) => {
941
1017
const middleware = createIntlMiddleware ( {
942
1018
defaultLocale : 'en' ,
943
- locales : [ 'en' , 'de' ] ,
1019
+ locales : [ 'en' , 'de' , 'de-AT' ] ,
944
1020
localePrefix : 'never'
945
1021
} ) ;
946
1022
@@ -1038,6 +1114,36 @@ describe('prefix-based routing', () => {
1038
1114
) ;
1039
1115
} ) ;
1040
1116
1117
+ it ( 'redirects requests with uppercase default locale in a nested path' , ( ) => {
1118
+ middleware ( createMockRequest ( '/EN/list' ) ) ;
1119
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
1120
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
1121
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
1122
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
1123
+ 'http://localhost:3000/list'
1124
+ ) ;
1125
+ } ) ;
1126
+
1127
+ it ( 'redirects requests with uppercase non-default locale in a nested path' , ( ) => {
1128
+ middleware ( createMockRequest ( '/DE-AT/list' ) ) ;
1129
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
1130
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
1131
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
1132
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
1133
+ 'http://localhost:3000/list'
1134
+ ) ;
1135
+ } ) ;
1136
+
1137
+ it ( 'redirects requests with lowercase non-default locale in a nested path' , ( ) => {
1138
+ middleware ( createMockRequest ( '/de-at/list' ) ) ;
1139
+ expect ( MockedNextResponse . rewrite ) . not . toHaveBeenCalled ( ) ;
1140
+ expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
1141
+ expect ( MockedNextResponse . redirect ) . toHaveBeenCalled ( ) ;
1142
+ expect ( MockedNextResponse . redirect . mock . calls [ 0 ] [ 0 ] . toString ( ) ) . toBe (
1143
+ 'http://localhost:3000/list'
1144
+ ) ;
1145
+ } ) ;
1146
+
1041
1147
it ( 'rewrites requests for the root if a cookie exists with a non-default locale' , ( ) => {
1042
1148
middleware ( createMockRequest ( '/' , 'en' , 'http://localhost:3000' , 'de' ) ) ;
1043
1149
expect ( MockedNextResponse . next ) . not . toHaveBeenCalled ( ) ;
0 commit comments