88import { JsonAstObject } from '@angular-devkit/core' ;
99import { Rule , Tree , UpdateRecorder } from '@angular-devkit/schematics' ;
1010import { getWorkspacePath } from '../../utility/config' ;
11+ import { NodeDependencyType , addPackageJsonDependency , getPackageJsonDependency } from '../../utility/dependencies' ;
1112import {
1213 appendValueInAstArray ,
1314 findPropertyInAstObject ,
1415 insertPropertyInAstObjectInOrder ,
1516 removePropertyInAstObject ,
1617} from '../../utility/json-utils' ;
18+ import { latestVersions } from '../../utility/latest-versions' ;
1719import { Builders } from '../../utility/workspace-models' ;
1820import { getAllOptions , getProjectTarget , getTargets , getWorkspace , isIvyEnabled } from './utils' ;
1921
@@ -28,29 +30,41 @@ export function updateWorkspaceConfig(): Rule {
2830 const workspace = getWorkspace ( tree ) ;
2931 const recorder = tree . beginUpdate ( workspacePath ) ;
3032
31- for ( const { target } of getTargets ( workspace , 'build' , Builders . Browser ) ) {
33+ for ( const { target, project } of getTargets ( workspace , 'build' , Builders . Browser ) ) {
3234 updateStyleOrScriptOption ( 'styles' , recorder , target ) ;
3335 updateStyleOrScriptOption ( 'scripts' , recorder , target ) ;
3436 addAnyComponentStyleBudget ( recorder , target ) ;
3537 updateAotOption ( tree , recorder , target ) ;
38+ addBuilderI18NOptions ( recorder , target , project ) ;
3639 }
3740
38- for ( const { target } of getTargets ( workspace , 'test' , Builders . Karma ) ) {
41+ for ( const { target, project } of getTargets ( workspace , 'test' , Builders . Karma ) ) {
3942 updateStyleOrScriptOption ( 'styles' , recorder , target ) ;
4043 updateStyleOrScriptOption ( 'scripts' , recorder , target ) ;
44+ addBuilderI18NOptions ( recorder , target , project ) ;
4145 }
4246
4347 for ( const { target } of getTargets ( workspace , 'server' , Builders . Server ) ) {
4448 updateOptimizationOption ( recorder , target ) ;
4549 }
4650
51+ for ( const { target, project } of getTargets ( workspace , 'extract-i18n' , Builders . ExtractI18n ) ) {
52+ addProjectI18NOptions ( recorder , tree , target , project ) ;
53+ removeExtracti18nDeprecatedOptions ( recorder , target ) ;
54+ }
55+
4756 tree . commitUpdate ( recorder ) ;
4857
4958 return tree ;
5059 } ;
5160}
5261
53- function addProjectI18NOptions ( recorder : UpdateRecorder , builderConfig : JsonAstObject , projectConfig : JsonAstObject ) {
62+ function addProjectI18NOptions (
63+ recorder : UpdateRecorder ,
64+ tree : Tree ,
65+ builderConfig : JsonAstObject ,
66+ projectConfig : JsonAstObject ,
67+ ) {
5468 const browserConfig = getProjectTarget ( projectConfig , 'build' , Builders . Browser ) ;
5569 if ( ! browserConfig || browserConfig . kind !== 'object' ) {
5670 return ;
@@ -86,33 +100,101 @@ function addProjectI18NOptions(recorder: UpdateRecorder, builderConfig: JsonAstO
86100 // Get sourceLocale from extract-i18n builder
87101 const i18nOptions = getAllOptions ( builderConfig ) ;
88102 const sourceLocale = i18nOptions
89- . map ( o => {
90- const sourceLocale = findPropertyInAstObject ( o , 'i18nLocale' ) ;
103+ . map ( o => {
104+ const sourceLocale = findPropertyInAstObject ( o , 'i18nLocale' ) ;
91105
92- return sourceLocale && sourceLocale . value ;
93- } )
94- . find ( x => ! ! x ) ;
106+ return sourceLocale && sourceLocale . value ;
107+ } )
108+ . find ( x => ! ! x ) ;
95109
96110 // Add i18n project configuration
97111 insertPropertyInAstObjectInOrder ( recorder , projectConfig , 'i18n' , {
98112 locales,
99113 // tslint:disable-next-line: no-any
100114 sourceLocale : sourceLocale as any ,
101115 } , 6 ) ;
116+
117+ // Add @angular /localize if not already a dependency
118+ if ( ! getPackageJsonDependency ( tree , '@angular/localize' ) ) {
119+ addPackageJsonDependency ( tree , {
120+ name : '@angular/localize' ,
121+ version : latestVersions . Angular ,
122+ type : NodeDependencyType . Default ,
123+ } ) ;
124+ }
102125 }
103126}
104127
105- function addBuilderI18NOptions ( recorder : UpdateRecorder , builderConfig : JsonAstObject ) {
128+ function addBuilderI18NOptions ( recorder : UpdateRecorder , builderConfig : JsonAstObject , projectConfig : JsonAstObject ) {
106129 const options = getAllOptions ( builderConfig ) ;
107130
131+ let hasi18n = false ;
108132 for ( const option of options ) {
109133 const localeId = findPropertyInAstObject ( option , 'i18nLocale' ) ;
110- if ( ! localeId || localeId . kind !== 'string' ) {
111- continue ;
134+ if ( localeId && localeId . kind === 'string' ) {
135+ // add new localize option
136+ insertPropertyInAstObjectInOrder ( recorder , option , 'localize' , [ localeId . value ] , 12 ) ;
137+ removePropertyInAstObject ( recorder , option , 'i18nLocale' ) ;
138+ }
139+
140+ const i18nFile = findPropertyInAstObject ( option , 'i18nFile' ) ;
141+ if ( i18nFile ) {
142+ removePropertyInAstObject ( recorder , option , 'i18nFile' ) ;
143+ }
144+
145+ const i18nFormat = findPropertyInAstObject ( option , 'i18nFormat' ) ;
146+ if ( i18nFormat ) {
147+ removePropertyInAstObject ( recorder , option , 'i18nFormat' ) ;
112148 }
113149
114- // add new localize option
115- insertPropertyInAstObjectInOrder ( recorder , option , 'localize' , [ localeId . value ] , 12 ) ;
150+ hasi18n = ! ! ( hasi18n || i18nFormat || i18nFile || localeId ) ;
151+ }
152+
153+ if ( hasi18n ) {
154+ const options = findPropertyInAstObject ( builderConfig , 'options' ) ;
155+ if ( ! options || options . kind !== 'object' ) {
156+ return ;
157+ }
158+
159+ // Don't add localize option of it's already present in the main options
160+ if ( findPropertyInAstObject ( options , 'i18nLocale' ) || findPropertyInAstObject ( options , 'localize' ) ) {
161+ return ;
162+ }
163+
164+ // Get sourceLocale from extract-i18n builder
165+ const extractI18nConfig = getProjectTarget ( projectConfig , 'extract-i18n' , Builders . ExtractI18n ) ;
166+ let sourceLocale : string | undefined ;
167+
168+ if ( extractI18nConfig && extractI18nConfig . kind === 'object' ) {
169+ const i18nOptions = getAllOptions ( extractI18nConfig ) ;
170+ sourceLocale = i18nOptions
171+ . map ( o => {
172+ const sourceLocale = findPropertyInAstObject ( o , 'i18nLocale' ) ;
173+
174+ return sourceLocale && sourceLocale . value ;
175+ } )
176+ . find ( x => ! ! x ) as string ;
177+ }
178+
179+ insertPropertyInAstObjectInOrder ( recorder , options , 'localize' , [ sourceLocale || 'en-US' ] , 12 ) ;
180+ }
181+ }
182+
183+ function removeExtracti18nDeprecatedOptions ( recorder : UpdateRecorder , builderConfig : JsonAstObject ) {
184+ const options = getAllOptions ( builderConfig ) ;
185+
186+ for ( const option of options ) {
187+ // deprecated options
188+ removePropertyInAstObject ( recorder , option , 'i18nLocale' ) ;
189+ const i18nFormat = option . properties . find ( ( { key } ) => key . value === 'i18nFormat' ) ;
190+
191+ if ( i18nFormat ) {
192+ // i18nFormat has been changed to format
193+ const key = i18nFormat . key ;
194+ const offset = key . start . offset + 1 ;
195+ recorder . remove ( offset , key . value . length ) ;
196+ recorder . insertLeft ( offset , 'format' ) ;
197+ }
116198 }
117199}
118200
@@ -122,7 +204,6 @@ function updateAotOption(tree: Tree, recorder: UpdateRecorder, builderConfig: Js
122204 return ;
123205 }
124206
125-
126207 const tsConfig = findPropertyInAstObject ( options , 'tsConfig' ) ;
127208 // Do not add aot option if the users already opted out from Ivy.
128209 if ( tsConfig && tsConfig . kind === 'string' && ! isIvyEnabled ( tree , tsConfig . value ) ) {
0 commit comments