@@ -16,6 +16,7 @@ import * as path from 'path';
16
16
import webpack from 'webpack' ;
17
17
import { ExecutionTransformer } from '../../transforms' ;
18
18
import { createI18nOptions } from '../../utils/i18n-options' ;
19
+ import { loadEsmModule } from '../../utils/load-esm' ;
19
20
import { assertCompatibleAngularVersion } from '../../utils/version' ;
20
21
import { generateBrowserWebpackConfigFromContext } from '../../utils/webpack-browser-config' ;
21
22
import {
@@ -31,6 +32,24 @@ import { Format, Schema } from './schema';
31
32
32
33
export type ExtractI18nBuilderOptions = Schema & JsonObject ;
33
34
35
+ /**
36
+ * The manually constructed type for the `@angular/localize/tools` module.
37
+ * This type only contains the exports that are need for this file.
38
+ *
39
+ * TODO_ESM: Remove once the `tools` entry point exists in a published package version
40
+ */
41
+ interface LocalizeToolsModule {
42
+ /* eslint-disable max-len */
43
+ checkDuplicateMessages : typeof import ( '@angular/localize/src/tools/src/extract/duplicates' ) . checkDuplicateMessages ;
44
+ XmbTranslationSerializer : typeof import ( '@angular/localize/src/tools/src/extract/translation_files/xmb_translation_serializer' ) . XmbTranslationSerializer ;
45
+ SimpleJsonTranslationSerializer : typeof import ( '@angular/localize/src/tools/src/extract/translation_files/json_translation_serializer' ) . SimpleJsonTranslationSerializer ;
46
+ Xliff1TranslationSerializer : typeof import ( '@angular/localize/src/tools/src/extract/translation_files/xliff1_translation_serializer' ) . Xliff1TranslationSerializer ;
47
+ Xliff2TranslationSerializer : typeof import ( '@angular/localize/src/tools/src/extract/translation_files/xliff2_translation_serializer' ) . Xliff2TranslationSerializer ;
48
+ ArbTranslationSerializer : typeof import ( '@angular/localize/src/tools/src/extract/translation_files/arb_translation_serializer' ) . ArbTranslationSerializer ;
49
+ LegacyMessageIdMigrationSerializer : typeof import ( '@angular/localize/src/tools/src/extract/translation_files/legacy_message_id_migration_serializer' ) . LegacyMessageIdMigrationSerializer ;
50
+ /* eslint-enable max-len */
51
+ }
52
+
34
53
function getI18nOutfile ( format : string | undefined ) {
35
54
switch ( format ) {
36
55
case 'xmb' :
@@ -52,6 +71,7 @@ function getI18nOutfile(format: string | undefined) {
52
71
}
53
72
54
73
async function getSerializer (
74
+ localizeToolsModule : LocalizeToolsModule | undefined ,
55
75
format : Format ,
56
76
sourceLocale : string ,
57
77
basePath : string ,
@@ -60,45 +80,57 @@ async function getSerializer(
60
80
) {
61
81
switch ( format ) {
62
82
case Format . Xmb :
63
- const { XmbTranslationSerializer } = await import (
64
- '@angular/localize/src/tools/src/extract/translation_files/xmb_translation_serializer'
65
- ) ;
83
+ const { XmbTranslationSerializer } =
84
+ localizeToolsModule ??
85
+ ( await import (
86
+ '@angular/localize/src/tools/src/extract/translation_files/xmb_translation_serializer'
87
+ ) ) ;
66
88
67
89
// eslint-disable-next-line @typescript-eslint/no-explicit-any
68
90
return new XmbTranslationSerializer ( basePath as any , useLegacyIds ) ;
69
91
case Format . Xlf :
70
92
case Format . Xlif :
71
93
case Format . Xliff :
72
- const { Xliff1TranslationSerializer } = await import (
73
- '@angular/localize/src/tools/src/extract/translation_files/xliff1_translation_serializer'
74
- ) ;
94
+ const { Xliff1TranslationSerializer } =
95
+ localizeToolsModule ??
96
+ ( await import (
97
+ '@angular/localize/src/tools/src/extract/translation_files/xliff1_translation_serializer'
98
+ ) ) ;
75
99
76
100
// eslint-disable-next-line @typescript-eslint/no-explicit-any
77
101
return new Xliff1TranslationSerializer ( sourceLocale , basePath as any , useLegacyIds , { } ) ;
78
102
case Format . Xlf2 :
79
103
case Format . Xliff2 :
80
- const { Xliff2TranslationSerializer } = await import (
81
- '@angular/localize/src/tools/src/extract/translation_files/xliff2_translation_serializer'
82
- ) ;
104
+ const { Xliff2TranslationSerializer } =
105
+ localizeToolsModule ??
106
+ ( await import (
107
+ '@angular/localize/src/tools/src/extract/translation_files/xliff2_translation_serializer'
108
+ ) ) ;
83
109
84
110
// eslint-disable-next-line @typescript-eslint/no-explicit-any
85
111
return new Xliff2TranslationSerializer ( sourceLocale , basePath as any , useLegacyIds , { } ) ;
86
112
case Format . Json :
87
- const { SimpleJsonTranslationSerializer } = await import (
88
- '@angular/localize/src/tools/src/extract/translation_files/json_translation_serializer'
89
- ) ;
113
+ const { SimpleJsonTranslationSerializer } =
114
+ localizeToolsModule ??
115
+ ( await import (
116
+ '@angular/localize/src/tools/src/extract/translation_files/json_translation_serializer'
117
+ ) ) ;
90
118
91
119
return new SimpleJsonTranslationSerializer ( sourceLocale ) ;
92
120
case Format . LegacyMigrate :
93
- const { LegacyMessageIdMigrationSerializer } = await import (
94
- '@angular/localize/src/tools/src/extract/translation_files/legacy_message_id_migration_serializer'
95
- ) ;
121
+ const { LegacyMessageIdMigrationSerializer } =
122
+ localizeToolsModule ??
123
+ ( await import (
124
+ '@angular/localize/src/tools/src/extract/translation_files/legacy_message_id_migration_serializer'
125
+ ) ) ;
96
126
97
127
return new LegacyMessageIdMigrationSerializer ( diagnostics ) ;
98
128
case Format . Arb :
99
- const { ArbTranslationSerializer } = await import (
100
- '@angular/localize/src/tools/src/extract/translation_files/arb_translation_serializer'
101
- ) ;
129
+ const { ArbTranslationSerializer } =
130
+ localizeToolsModule ??
131
+ ( await import (
132
+ '@angular/localize/src/tools/src/extract/translation_files/arb_translation_serializer'
133
+ ) ) ;
102
134
103
135
const fileSystem = {
104
136
relative ( from : string , to : string ) : string {
@@ -253,6 +285,17 @@ export async function execute(
253
285
} ;
254
286
}
255
287
288
+ // All the localize usages are setup to first try the ESM entry point then fallback to the deep imports.
289
+ // This provides interim compatibility while the framework is transitioned to bundled ESM packages.
290
+ // TODO_ESM: Remove all deep imports once `@angular/localize` is published with the `tools` entry point
291
+ let localizeToolsModule ;
292
+ try {
293
+ // Load ESM `@angular/localize/tools` using the TypeScript dynamic import workaround.
294
+ // Once TypeScript provides support for keeping the dynamic import this workaround can be
295
+ // changed to a direct dynamic import.
296
+ localizeToolsModule = await loadEsmModule < LocalizeToolsModule > ( '@angular/localize/tools' ) ;
297
+ } catch { }
298
+
256
299
const webpackResult = await runWebpack (
257
300
( await transforms ?. webpackConfiguration ?.( config ) ) || config ,
258
301
context ,
@@ -272,9 +315,8 @@ export async function execute(
272
315
273
316
const basePath = config . context || projectRoot ;
274
317
275
- const { checkDuplicateMessages } = await import (
276
- '@angular/localize/src/tools/src/extract/duplicates'
277
- ) ;
318
+ const { checkDuplicateMessages } =
319
+ localizeToolsModule ?? ( await import ( '@angular/localize/src/tools/src/extract/duplicates' ) ) ;
278
320
279
321
// The filesystem is used to create a relative path for each file
280
322
// from the basePath. This relative path is then used in the error message.
@@ -297,6 +339,7 @@ export async function execute(
297
339
298
340
// Serialize all extracted messages
299
341
const serializer = await getSerializer (
342
+ localizeToolsModule ,
300
343
format ,
301
344
i18n . sourceLocale ,
302
345
basePath ,
0 commit comments