8
8
9
9
import type { Plugin } from 'esbuild' ;
10
10
11
+ /**
12
+ * The internal namespace used by generated locale import statements and Angular locale data plugin.
13
+ */
14
+ export const LOCALE_DATA_NAMESPACE = 'angular:locale/data' ;
15
+
11
16
/**
12
17
* The base module location used to search for locale specific data.
13
18
*/
@@ -35,15 +40,39 @@ export function createAngularLocaleDataPlugin(): Plugin {
35
40
36
41
build . onResolve ( { filter : / ^ a n g u l a r : l o c a l e \/ d a t a : / } , async ( { path } ) => {
37
42
// Extract the locale from the path
38
- const originalLocale = path . split ( ':' , 3 ) [ 2 ] ;
43
+ const rawLocaleTag = path . split ( ':' , 3 ) [ 2 ] ;
39
44
40
- // Remove any private subtags since these will never match
41
- let partialLocale = originalLocale . replace ( / - x ( - [ a - z A - Z 0 - 9 ] { 1 , 8 } ) + $ / , '' ) ;
45
+ // Extract and normalize the base name of the raw locale tag
46
+ let partialLocaleTag : string ;
47
+ try {
48
+ const locale = new Intl . Locale ( rawLocaleTag ) ;
49
+ partialLocaleTag = locale . baseName ;
50
+ } catch {
51
+ return {
52
+ path : rawLocaleTag ,
53
+ namespace : LOCALE_DATA_NAMESPACE ,
54
+ errors : [
55
+ {
56
+ text : `Invalid or unsupported locale provided in configuration: "${ rawLocaleTag } "` ,
57
+ } ,
58
+ ] ,
59
+ } ;
60
+ }
42
61
43
62
let exact = true ;
44
- while ( partialLocale ) {
45
- const potentialPath = `${ LOCALE_DATA_BASE_MODULE } /${ partialLocale } ` ;
63
+ while ( partialLocaleTag ) {
64
+ // Angular embeds the `en`/`en-US` locale into the framework and it does not need to be included again here.
65
+ // The onLoad hook below for the locale data namespace has an `empty` loader that will prevent inclusion.
66
+ // Angular does not contain exact locale data for `en-US` but `en` is equivalent.
67
+ if ( partialLocaleTag === 'en' || partialLocaleTag === 'en-US' ) {
68
+ return {
69
+ path : rawLocaleTag ,
70
+ namespace : LOCALE_DATA_NAMESPACE ,
71
+ } ;
72
+ }
46
73
74
+ // Attempt to resolve the locale tag data within the Angular base module location
75
+ const potentialPath = `${ LOCALE_DATA_BASE_MODULE } /${ partialLocaleTag } ` ;
47
76
const result = await build . resolve ( potentialPath , {
48
77
kind : 'import-statement' ,
49
78
resolveDir : build . initialOptions . absWorkingDir ,
@@ -58,39 +87,40 @@ export function createAngularLocaleDataPlugin(): Plugin {
58
87
...result . warnings ,
59
88
{
60
89
location : null ,
61
- text : `Locale data for '${ originalLocale } ' cannot be found. Using locale data for '${ partialLocale } '.` ,
90
+ text : `Locale data for '${ rawLocaleTag } ' cannot be found. Using locale data for '${ partialLocaleTag } '.` ,
62
91
} ,
63
92
] ,
64
93
} ;
65
94
}
66
95
}
67
96
68
- // Remove the last subtag and try again with a less specific locale
69
- const parts = partialLocale . split ( '-' ) ;
70
- partialLocale = parts . slice ( 0 , - 1 ) . join ( '-' ) ;
97
+ // Remove the last subtag and try again with a less specific locale.
98
+ // Usually the match is exact so the string splitting here is not done until actually needed after the exact
99
+ // match fails to resolve.
100
+ const parts = partialLocaleTag . split ( '-' ) ;
101
+ partialLocaleTag = parts . slice ( 0 , - 1 ) . join ( '-' ) ;
71
102
exact = false ;
72
- // The locales "en" and "en-US" are considered exact to retain existing behavior
73
- if ( originalLocale === 'en-US' && partialLocale === 'en' ) {
74
- exact = true ;
75
- }
76
103
}
77
104
78
105
// Not found so issue a warning and use an empty loader. Framework built-in `en-US` data will be used.
79
106
// This retains existing behavior as in the Webpack-based builder.
80
107
return {
81
- path : originalLocale ,
82
- namespace : 'angular:locale/data' ,
108
+ path : rawLocaleTag ,
109
+ namespace : LOCALE_DATA_NAMESPACE ,
83
110
warnings : [
84
111
{
85
112
location : null ,
86
- text : `Locale data for '${ originalLocale } ' cannot be found. No locale data will be included for this locale.` ,
113
+ text : `Locale data for '${ rawLocaleTag } ' cannot be found. No locale data will be included for this locale.` ,
87
114
} ,
88
115
] ,
89
116
} ;
90
117
} ) ;
91
118
92
119
// Locales that cannot be found will be loaded as empty content with a warning from the resolve step
93
- build . onLoad ( { filter : / ./ , namespace : 'angular:locale/data' } , ( ) => ( { loader : 'empty' } ) ) ;
120
+ build . onLoad ( { filter : / ./ , namespace : LOCALE_DATA_NAMESPACE } , ( ) => ( {
121
+ contents : '' ,
122
+ loader : 'empty' ,
123
+ } ) ) ;
94
124
} ,
95
125
} ;
96
126
}
0 commit comments