feat(angular): add the extract-i18n executor (#21802)
This commit is contained in:
parent
b625a79cca
commit
343c0f6690
@ -6706,6 +6706,14 @@
|
|||||||
"isExternal": false,
|
"isExternal": false,
|
||||||
"disableCollapsible": false
|
"disableCollapsible": false
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "extract-i18n",
|
||||||
|
"path": "/nx-api/angular/executors/extract-i18n",
|
||||||
|
"name": "extract-i18n",
|
||||||
|
"children": [],
|
||||||
|
"isExternal": false,
|
||||||
|
"disableCollapsible": false
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "webpack-browser",
|
"id": "webpack-browser",
|
||||||
"path": "/nx-api/angular/executors/webpack-browser",
|
"path": "/nx-api/angular/executors/webpack-browser",
|
||||||
|
|||||||
@ -85,6 +85,15 @@
|
|||||||
"path": "/nx-api/angular/executors/application",
|
"path": "/nx-api/angular/executors/application",
|
||||||
"type": "executor"
|
"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": {
|
"/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",
|
"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",
|
"file": "generated/packages/angular/executors/webpack-browser.json",
|
||||||
|
|||||||
@ -80,6 +80,15 @@
|
|||||||
"path": "angular/executors/application",
|
"path": "angular/executors/application",
|
||||||
"type": "executor"
|
"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",
|
"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",
|
"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)
|
- [browser-esbuild](/nx-api/angular/executors/browser-esbuild)
|
||||||
- [module-federation-dev-server](/nx-api/angular/executors/module-federation-dev-server)
|
- [module-federation-dev-server](/nx-api/angular/executors/module-federation-dev-server)
|
||||||
- [application](/nx-api/angular/executors/application)
|
- [application](/nx-api/angular/executors/application)
|
||||||
|
- [extract-i18n](/nx-api/angular/executors/extract-i18n)
|
||||||
- [webpack-browser](/nx-api/angular/executors/webpack-browser)
|
- [webpack-browser](/nx-api/angular/executors/webpack-browser)
|
||||||
- [dev-server](/nx-api/angular/executors/dev-server)
|
- [dev-server](/nx-api/angular/executors/dev-server)
|
||||||
- [webpack-server](/nx-api/angular/executors/webpack-server)
|
- [webpack-server](/nx-api/angular/executors/webpack-server)
|
||||||
|
|||||||
@ -29,6 +29,11 @@
|
|||||||
"implementation": "./src/executors/application/application.impl",
|
"implementation": "./src/executors/application/application.impl",
|
||||||
"schema": "./src/executors/application/schema.json",
|
"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_."
|
"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": {
|
"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/package/package.impl';
|
||||||
export * from './src/executors/browser-esbuild/browser-esbuild.impl';
|
export * from './src/executors/browser-esbuild/browser-esbuild.impl';
|
||||||
export * from './src/executors/application/application.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';
|
import { executeDevServerBuilder } from './src/builders/dev-server/dev-server.impl';
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
import type { BuilderContext } from '@angular-devkit/architect';
|
import type { BuilderContext } from '@angular-devkit/architect';
|
||||||
import type {
|
import type { DevServerBuilderOptions } from '@angular-devkit/build-angular';
|
||||||
ApplicationBuilderOptions,
|
|
||||||
BrowserBuilderOptions,
|
|
||||||
DevServerBuilderOptions,
|
|
||||||
} from '@angular-devkit/build-angular';
|
|
||||||
import type { Schema as BrowserEsbuildBuilderOptions } from '@angular-devkit/build-angular/src/builders/browser-esbuild/schema';
|
|
||||||
import {
|
import {
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
normalizePath,
|
normalizePath,
|
||||||
parseTargetString,
|
parseTargetString,
|
||||||
readCachedProjectGraph,
|
readCachedProjectGraph,
|
||||||
type Target,
|
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { getRootTsConfigPath } from '@nx/js';
|
import { getRootTsConfigPath } from '@nx/js';
|
||||||
import type { DependentBuildableProjectNode } from '@nx/js/src/utils/buildable-libs-utils';
|
import type { DependentBuildableProjectNode } from '@nx/js/src/utils/buildable-libs-utils';
|
||||||
@ -28,6 +22,7 @@ import {
|
|||||||
loadPlugins,
|
loadPlugins,
|
||||||
type PluginSpec,
|
type PluginSpec,
|
||||||
} from '../../executors/utilities/esbuild-extensions';
|
} from '../../executors/utilities/esbuild-extensions';
|
||||||
|
import { patchBuilderContext } from '../../executors/utilities/patch-builder-context';
|
||||||
import { createTmpTsConfigForBuildableLibs } from '../utilities/buildable-libs';
|
import { createTmpTsConfigForBuildableLibs } from '../utilities/buildable-libs';
|
||||||
import {
|
import {
|
||||||
mergeCustomWebpackConfig,
|
mergeCustomWebpackConfig,
|
||||||
@ -288,60 +283,3 @@ async function loadIndexHtmlFileTransformer(
|
|||||||
)
|
)
|
||||||
: await loadIndexHtmlTransformer(pathToIndexFileTransformer, tsConfig);
|
: 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