Skip to content

Commit afbe311

Browse files
clydinalan-agius4
authored andcommitted
refactor(@angular/cli): provide a default extract-i18n target for applications
The `extract-i18n` command will now use a default project target and builder name if the target entry is not explicitly defined. This allows the removal of additional configuration from an `angular.json` file. If the target is already present than it will take priority over any default builder behavior. Infrastructure is also now present to allow other architect commands to have similar functionality in the future.
1 parent be46c5f commit afbe311

File tree

2 files changed

+65
-1
lines changed

2 files changed

+65
-1
lines changed

packages/angular/cli/src/command-builder/architect-command-module.ts

+28-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import { Target } from '@angular-devkit/architect';
10+
import { workspaces } from '@angular-devkit/core';
911
import { Argv } from 'yargs';
1012
import { getProjectByCwd } from '../utilities/config';
1113
import { memoize } from '../utilities/memoize';
@@ -28,7 +30,33 @@ export abstract class ArchitectCommandModule
2830
{
2931
abstract readonly multiTarget: boolean;
3032

33+
findDefaultBuilderName?(
34+
project: workspaces.ProjectDefinition,
35+
target: Target,
36+
): Promise<string | undefined>;
37+
3138
async builder(argv: Argv): Promise<Argv<ArchitectCommandArgs>> {
39+
const target = this.getArchitectTarget();
40+
41+
// Add default builder if target is not in project and a command default is provided
42+
if (this.findDefaultBuilderName && this.context.workspace) {
43+
for (const [project, projectDefinition] of this.context.workspace.projects) {
44+
if (projectDefinition.targets.has(target)) {
45+
continue;
46+
}
47+
48+
const defaultBuilder = await this.findDefaultBuilderName(projectDefinition, {
49+
project,
50+
target,
51+
});
52+
if (defaultBuilder) {
53+
projectDefinition.targets.set(target, {
54+
builder: defaultBuilder,
55+
});
56+
}
57+
}
58+
}
59+
3260
const project = this.getArchitectProject();
3361
const { jsonHelp, getYargsCompletions, help } = this.context.args.options;
3462

@@ -60,7 +88,6 @@ export abstract class ArchitectCommandModule
6088
return localYargs;
6189
}
6290

63-
const target = this.getArchitectTarget();
6491
const schemaOptions = await this.getArchitectTargetOptions({
6592
project,
6693
target,

packages/angular/cli/src/commands/extract-i18n/cli.ts

+37
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
* found in the LICENSE file at https://angular.dev/license
77
*/
88

9+
import { workspaces } from '@angular-devkit/core';
10+
import { createRequire } from 'node:module';
11+
import { join } from 'node:path';
912
import { ArchitectCommandModule } from '../../command-builder/architect-command-module';
1013
import { CommandModuleImplementation } from '../../command-builder/command-module';
1114

@@ -17,4 +20,38 @@ export default class ExtractI18nCommandModule
1720
command = 'extract-i18n [project]';
1821
describe = 'Extracts i18n messages from source code.';
1922
longDescriptionPath?: string | undefined;
23+
24+
override async findDefaultBuilderName(
25+
project: workspaces.ProjectDefinition,
26+
): Promise<string | undefined> {
27+
// Only application type projects have a default i18n extraction target
28+
if (project.extensions['projectType'] !== 'application') {
29+
return;
30+
}
31+
32+
const buildTarget = project.targets.get('build');
33+
if (!buildTarget) {
34+
// No default if there is no build target
35+
return;
36+
}
37+
38+
// Provide a default based on the defined builder for the 'build' target
39+
switch (buildTarget.builder) {
40+
case '@angular-devkit/build-angular:application':
41+
case '@angular-devkit/build-angular:browser-esbuild':
42+
case '@angular-devkit/build-angular:browser':
43+
return '@angular-devkit/build-angular:extract-i18n';
44+
case '@angular/build:application':
45+
return '@angular/build:extract-i18n';
46+
}
47+
48+
// For other builders, check for `@angular-devkit/build-angular` and use if found.
49+
// This package is safer to use since it supports both application builder types.
50+
try {
51+
const projectRequire = createRequire(join(this.context.root, project.root) + '/');
52+
projectRequire.resolve('@angular-devkit/build-angular');
53+
54+
return '@angular-devkit/build-angular:extract-i18n';
55+
} catch {}
56+
}
2057
}

0 commit comments

Comments
 (0)