feat(angular): add the extract-i18n executor (#21802)
This commit is contained in:
parent
b625a79cca
commit
343c0f6690
@ -6706,6 +6706,14 @@
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"id": "extract-i18n",
|
||||
"path": "/nx-api/angular/executors/extract-i18n",
|
||||
"name": "extract-i18n",
|
||||
"children": [],
|
||||
"isExternal": false,
|
||||
"disableCollapsible": false
|
||||
},
|
||||
{
|
||||
"id": "webpack-browser",
|
||||
"path": "/nx-api/angular/executors/webpack-browser",
|
||||
|
||||
@ -85,6 +85,15 @@
|
||||
"path": "/nx-api/angular/executors/application",
|
||||
"type": "executor"
|
||||
},
|
||||
"/nx-api/angular/executors/extract-i18n": {
|
||||
"description": "Extracts i18n messages from source code.",
|
||||
"file": "generated/packages/angular/executors/extract-i18n.json",
|
||||
"hidden": false,
|
||||
"name": "extract-i18n",
|
||||
"originalFilePath": "/packages/angular/src/executors/extract-i18n/schema.json",
|
||||
"path": "/nx-api/angular/executors/extract-i18n",
|
||||
"type": "executor"
|
||||
},
|
||||
"/nx-api/angular/executors/webpack-browser": {
|
||||
"description": "The `webpack-browser` executor is very similar to the standard `browser` builder provided by the Angular Devkit. It allows you to build your Angular application to a build artifact that can be hosted online. There are some key differences: \n- Supports Custom Webpack Configurations \n- Supports Incremental Building",
|
||||
"file": "generated/packages/angular/executors/webpack-browser.json",
|
||||
|
||||
@ -80,6 +80,15 @@
|
||||
"path": "angular/executors/application",
|
||||
"type": "executor"
|
||||
},
|
||||
{
|
||||
"description": "Extracts i18n messages from source code.",
|
||||
"file": "generated/packages/angular/executors/extract-i18n.json",
|
||||
"hidden": false,
|
||||
"name": "extract-i18n",
|
||||
"originalFilePath": "/packages/angular/src/executors/extract-i18n/schema.json",
|
||||
"path": "angular/executors/extract-i18n",
|
||||
"type": "executor"
|
||||
},
|
||||
{
|
||||
"description": "The `webpack-browser` executor is very similar to the standard `browser` builder provided by the Angular Devkit. It allows you to build your Angular application to a build artifact that can be hosted online. There are some key differences: \n- Supports Custom Webpack Configurations \n- Supports Incremental Building",
|
||||
"file": "generated/packages/angular/executors/webpack-browser.json",
|
||||
|
||||
55
docs/generated/packages/angular/executors/extract-i18n.json
Normal file
55
docs/generated/packages/angular/executors/extract-i18n.json
Normal file
@ -0,0 +1,55 @@
|
||||
{
|
||||
"name": "extract-i18n",
|
||||
"implementation": "/packages/angular/src/executors/extract-i18n/extract-i18n.impl.ts",
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Nx extract-i18n Executor",
|
||||
"description": "Extracts i18n messages from source code.",
|
||||
"outputCapture": "direct-nodejs",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"buildTarget": {
|
||||
"type": "string",
|
||||
"description": "A builder target to extract i18n messages in the format of `project:target[:configuration]`. You can also pass in more than one configuration name as a comma-separated list. Example: `project:target:production,staging`.",
|
||||
"pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"description": "Output format for the generated file.",
|
||||
"default": "xlf",
|
||||
"enum": [
|
||||
"xmb",
|
||||
"xlf",
|
||||
"xlif",
|
||||
"xliff",
|
||||
"xlf2",
|
||||
"xliff2",
|
||||
"json",
|
||||
"arb",
|
||||
"legacy-migrate"
|
||||
]
|
||||
},
|
||||
"progress": {
|
||||
"type": "boolean",
|
||||
"description": "Log progress to the console.",
|
||||
"default": true
|
||||
},
|
||||
"outputPath": {
|
||||
"type": "string",
|
||||
"description": "Path where output will be placed."
|
||||
},
|
||||
"outFile": {
|
||||
"type": "string",
|
||||
"description": "Name of the file to output."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["buildTarget"],
|
||||
"presets": []
|
||||
},
|
||||
"description": "Extracts i18n messages from source code.",
|
||||
"aliases": [],
|
||||
"hidden": false,
|
||||
"path": "/packages/angular/src/executors/extract-i18n/schema.json",
|
||||
"type": "executor"
|
||||
}
|
||||
@ -325,6 +325,7 @@
|
||||
- [browser-esbuild](/nx-api/angular/executors/browser-esbuild)
|
||||
- [module-federation-dev-server](/nx-api/angular/executors/module-federation-dev-server)
|
||||
- [application](/nx-api/angular/executors/application)
|
||||
- [extract-i18n](/nx-api/angular/executors/extract-i18n)
|
||||
- [webpack-browser](/nx-api/angular/executors/webpack-browser)
|
||||
- [dev-server](/nx-api/angular/executors/dev-server)
|
||||
- [webpack-server](/nx-api/angular/executors/webpack-server)
|
||||
|
||||
@ -29,6 +29,11 @@
|
||||
"implementation": "./src/executors/application/application.impl",
|
||||
"schema": "./src/executors/application/schema.json",
|
||||
"description": "Builds an application with esbuild with support for incremental builds. _Note: this is only supported in Angular versions >= 17.0.0_."
|
||||
},
|
||||
"extract-i18n": {
|
||||
"implementation": "./src/executors/extract-i18n/extract-i18n.impl",
|
||||
"schema": "./src/executors/extract-i18n/schema.json",
|
||||
"description": "Extracts i18n messages from source code."
|
||||
}
|
||||
},
|
||||
"builders": {
|
||||
|
||||
@ -7,6 +7,7 @@ export * from './src/executors/ng-packagr-lite/ng-packagr-lite.impl';
|
||||
export * from './src/executors/package/package.impl';
|
||||
export * from './src/executors/browser-esbuild/browser-esbuild.impl';
|
||||
export * from './src/executors/application/application.impl';
|
||||
export * from './src/executors/extract-i18n/extract-i18n.impl';
|
||||
|
||||
import { executeDevServerBuilder } from './src/builders/dev-server/dev-server.impl';
|
||||
|
||||
|
||||
@ -1,16 +1,10 @@
|
||||
import type { BuilderContext } from '@angular-devkit/architect';
|
||||
import type {
|
||||
ApplicationBuilderOptions,
|
||||
BrowserBuilderOptions,
|
||||
DevServerBuilderOptions,
|
||||
} from '@angular-devkit/build-angular';
|
||||
import type { Schema as BrowserEsbuildBuilderOptions } from '@angular-devkit/build-angular/src/builders/browser-esbuild/schema';
|
||||
import type { DevServerBuilderOptions } from '@angular-devkit/build-angular';
|
||||
import {
|
||||
joinPathFragments,
|
||||
normalizePath,
|
||||
parseTargetString,
|
||||
readCachedProjectGraph,
|
||||
type Target,
|
||||
} from '@nx/devkit';
|
||||
import { getRootTsConfigPath } from '@nx/js';
|
||||
import type { DependentBuildableProjectNode } from '@nx/js/src/utils/buildable-libs-utils';
|
||||
@ -28,6 +22,7 @@ import {
|
||||
loadPlugins,
|
||||
type PluginSpec,
|
||||
} from '../../executors/utilities/esbuild-extensions';
|
||||
import { patchBuilderContext } from '../../executors/utilities/patch-builder-context';
|
||||
import { createTmpTsConfigForBuildableLibs } from '../utilities/buildable-libs';
|
||||
import {
|
||||
mergeCustomWebpackConfig,
|
||||
@ -288,60 +283,3 @@ async function loadIndexHtmlFileTransformer(
|
||||
)
|
||||
: await loadIndexHtmlTransformer(pathToIndexFileTransformer, tsConfig);
|
||||
}
|
||||
|
||||
const executorToBuilderMap = new Map<string, string>([
|
||||
[
|
||||
'@nx/angular:browser-esbuild',
|
||||
'@angular-devkit/build-angular:browser-esbuild',
|
||||
],
|
||||
['@nx/angular:application', '@angular-devkit/build-angular:application'],
|
||||
]);
|
||||
|
||||
function patchBuilderContext(
|
||||
context: BuilderContext,
|
||||
isUsingEsbuildBuilder: boolean,
|
||||
buildTarget: Target
|
||||
): void {
|
||||
const originalGetBuilderNameForTarget = context.getBuilderNameForTarget;
|
||||
context.getBuilderNameForTarget = async (target) => {
|
||||
const builderName = await originalGetBuilderNameForTarget(target);
|
||||
|
||||
if (executorToBuilderMap.has(builderName)) {
|
||||
return executorToBuilderMap.get(builderName)!;
|
||||
}
|
||||
|
||||
return builderName;
|
||||
};
|
||||
|
||||
if (isUsingEsbuildBuilder) {
|
||||
const originalGetTargetOptions = context.getTargetOptions;
|
||||
context.getTargetOptions = async (target) => {
|
||||
const options = await originalGetTargetOptions(target);
|
||||
|
||||
if (
|
||||
target.project === buildTarget.project &&
|
||||
target.target === buildTarget.target &&
|
||||
target.configuration === buildTarget.configuration
|
||||
) {
|
||||
cleanBuildTargetOptions(options);
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function cleanBuildTargetOptions(
|
||||
options: any
|
||||
):
|
||||
| ApplicationBuilderOptions
|
||||
| BrowserBuilderOptions
|
||||
| BrowserEsbuildBuilderOptions {
|
||||
delete options.buildLibsFromSource;
|
||||
delete options.customWebpackConfig;
|
||||
delete options.indexHtmlTransformer;
|
||||
delete options.indexFileTransformer;
|
||||
delete options.plugins;
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@ -0,0 +1,68 @@
|
||||
import type { ExtractI18nBuilderOptions } from '@angular-devkit/build-angular';
|
||||
import { parseTargetString, type ExecutorContext } from '@nx/devkit';
|
||||
import { createBuilderContext } from 'nx/src/adapter/ngcli-adapter';
|
||||
import { readCachedProjectConfiguration } from 'nx/src/project-graph/project-graph';
|
||||
import { getInstalledAngularVersionInfo } from '../utilities/angular-version-utils';
|
||||
import { patchBuilderContext } from '../utilities/patch-builder-context';
|
||||
import type { ExtractI18nExecutorOptions } from './schema';
|
||||
|
||||
export default async function* extractI18nExecutor(
|
||||
options: ExtractI18nExecutorOptions,
|
||||
context: ExecutorContext
|
||||
) {
|
||||
const parsedBuildTarget = parseTargetString(options.buildTarget, context);
|
||||
const browserTargetProjectConfiguration = readCachedProjectConfiguration(
|
||||
parsedBuildTarget.project
|
||||
);
|
||||
|
||||
const buildTarget =
|
||||
browserTargetProjectConfiguration.targets[parsedBuildTarget.target];
|
||||
|
||||
const isUsingEsbuildBuilder = [
|
||||
'@angular-devkit/build-angular:application',
|
||||
'@angular-devkit/build-angular:browser-esbuild',
|
||||
'@nx/angular:application',
|
||||
'@nx/angular:browser-esbuild',
|
||||
].includes(buildTarget.executor);
|
||||
|
||||
const builderContext = await createBuilderContext(
|
||||
{
|
||||
builderName: 'extrct-i18n',
|
||||
description: 'Extracts i18n messages from source code.',
|
||||
optionSchema: await import('./schema.json'),
|
||||
},
|
||||
context
|
||||
);
|
||||
|
||||
/**
|
||||
* The Angular CLI extract-i18n builder make some decisions based on the build
|
||||
* target builder but it only considers `@angular-devkit/build-angular:*`
|
||||
* builders. Since we are using a custom builder, we patch the context to
|
||||
* handle `@nx/angular:*` executors.
|
||||
*/
|
||||
patchBuilderContext(builderContext, isUsingEsbuildBuilder, parsedBuildTarget);
|
||||
|
||||
const { executeExtractI18nBuilder } = await import(
|
||||
'@angular-devkit/build-angular'
|
||||
);
|
||||
const delegateBuilderOptions = getDelegateBuilderOptions(options);
|
||||
|
||||
return await executeExtractI18nBuilder(
|
||||
delegateBuilderOptions,
|
||||
builderContext
|
||||
);
|
||||
}
|
||||
|
||||
function getDelegateBuilderOptions(
|
||||
options: ExtractI18nExecutorOptions
|
||||
): ExtractI18nBuilderOptions {
|
||||
const delegateBuilderOptions: ExtractI18nBuilderOptions = { ...options };
|
||||
|
||||
const { major: angularMajorVersion } = getInstalledAngularVersionInfo();
|
||||
if (angularMajorVersion <= 17) {
|
||||
delegateBuilderOptions.browserTarget = delegateBuilderOptions.buildTarget;
|
||||
delete delegateBuilderOptions.buildTarget;
|
||||
}
|
||||
|
||||
return delegateBuilderOptions;
|
||||
}
|
||||
8
packages/angular/src/executors/extract-i18n/schema.d.ts
vendored
Normal file
8
packages/angular/src/executors/extract-i18n/schema.d.ts
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
import type { ExtractI18nBuilderOptions } from '@angular-devkit/build-angular';
|
||||
|
||||
export type ExtractI18nExecutorOptions = Omit<
|
||||
ExtractI18nBuilderOptions,
|
||||
'browserTarget'
|
||||
> & {
|
||||
buildTarget: string;
|
||||
};
|
||||
45
packages/angular/src/executors/extract-i18n/schema.json
Normal file
45
packages/angular/src/executors/extract-i18n/schema.json
Normal file
@ -0,0 +1,45 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema",
|
||||
"title": "Schema for Nx extract-i18n Executor",
|
||||
"description": "Extracts i18n messages from source code.",
|
||||
"outputCapture": "direct-nodejs",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"buildTarget": {
|
||||
"type": "string",
|
||||
"description": "A builder target to extract i18n messages in the format of `project:target[:configuration]`. You can also pass in more than one configuration name as a comma-separated list. Example: `project:target:production,staging`.",
|
||||
"pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$"
|
||||
},
|
||||
"format": {
|
||||
"type": "string",
|
||||
"description": "Output format for the generated file.",
|
||||
"default": "xlf",
|
||||
"enum": [
|
||||
"xmb",
|
||||
"xlf",
|
||||
"xlif",
|
||||
"xliff",
|
||||
"xlf2",
|
||||
"xliff2",
|
||||
"json",
|
||||
"arb",
|
||||
"legacy-migrate"
|
||||
]
|
||||
},
|
||||
"progress": {
|
||||
"type": "boolean",
|
||||
"description": "Log progress to the console.",
|
||||
"default": true
|
||||
},
|
||||
"outputPath": {
|
||||
"type": "string",
|
||||
"description": "Path where output will be placed."
|
||||
},
|
||||
"outFile": {
|
||||
"type": "string",
|
||||
"description": "Name of the file to output."
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["buildTarget"]
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
import type { BuilderContext } from '@angular-devkit/architect';
|
||||
import type {
|
||||
ApplicationBuilderOptions,
|
||||
BrowserBuilderOptions,
|
||||
} from '@angular-devkit/build-angular';
|
||||
import type { Schema as BrowserEsbuildBuilderOptions } from '@angular-devkit/build-angular/src/builders/browser-esbuild/schema';
|
||||
import type { Target } from '@nx/devkit';
|
||||
|
||||
const executorToBuilderMap = new Map<string, string>([
|
||||
[
|
||||
'@nx/angular:browser-esbuild',
|
||||
'@angular-devkit/build-angular:browser-esbuild',
|
||||
],
|
||||
['@nx/angular:application', '@angular-devkit/build-angular:application'],
|
||||
]);
|
||||
|
||||
export function patchBuilderContext(
|
||||
context: BuilderContext,
|
||||
isUsingEsbuildBuilder: boolean,
|
||||
buildTarget: Target
|
||||
): void {
|
||||
const originalGetBuilderNameForTarget = context.getBuilderNameForTarget;
|
||||
context.getBuilderNameForTarget = async (target) => {
|
||||
const builderName = await originalGetBuilderNameForTarget(target);
|
||||
|
||||
if (executorToBuilderMap.has(builderName)) {
|
||||
return executorToBuilderMap.get(builderName)!;
|
||||
}
|
||||
|
||||
return builderName;
|
||||
};
|
||||
|
||||
if (isUsingEsbuildBuilder) {
|
||||
const originalGetTargetOptions = context.getTargetOptions;
|
||||
context.getTargetOptions = async (target) => {
|
||||
const options = await originalGetTargetOptions(target);
|
||||
|
||||
if (
|
||||
target.project === buildTarget.project &&
|
||||
target.target === buildTarget.target &&
|
||||
target.configuration === buildTarget.configuration
|
||||
) {
|
||||
cleanBuildTargetOptions(options);
|
||||
}
|
||||
|
||||
return options;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function cleanBuildTargetOptions(
|
||||
options: any
|
||||
):
|
||||
| ApplicationBuilderOptions
|
||||
| BrowserBuilderOptions
|
||||
| BrowserEsbuildBuilderOptions {
|
||||
delete options.buildLibsFromSource;
|
||||
delete options.customWebpackConfig;
|
||||
delete options.indexHtmlTransformer;
|
||||
delete options.indexFileTransformer;
|
||||
delete options.plugins;
|
||||
|
||||
return options;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user