diff --git a/.pullapprove.yml b/.pullapprove.yml
index a4fd7d26a44..789600040b2 100644
--- a/.pullapprove.yml
+++ b/.pullapprove.yml
@@ -1028,7 +1028,8 @@ groups:
- *can-be-global-docs-approved
- >
contains_any_globs(files, [
- 'packages/compiler-cli/src/tooling.ts'
+ 'packages/compiler-cli/src/tooling.ts',
+ 'packages/localize/tools/index.ts'
])
reviewers:
users:
diff --git a/packages/compiler-cli/BUILD.bazel b/packages/compiler-cli/BUILD.bazel
index 7ed45e5dca5..19d68a68018 100644
--- a/packages/compiler-cli/BUILD.bazel
+++ b/packages/compiler-cli/BUILD.bazel
@@ -1,6 +1,6 @@
load("//tools:defaults.bzl", "api_golden_test", "pkg_npm", "ts_config", "ts_library")
load("@npm//@bazel/esbuild:index.bzl", "esbuild", "esbuild_config")
-load(":extract_typings_rule.bzl", "extract_typings")
+load("//tools:extract_typings_rule.bzl", "extract_typings")
# Load ng_perf_flag explicitly from ng_perf.bzl as it's private API, and not exposed to other
# consumers of @angular/bazel.
diff --git a/packages/localize/BUILD.bazel b/packages/localize/BUILD.bazel
index 7214aa8a6df..42066b3b98c 100644
--- a/packages/localize/BUILD.bazel
+++ b/packages/localize/BUILD.bazel
@@ -25,7 +25,7 @@ ng_package(
],
nested_packages = [
"//packages/localize/schematics:npm_package",
- "//packages/localize/src/tools:npm_package",
+ "//packages/localize/tools:npm_package",
],
tags = [
"release-with-framework",
diff --git a/packages/localize/package.json b/packages/localize/package.json
index 27daca069ac..1d437e09b99 100644
--- a/packages/localize/package.json
+++ b/packages/localize/package.json
@@ -3,9 +3,15 @@
"version": "0.0.0-PLACEHOLDER",
"description": "Angular - library for localizing messages",
"bin": {
- "localize-translate": "./src/tools/src/translate/main.js",
- "localize-extract": "./src/tools/src/extract/main.js",
- "localize-migrate": "./src/tools/src/migrate/main.js"
+ "localize-translate": "./tools/bundles/src/translate/cli.js",
+ "localize-extract": "./tools/bundles/src/extract/cli.js",
+ "localize-migrate": "./tools/bundles/src/migrate/cli.js"
+ },
+ "exports": {
+ "./tools": {
+ "types": "./tools/index.d.ts",
+ "default": "./tools/bundles/index.js"
+ }
},
"author": "angular",
"license": "MIT",
@@ -28,7 +34,8 @@
"**/init.mjs"
],
"dependencies": {
- "@babel/core": "7.8.3",
+ "@babel/core": "7.8.6",
+ "@babel/types": "7.8.6",
"glob": "7.2.0",
"yargs": "^17.0.0"
},
diff --git a/packages/localize/src/tools/BUILD.bazel b/packages/localize/src/tools/BUILD.bazel
deleted file mode 100644
index a7b42679670..00000000000
--- a/packages/localize/src/tools/BUILD.bazel
+++ /dev/null
@@ -1,40 +0,0 @@
-load("//tools:defaults.bzl", "pkg_npm", "ts_config", "ts_library")
-
-package(default_visibility = ["//visibility:public"])
-
-ts_config(
- name = "tsconfig",
- src = "tsconfig-build.json",
- deps = ["//packages:tsconfig-build.json"],
-)
-
-ts_library(
- name = "tools",
- srcs = glob(
- [
- "**/*.ts",
- ],
- ),
- tsconfig = ":tsconfig",
- deps = [
- "//packages/compiler",
- "//packages/compiler-cli/private",
- "//packages/localize",
- "@npm//@babel/core",
- "@npm//@babel/types",
- "@npm//@types/babel__core",
- "@npm//@types/babel__traverse",
- "@npm//@types/glob",
- "@npm//@types/node",
- "@npm//@types/yargs",
- ],
-)
-
-pkg_npm(
- name = "npm_package",
- srcs = [
- ],
- deps = [
- ":tools",
- ],
-)
diff --git a/packages/localize/src/tools/tsconfig-build.json b/packages/localize/src/tools/tsconfig-build.json
deleted file mode 100644
index d72ef484361..00000000000
--- a/packages/localize/src/tools/tsconfig-build.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "extends": "../../../tsconfig-build.json",
-
- "compilerOptions": {
- "module": "commonjs",
- "stripInternal": false,
- "target": "es2015",
- "lib": [
- "es2015",
- "es2017.object"
- ],
- "paths": {
- "@angular/*": ["./packages/*"]
- },
- "strict": true,
- "types": [
- "node"
- ]
- },
- "bazelOptions": {
- "suppressTsconfigOverrideWarnings": true
- }
-}
\ No newline at end of file
diff --git a/packages/localize/tools/BUILD.bazel b/packages/localize/tools/BUILD.bazel
new file mode 100644
index 00000000000..07231f7355c
--- /dev/null
+++ b/packages/localize/tools/BUILD.bazel
@@ -0,0 +1,72 @@
+load("@npm//@bazel/esbuild:index.bzl", "esbuild", "esbuild_config")
+load("//tools:defaults.bzl", "pkg_npm", "ts_library")
+load("//tools:extract_typings_rule.bzl", "extract_typings")
+
+ts_library(
+ name = "tools",
+ srcs = glob(
+ [
+ "**/*.ts",
+ ],
+ ),
+ visibility = ["//packages/localize/tools:__subpackages__"],
+ deps = [
+ "//packages/compiler",
+ "//packages/compiler-cli/private",
+ "//packages/localize",
+ "@npm//@babel/core",
+ "@npm//@babel/types",
+ "@npm//@types/babel__core",
+ "@npm//@types/babel__traverse",
+ "@npm//@types/glob",
+ "@npm//@types/node",
+ "@npm//@types/yargs",
+ "@npm//glob",
+ ],
+)
+
+esbuild_config(
+ name = "esbuild_config",
+ config_file = "esbuild.config.js",
+)
+
+esbuild(
+ name = "bundles",
+ config = ":esbuild_config",
+ entry_points = [
+ ":index.ts",
+ ":src/extract/cli.ts",
+ ":src/migrate/cli.ts",
+ ":src/translate/cli.ts",
+ ],
+ external = [
+ "@angular/localize",
+ "@angular/compiler",
+ "@angular/compiler-cli/private/localize",
+ "@babel/core",
+ "@babel/types",
+ "yargs",
+ "glob",
+ ],
+ format = "esm",
+ platform = "node",
+ target = "node14",
+ deps = [
+ ":tools",
+ ],
+)
+
+extract_typings(
+ name = "api_type_definitions",
+ deps = [":tools"],
+)
+
+pkg_npm(
+ name = "npm_package",
+ srcs = ["README.md"],
+ visibility = ["//packages/localize:__pkg__"],
+ deps = [
+ ":api_type_definitions",
+ ":bundles",
+ ],
+)
diff --git a/packages/localize/tools/README.md b/packages/localize/tools/README.md
new file mode 100644
index 00000000000..11429306d87
--- /dev/null
+++ b/packages/localize/tools/README.md
@@ -0,0 +1,4 @@
+### Disclaimer
+
+The localize tools are consumed via the Angular CLI. The programmatic APIs are not considered officially
+supported though and are not subject to the breaking change guarantees of SemVer.
\ No newline at end of file
diff --git a/packages/localize/tools/esbuild.config.js b/packages/localize/tools/esbuild.config.js
new file mode 100644
index 00000000000..33dec5e1164
--- /dev/null
+++ b/packages/localize/tools/esbuild.config.js
@@ -0,0 +1,21 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+module.exports = {
+ resolveExtensions: ['.mjs'],
+ // Note: `@bazel/esbuild` has a bug and does not pass-through the format from Starlark.
+ format: 'esm',
+ banner: {
+ // Workaround for: https://github.com/evanw/esbuild/issues/946
+ // TODO: Remove this workaround in the future once devmode is ESM as well.
+ js: `
+ import {createRequire as __cjsCompatRequire} from 'module';
+ const require = __cjsCompatRequire(import.meta.url);
+ `,
+ },
+};
diff --git a/packages/localize/tools/index.ts b/packages/localize/tools/index.ts
new file mode 100644
index 00000000000..3127e2f0572
--- /dev/null
+++ b/packages/localize/tools/index.ts
@@ -0,0 +1,32 @@
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+// Note: Before changing any exports here, consult with the Angular tooling team
+// as the CLI heavily relies on exports declared here.
+
+import {NodeJSFileSystem, setFileSystem} from '@angular/compiler-cli/private/localize';
+setFileSystem(new NodeJSFileSystem());
+
+export {DiagnosticHandlingStrategy, Diagnostics} from './src/diagnostics';
+export {checkDuplicateMessages} from './src/extract/duplicates';
+export {MessageExtractor} from './src/extract/extraction';
+export {ArbTranslationSerializer} from './src/extract/translation_files/arb_translation_serializer';
+export {SimpleJsonTranslationSerializer} from './src/extract/translation_files/json_translation_serializer';
+export {LegacyMessageIdMigrationSerializer} from './src/extract/translation_files/legacy_message_id_migration_serializer';
+export {Xliff1TranslationSerializer} from './src/extract/translation_files/xliff1_translation_serializer';
+export {Xliff2TranslationSerializer} from './src/extract/translation_files/xliff2_translation_serializer';
+export {XmbTranslationSerializer} from './src/extract/translation_files/xmb_translation_serializer';
+export {buildLocalizeReplacement, isGlobalIdentifier, translate, unwrapExpressionsFromTemplateLiteral, unwrapMessagePartsFromLocalizeCall, unwrapMessagePartsFromTemplateLiteral, unwrapSubstitutionsFromLocalizeCall} from './src/source_file_utils';
+export {makeEs2015TranslatePlugin} from './src/translate/source_files/es2015_translate_plugin';
+export {makeEs5TranslatePlugin} from './src/translate/source_files/es5_translate_plugin';
+export {makeLocalePlugin} from './src/translate/source_files/locale_plugin';
+export {ArbTranslationParser} from './src/translate/translation_files/translation_parsers/arb_translation_parser';
+export {SimpleJsonTranslationParser} from './src/translate/translation_files/translation_parsers/simple_json_translation_parser';
+export {Xliff1TranslationParser} from './src/translate/translation_files/translation_parsers/xliff1_translation_parser';
+export {Xliff2TranslationParser} from './src/translate/translation_files/translation_parsers/xliff2_translation_parser';
+export {XtbTranslationParser} from './src/translate/translation_files/translation_parsers/xtb_translation_parser';
diff --git a/packages/localize/tools/src/extract/cli.ts b/packages/localize/tools/src/extract/cli.ts
new file mode 100644
index 00000000000..1422a7238bc
--- /dev/null
+++ b/packages/localize/tools/src/extract/cli.ts
@@ -0,0 +1,116 @@
+#!/usr/bin/env node
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {ConsoleLogger, LogLevel, NodeJSFileSystem, setFileSystem} from '@angular/compiler-cli/private/localize';
+import * as glob from 'glob';
+import * as yargs from 'yargs';
+
+import {DiagnosticHandlingStrategy} from '../diagnostics';
+import {parseFormatOptions} from './translation_files/format_options';
+import {extractTranslations} from './index';
+
+process.title = 'Angular Localization Message Extractor (localize-extract)';
+const args = process.argv.slice(2);
+const options =
+ yargs
+ .option('l', {
+ alias: 'locale',
+ describe: 'The locale of the source being processed',
+ default: 'en',
+ type: 'string',
+ })
+ .option('r', {
+ alias: 'root',
+ default: '.',
+ describe: 'The root path for other paths provided in these options.\n' +
+ 'This should either be absolute or relative to the current working directory.',
+ type: 'string',
+ })
+ .option('s', {
+ alias: 'source',
+ required: true,
+ describe:
+ 'A glob pattern indicating what files to search for translations, e.g. `./dist/**/*.js`.\n' +
+ 'This should be relative to the root path.',
+ type: 'string',
+ })
+ .option('f', {
+ alias: 'format',
+ required: true,
+ choices:
+ ['xmb', 'xlf', 'xlif', 'xliff', 'xlf2', 'xlif2', 'xliff2', 'json', 'legacy-migrate'],
+ describe: 'The format of the translation file.',
+ type: 'string',
+ })
+ .option('formatOptions', {
+ describe:
+ 'Additional options to pass to the translation file serializer, in the form of JSON formatted key-value string pairs:\n' +
+ 'For example: `--formatOptions {"xml:space":"preserve"}.\n' +
+ 'The meaning of the options is specific to the format being serialized.',
+ type: 'string'
+ })
+ .option('o', {
+ alias: 'outputPath',
+ required: true,
+ describe:
+ 'A path to where the translation file will be written. This should be relative to the root path.',
+ type: 'string',
+ })
+ .option('loglevel', {
+ describe: 'The lowest severity logging message that should be output.',
+ choices: ['debug', 'info', 'warn', 'error'],
+ type: 'string',
+ })
+ .option('useSourceMaps', {
+ type: 'boolean',
+ default: true,
+ describe:
+ 'Whether to generate source information in the output files by following source-map mappings found in the source files',
+ })
+ .option('useLegacyIds', {
+ type: 'boolean',
+ default: true,
+ describe:
+ 'Whether to use the legacy id format for messages that were extracted from Angular templates.',
+ })
+ .option('d', {
+ alias: 'duplicateMessageHandling',
+ describe: 'How to handle messages with the same id but different text.',
+ choices: ['error', 'warning', 'ignore'],
+ default: 'warning',
+ type: 'string',
+ })
+ .strict()
+ .help()
+ .parse(args);
+
+const fileSystem = new NodeJSFileSystem();
+setFileSystem(fileSystem);
+
+const rootPath = options.r;
+const sourceFilePaths = glob.sync(options.s, {cwd: rootPath, nodir: true});
+const logLevel = options.loglevel as (keyof typeof LogLevel) | undefined;
+const logger = new ConsoleLogger(logLevel ? LogLevel[logLevel] : LogLevel.warn);
+const duplicateMessageHandling = options.d as DiagnosticHandlingStrategy;
+const formatOptions = parseFormatOptions(options.formatOptions);
+const format = options.f;
+
+extractTranslations({
+ rootPath,
+ sourceFilePaths,
+ sourceLocale: options.l,
+ format,
+ outputPath: options.o,
+ logger,
+ useSourceMaps: options.useSourceMaps,
+ useLegacyIds: format === 'legacy-migrate' || options.useLegacyIds,
+ duplicateMessageHandling,
+ formatOptions,
+ fileSystem,
+});
diff --git a/packages/localize/tools/src/extract/main.ts b/packages/localize/tools/src/extract/index.ts
similarity index 52%
rename from packages/localize/tools/src/extract/main.ts
rename to packages/localize/tools/src/extract/index.ts
index 426595acdc7..a36b20e6729 100644
--- a/packages/localize/tools/src/extract/main.ts
+++ b/packages/localize/tools/src/extract/index.ts
@@ -1,4 +1,3 @@
-#!/usr/bin/env node
/**
* @license
* Copyright Google LLC All Rights Reserved.
@@ -6,126 +5,22 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {setFileSystem, NodeJSFileSystem, AbsoluteFsPath, FileSystem, PathManipulation, ConsoleLogger, Logger, LogLevel} from '@angular/compiler-cli/private/localize';
+import {AbsoluteFsPath, FileSystem, Logger, PathManipulation} from '@angular/compiler-cli/private/localize';
import {ɵParsedMessage} from '@angular/localize';
-import * as glob from 'glob';
-import * as yargs from 'yargs';
-import {Diagnostics, DiagnosticHandlingStrategy} from '../diagnostics';
+import {DiagnosticHandlingStrategy, Diagnostics} from '../diagnostics';
import {checkDuplicateMessages} from './duplicates';
import {MessageExtractor} from './extraction';
-import {TranslationSerializer} from './translation_files/translation_serializer';
import {ArbTranslationSerializer} from './translation_files/arb_translation_serializer';
+import {FormatOptions} from './translation_files/format_options';
import {SimpleJsonTranslationSerializer} from './translation_files/json_translation_serializer';
+import {LegacyMessageIdMigrationSerializer} from './translation_files/legacy_message_id_migration_serializer';
+import {TranslationSerializer} from './translation_files/translation_serializer';
import {Xliff1TranslationSerializer} from './translation_files/xliff1_translation_serializer';
import {Xliff2TranslationSerializer} from './translation_files/xliff2_translation_serializer';
import {XmbTranslationSerializer} from './translation_files/xmb_translation_serializer';
-import {FormatOptions, parseFormatOptions} from './translation_files/format_options';
-import {LegacyMessageIdMigrationSerializer} from './translation_files/legacy_message_id_migration_serializer';
-if (require.main === module) {
- process.title = 'Angular Localization Message Extractor (localize-extract)';
- const args = process.argv.slice(2);
- const options =
- yargs
- .option('l', {
- alias: 'locale',
- describe: 'The locale of the source being processed',
- default: 'en',
- type: 'string',
- })
- .option('r', {
- alias: 'root',
- default: '.',
- describe: 'The root path for other paths provided in these options.\n' +
- 'This should either be absolute or relative to the current working directory.',
- type: 'string',
- })
- .option('s', {
- alias: 'source',
- required: true,
- describe:
- 'A glob pattern indicating what files to search for translations, e.g. `./dist/**/*.js`.\n' +
- 'This should be relative to the root path.',
- type: 'string',
- })
- .option('f', {
- alias: 'format',
- required: true,
- choices: [
- 'xmb', 'xlf', 'xlif', 'xliff', 'xlf2', 'xlif2', 'xliff2', 'json', 'legacy-migrate'
- ],
- describe: 'The format of the translation file.',
- type: 'string',
- })
- .option('formatOptions', {
- describe:
- 'Additional options to pass to the translation file serializer, in the form of JSON formatted key-value string pairs:\n' +
- 'For example: `--formatOptions {"xml:space":"preserve"}.\n' +
- 'The meaning of the options is specific to the format being serialized.',
- type: 'string'
- })
- .option('o', {
- alias: 'outputPath',
- required: true,
- describe:
- 'A path to where the translation file will be written. This should be relative to the root path.',
- type: 'string',
- })
- .option('loglevel', {
- describe: 'The lowest severity logging message that should be output.',
- choices: ['debug', 'info', 'warn', 'error'],
- type: 'string',
- })
- .option('useSourceMaps', {
- type: 'boolean',
- default: true,
- describe:
- 'Whether to generate source information in the output files by following source-map mappings found in the source files',
- })
- .option('useLegacyIds', {
- type: 'boolean',
- default: true,
- describe:
- 'Whether to use the legacy id format for messages that were extracted from Angular templates.',
- })
- .option('d', {
- alias: 'duplicateMessageHandling',
- describe: 'How to handle messages with the same id but different text.',
- choices: ['error', 'warning', 'ignore'],
- default: 'warning',
- type: 'string',
- })
- .strict()
- .help()
- .parse(args);
-
- const fileSystem = new NodeJSFileSystem();
- setFileSystem(fileSystem);
-
- const rootPath = options.r;
- const sourceFilePaths = glob.sync(options.s, {cwd: rootPath, nodir: true});
- const logLevel = options.loglevel as (keyof typeof LogLevel) | undefined;
- const logger = new ConsoleLogger(logLevel ? LogLevel[logLevel] : LogLevel.warn);
- const duplicateMessageHandling = options.d as DiagnosticHandlingStrategy;
- const formatOptions = parseFormatOptions(options.formatOptions);
- const format = options.f;
-
- extractTranslations({
- rootPath,
- sourceFilePaths,
- sourceLocale: options.l,
- format,
- outputPath: options.o,
- logger,
- useSourceMaps: options.useSourceMaps,
- useLegacyIds: format === 'legacy-migrate' || options.useLegacyIds,
- duplicateMessageHandling,
- formatOptions,
- fileSystem,
- });
-}
export interface ExtractTranslationsOptions {
/**
diff --git a/packages/localize/tools/src/migrate/cli.ts b/packages/localize/tools/src/migrate/cli.ts
new file mode 100644
index 00000000000..c0528662cab
--- /dev/null
+++ b/packages/localize/tools/src/migrate/cli.ts
@@ -0,0 +1,51 @@
+#!/usr/bin/env node
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+
+import {ConsoleLogger, LogLevel, NodeJSFileSystem, setFileSystem} from '@angular/compiler-cli/private/localize';
+import * as glob from 'glob';
+import * as yargs from 'yargs';
+import {migrateFiles} from './index';
+
+const args = process.argv.slice(2);
+const options =
+ yargs
+ .option('r', {
+ alias: 'root',
+ default: '.',
+ describe: 'The root path for other paths provided in these options.\n' +
+ 'This should either be absolute or relative to the current working directory.',
+ type: 'string',
+ })
+ .option('f', {
+ alias: 'files',
+ required: true,
+ describe:
+ 'A glob pattern indicating what files to migrate. This should be relative to the root path',
+ type: 'string',
+ })
+ .option('m', {
+ alias: 'mapFile',
+ required: true,
+ describe:
+ 'Path to the migration mapping file generated by `localize-extract`. This should be relative to the root path.',
+ type: 'string',
+ })
+ .strict()
+ .help()
+ .parse(args);
+
+const fs = new NodeJSFileSystem();
+setFileSystem(fs);
+
+const rootPath = options.r;
+const translationFilePaths = glob.sync(options.f, {cwd: rootPath, nodir: true});
+const logger = new ConsoleLogger(LogLevel.warn);
+
+migrateFiles({rootPath, translationFilePaths, mappingFilePath: options.m, logger});
+process.exit(0);
diff --git a/packages/localize/tools/src/migrate/main.ts b/packages/localize/tools/src/migrate/index.ts
similarity index 51%
rename from packages/localize/tools/src/migrate/main.ts
rename to packages/localize/tools/src/migrate/index.ts
index 8fa81cc14f4..c05cdef9d63 100644
--- a/packages/localize/tools/src/migrate/main.ts
+++ b/packages/localize/tools/src/migrate/index.ts
@@ -1,4 +1,3 @@
-#!/usr/bin/env node
/**
* @license
* Copyright Google LLC All Rights Reserved.
@@ -6,51 +5,10 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {getFileSystem, NodeJSFileSystem, setFileSystem, ConsoleLogger, Logger, LogLevel} from '@angular/compiler-cli/private/localize';
-import * as glob from 'glob';
-import * as yargs from 'yargs';
+
+import {getFileSystem, Logger} from '@angular/compiler-cli/private/localize';
import {migrateFile, MigrationMapping} from './migrate';
-if (require.main === module) {
- const args = process.argv.slice(2);
- const options =
- yargs
- .option('r', {
- alias: 'root',
- default: '.',
- describe: 'The root path for other paths provided in these options.\n' +
- 'This should either be absolute or relative to the current working directory.',
- type: 'string',
- })
- .option('f', {
- alias: 'files',
- required: true,
- describe:
- 'A glob pattern indicating what files to migrate. This should be relative to the root path',
- type: 'string',
- })
- .option('m', {
- alias: 'mapFile',
- required: true,
- describe:
- 'Path to the migration mapping file generated by `localize-extract`. This should be relative to the root path.',
- type: 'string',
- })
- .strict()
- .help()
- .parse(args);
-
- const fs = new NodeJSFileSystem();
- setFileSystem(fs);
-
- const rootPath = options.r;
- const translationFilePaths = glob.sync(options.f, {cwd: rootPath, nodir: true});
- const logger = new ConsoleLogger(LogLevel.warn);
-
- migrateFiles({rootPath, translationFilePaths, mappingFilePath: options.m, logger});
- process.exit(0);
-}
-
export interface MigrateFilesOptions {
/**
* The base path for other paths provided in these options.
diff --git a/packages/localize/tools/src/translate/cli.ts b/packages/localize/tools/src/translate/cli.ts
new file mode 100644
index 00000000000..c1724552bd1
--- /dev/null
+++ b/packages/localize/tools/src/translate/cli.ts
@@ -0,0 +1,131 @@
+#!/usr/bin/env node
+/**
+ * @license
+ * Copyright Google LLC All Rights Reserved.
+ *
+ * Use of this source code is governed by an MIT-style license that can be
+ * found in the LICENSE file at https://angular.io/license
+ */
+import {NodeJSFileSystem, setFileSystem} from '@angular/compiler-cli/private/localize';
+import * as glob from 'glob';
+import * as yargs from 'yargs';
+
+import {DiagnosticHandlingStrategy, Diagnostics} from '../diagnostics';
+import {getOutputPathFn} from './output_path';
+import {translateFiles} from './index';
+
+process.title = 'Angular Localization Message Translator (localize-translate)';
+const args = process.argv.slice(2);
+const options =
+ yargs
+ .option('r', {
+ alias: 'root',
+ required: true,
+ describe:
+ 'The root path of the files to translate, either absolute or relative to the current working directory. E.g. `dist/en`.',
+ type: 'string',
+ })
+ .option('s', {
+ alias: 'source',
+ required: true,
+ describe:
+ 'A glob pattern indicating what files to translate, relative to the `root` path. E.g. `bundles/**/*`.',
+ type: 'string',
+ })
+
+ .option('l', {
+ alias: 'source-locale',
+ describe:
+ 'The source locale of the application. If this is provided then a copy of the application will be created with no translation but just the `$localize` calls stripped out.',
+ type: 'string',
+ })
+
+ .option('t', {
+ alias: 'translations',
+ required: true,
+ array: true,
+ describe:
+ 'A list of paths to the translation files to load, either absolute or relative to the current working directory.\n' +
+ 'E.g. `-t src/locale/messages.en.xlf src/locale/messages.fr.xlf src/locale/messages.de.xlf`.\n' +
+ 'If you want to merge multiple translation files for each locale, then provide the list of files in an array.\n' +
+ 'Note that the arrays must be in double quotes if you include any whitespace within the array.\n' +
+ 'E.g. `-t "[src/locale/messages.en.xlf, src/locale/messages-2.en.xlf]" [src/locale/messages.fr.xlf,src/locale/messages-2.fr.xlf]`',
+ type: 'string',
+ })
+
+ .option('target-locales', {
+ array: true,
+ describe:
+ 'A list of target locales for the translation files, which will override any target locale parsed from the translation file.\n' +
+ 'E.g. "-t en fr de".',
+ type: 'string',
+ })
+
+ .option('o', {
+ alias: 'outputPath',
+ required: true,
+ describe: 'A output path pattern to where the translated files will be written.\n' +
+ 'The path must be either absolute or relative to the current working directory.\n' +
+ 'The marker `{{LOCALE}}` will be replaced with the target locale. E.g. `dist/{{LOCALE}}`.',
+ type: 'string',
+ })
+
+ .option('m', {
+ alias: 'missingTranslation',
+ describe: 'How to handle missing translations.',
+ choices: ['error', 'warning', 'ignore'],
+ default: 'warning',
+ type: 'string',
+ })
+
+ .option('d', {
+ alias: 'duplicateTranslation',
+ describe: 'How to handle duplicate translations.',
+ choices: ['error', 'warning', 'ignore'],
+ default: 'warning',
+ type: 'string',
+ })
+
+ .strict()
+ .help()
+ .parse(args);
+
+const fs = new NodeJSFileSystem();
+setFileSystem(fs);
+
+const sourceRootPath = options.r;
+const sourceFilePaths = glob.sync(options.s, {cwd: sourceRootPath, nodir: true});
+const translationFilePaths: (string|string[])[] = convertArraysFromArgs(options.t);
+const outputPathFn = getOutputPathFn(fs, fs.resolve(options.o));
+const diagnostics = new Diagnostics();
+const missingTranslation = options.m as DiagnosticHandlingStrategy;
+const duplicateTranslation = options.d as DiagnosticHandlingStrategy;
+const sourceLocale: string|undefined = options.l;
+const translationFileLocales: string[] = options['target-locales'] || [];
+
+translateFiles({
+ sourceRootPath,
+ sourceFilePaths,
+ translationFilePaths,
+ translationFileLocales,
+ outputPathFn,
+ diagnostics,
+ missingTranslation,
+ duplicateTranslation,
+ sourceLocale
+});
+
+diagnostics.messages.forEach(m => console.warn(`${m.type}: ${m.message}`));
+process.exit(diagnostics.hasErrors ? 1 : 0);
+
+/**
+ * Parse each of the given string `args` and convert it to an array if it is of the form
+ * `[abc, def, ghi]`, i.e. it is enclosed in square brackets with comma delimited items.
+ * @param args The string to potentially convert to arrays.
+ */
+function convertArraysFromArgs(args: string[]): (string|string[])[] {
+ return args.map(
+ arg => (arg.startsWith('[') && arg.endsWith(']')) ?
+ arg.slice(1, -1).split(',').map(arg => arg.trim()) :
+ arg);
+}
diff --git a/packages/localize/tools/src/translate/main.ts b/packages/localize/tools/src/translate/index.ts
similarity index 50%
rename from packages/localize/tools/src/translate/main.ts
rename to packages/localize/tools/src/translate/index.ts
index e216705525b..019cbfc7e50 100644
--- a/packages/localize/tools/src/translate/main.ts
+++ b/packages/localize/tools/src/translate/index.ts
@@ -1,4 +1,3 @@
-#!/usr/bin/env node
/**
* @license
* Copyright Google LLC All Rights Reserved.
@@ -6,13 +5,11 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {getFileSystem, NodeJSFileSystem, setFileSystem, relativeFrom} from '@angular/compiler-cli/private/localize';
-import * as glob from 'glob';
-import * as yargs from 'yargs';
+import {getFileSystem, relativeFrom} from '@angular/compiler-cli/private/localize';
import {DiagnosticHandlingStrategy, Diagnostics} from '../diagnostics';
import {AssetTranslationHandler} from './asset_files/asset_translation_handler';
-import {getOutputPathFn, OutputPathFn} from './output_path';
+import {OutputPathFn} from './output_path';
import {SourceFileTranslationHandler} from './source_files/source_file_translation_handler';
import {TranslationLoader} from './translation_files/translation_loader';
import {ArbTranslationParser} from './translation_files/translation_parsers/arb_translation_parser';
@@ -22,112 +19,6 @@ import {Xliff2TranslationParser} from './translation_files/translation_parsers/x
import {XtbTranslationParser} from './translation_files/translation_parsers/xtb_translation_parser';
import {Translator} from './translator';
-if (require.main === module) {
- process.title = 'Angular Localization Message Translator (localize-translate)';
- const args = process.argv.slice(2);
- const options =
- yargs
- .option('r', {
- alias: 'root',
- required: true,
- describe:
- 'The root path of the files to translate, either absolute or relative to the current working directory. E.g. `dist/en`.',
- type: 'string',
- })
- .option('s', {
- alias: 'source',
- required: true,
- describe:
- 'A glob pattern indicating what files to translate, relative to the `root` path. E.g. `bundles/**/*`.',
- type: 'string',
- })
-
- .option('l', {
- alias: 'source-locale',
- describe:
- 'The source locale of the application. If this is provided then a copy of the application will be created with no translation but just the `$localize` calls stripped out.',
- type: 'string',
- })
-
- .option('t', {
- alias: 'translations',
- required: true,
- array: true,
- describe:
- 'A list of paths to the translation files to load, either absolute or relative to the current working directory.\n' +
- 'E.g. `-t src/locale/messages.en.xlf src/locale/messages.fr.xlf src/locale/messages.de.xlf`.\n' +
- 'If you want to merge multiple translation files for each locale, then provide the list of files in an array.\n' +
- 'Note that the arrays must be in double quotes if you include any whitespace within the array.\n' +
- 'E.g. `-t "[src/locale/messages.en.xlf, src/locale/messages-2.en.xlf]" [src/locale/messages.fr.xlf,src/locale/messages-2.fr.xlf]`',
- type: 'string',
- })
-
- .option('target-locales', {
- array: true,
- describe:
- 'A list of target locales for the translation files, which will override any target locale parsed from the translation file.\n' +
- 'E.g. "-t en fr de".',
- type: 'string',
- })
-
- .option('o', {
- alias: 'outputPath',
- required: true,
- describe: 'A output path pattern to where the translated files will be written.\n' +
- 'The path must be either absolute or relative to the current working directory.\n' +
- 'The marker `{{LOCALE}}` will be replaced with the target locale. E.g. `dist/{{LOCALE}}`.',
- type: 'string',
- })
-
- .option('m', {
- alias: 'missingTranslation',
- describe: 'How to handle missing translations.',
- choices: ['error', 'warning', 'ignore'],
- default: 'warning',
- type: 'string',
- })
-
- .option('d', {
- alias: 'duplicateTranslation',
- describe: 'How to handle duplicate translations.',
- choices: ['error', 'warning', 'ignore'],
- default: 'warning',
- type: 'string',
- })
-
- .strict()
- .help()
- .parse(args);
-
- const fs = new NodeJSFileSystem();
- setFileSystem(fs);
-
- const sourceRootPath = options.r;
- const sourceFilePaths = glob.sync(options.s, {cwd: sourceRootPath, nodir: true});
- const translationFilePaths: (string|string[])[] = convertArraysFromArgs(options.t);
- const outputPathFn = getOutputPathFn(fs, fs.resolve(options.o));
- const diagnostics = new Diagnostics();
- const missingTranslation = options.m as DiagnosticHandlingStrategy;
- const duplicateTranslation = options.d as DiagnosticHandlingStrategy;
- const sourceLocale: string|undefined = options.l;
- const translationFileLocales: string[] = options['target-locales'] || [];
-
- translateFiles({
- sourceRootPath,
- sourceFilePaths,
- translationFilePaths,
- translationFileLocales,
- outputPathFn,
- diagnostics,
- missingTranslation,
- duplicateTranslation,
- sourceLocale
- });
-
- diagnostics.messages.forEach(m => console.warn(`${m.type}: ${m.message}`));
- process.exit(diagnostics.hasErrors ? 1 : 0);
-}
-
export interface TranslateFilesOptions {
/**
* The root path of the files to translate, either absolute or relative to the current working
@@ -235,15 +126,3 @@ export function translateFiles({
sourceFilePaths.map(relativeFrom), fs.resolve(sourceRootPath), outputPathFn, translations,
sourceLocale);
}
-
-/**
- * Parse each of the given string `args` and convert it to an array if it is of the form
- * `[abc, def, ghi]`, i.e. it is enclosed in square brackets with comma delimited items.
- * @param args The string to potentially convert to arrays.
- */
-function convertArraysFromArgs(args: string[]): (string|string[])[] {
- return args.map(
- arg => (arg.startsWith('[') && arg.endsWith(']')) ?
- arg.slice(1, -1).split(',').map(arg => arg.trim()) :
- arg);
-}
diff --git a/packages/localize/tools/src/translate/translation_files/translation_parsers/translation_parser.ts b/packages/localize/tools/src/translate/translation_files/translation_parsers/translation_parser.ts
index 514ff7bdecf..51d21009d98 100644
--- a/packages/localize/tools/src/translate/translation_files/translation_parsers/translation_parser.ts
+++ b/packages/localize/tools/src/translate/translation_files/translation_parsers/translation_parser.ts
@@ -5,7 +5,7 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
-import {ɵMessageId, ɵParsedTranslation} from '@angular/localize/private';
+import {ɵMessageId, ɵParsedTranslation} from '@angular/localize';
import {Diagnostics} from '../../../diagnostics';
/**
diff --git a/packages/localize/tools/test/BUILD.bazel b/packages/localize/tools/test/BUILD.bazel
index 1e2d6d768c9..e575065a6f6 100644
--- a/packages/localize/tools/test/BUILD.bazel
+++ b/packages/localize/tools/test/BUILD.bazel
@@ -6,7 +6,7 @@ ts_library(
srcs = glob(
["**/*.ts"],
),
- visibility = ["//packages/localize/src/tools/test:__subpackages__"],
+ visibility = ["//packages/localize/tools/test:__subpackages__"],
deps = [
"//packages:types",
"//packages/compiler",
@@ -14,9 +14,9 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/file_system/testing",
"//packages/compiler-cli/src/ngtsc/logging/testing",
"//packages/localize",
- "//packages/localize/src/tools",
- "//packages/localize/src/tools/test/helpers",
"//packages/localize/src/utils",
+ "//packages/localize/tools",
+ "//packages/localize/tools/test/helpers",
"@npm//@babel/core",
"@npm//@babel/generator",
"@npm//@babel/template",
diff --git a/packages/localize/tools/test/extract/integration/BUILD.bazel b/packages/localize/tools/test/extract/integration/BUILD.bazel
index 0fbc08c302e..1464fa8e72b 100644
--- a/packages/localize/tools/test/extract/integration/BUILD.bazel
+++ b/packages/localize/tools/test/extract/integration/BUILD.bazel
@@ -13,9 +13,9 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/logging",
"//packages/compiler-cli/src/ngtsc/logging/testing",
"//packages/compiler-cli/src/ngtsc/testing",
- "//packages/localize/src/tools",
- "//packages/localize/src/tools/test:test_lib",
- "//packages/localize/src/tools/test/helpers",
+ "//packages/localize/tools",
+ "//packages/localize/tools/test:test_lib",
+ "//packages/localize/tools/test/helpers",
],
)
@@ -23,9 +23,9 @@ jasmine_node_test(
name = "integration",
bootstrap = ["//tools/testing:node_no_angular_es5"],
data = [
- "//packages/localize/src/tools/test/extract/integration/test_files",
- "//packages/localize/src/tools/test/extract/integration/test_files:compile_es2015",
- "//packages/localize/src/tools/test/extract/integration/test_files:compile_es5",
+ "//packages/localize/tools/test/extract/integration/test_files",
+ "//packages/localize/tools/test/extract/integration/test_files:compile_es2015",
+ "//packages/localize/tools/test/extract/integration/test_files:compile_es5",
],
deps = [
":test_lib",
diff --git a/packages/localize/tools/test/extract/integration/main_spec.ts b/packages/localize/tools/test/extract/integration/main_spec.ts
index bc1c45b60f7..c26a90b55c2 100644
--- a/packages/localize/tools/test/extract/integration/main_spec.ts
+++ b/packages/localize/tools/test/extract/integration/main_spec.ts
@@ -10,7 +10,7 @@ import {InvalidFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system/src
import {MockLogger} from '@angular/compiler-cli/src/ngtsc/logging/testing';
import {loadTestDirectory} from '@angular/compiler-cli/src/ngtsc/testing';
-import {extractTranslations} from '../../../src/extract/main';
+import {extractTranslations} from '../../../src/extract/index';
import {FormatOptions} from '../../../src/extract/translation_files/format_options';
import {runInNativeFileSystem} from '../../helpers';
import {toAttributes} from '../translation_files/utils';
@@ -398,7 +398,7 @@ runInNativeFileSystem(() => {
` `,
// These source file paths are due to how Bazel TypeScript compilation source-maps
// work
- ` ../packages/localize/src/tools/test/extract/integration/test_files/src/a.ts`,
+ ` ../packages/localize/tools/test/extract/integration/test_files/src/a.ts`,
` 3,${
target === 'es2015' ? 7 : 5}`,
` `,
@@ -406,7 +406,7 @@ runInNativeFileSystem(() => {
` `,
` Message in !`,
` `,
- ` ../packages/localize/src/tools/test/extract/integration/test_files/src/b.ts`,
+ ` ../packages/localize/tools/test/extract/integration/test_files/src/b.ts`,
` 3`,
` `,
` `,
diff --git a/packages/localize/tools/test/extract/integration/test_files/BUILD.bazel b/packages/localize/tools/test/extract/integration/test_files/BUILD.bazel
index 8ed3f1c0281..5a89e435a17 100644
--- a/packages/localize/tools/test/extract/integration/test_files/BUILD.bazel
+++ b/packages/localize/tools/test/extract/integration/test_files/BUILD.bazel
@@ -1,7 +1,7 @@
load("@npm//typescript:index.bzl", "tsc")
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
-package(default_visibility = ["//packages/localize/src/tools/test/extract/integration:__pkg__"])
+package(default_visibility = ["//packages/localize/tools/test/extract/integration:__pkg__"])
tsc(
name = "compile_es5",
diff --git a/packages/localize/tools/test/helpers/BUILD.bazel b/packages/localize/tools/test/helpers/BUILD.bazel
index a54218c7402..9f9ea16d7ef 100644
--- a/packages/localize/tools/test/helpers/BUILD.bazel
+++ b/packages/localize/tools/test/helpers/BUILD.bazel
@@ -6,7 +6,7 @@ ts_library(
srcs = glob(
["**/*.ts"],
),
- visibility = ["//packages/localize/src/tools/test:__subpackages__"],
+ visibility = ["//packages/localize/tools/test:__subpackages__"],
deps = [
"//packages/compiler-cli/src/ngtsc/file_system",
"//packages/compiler-cli/src/ngtsc/file_system/testing",
diff --git a/packages/localize/tools/test/migrate/integration/BUILD.bazel b/packages/localize/tools/test/migrate/integration/BUILD.bazel
index 1b3e056feca..52b652f7544 100644
--- a/packages/localize/tools/test/migrate/integration/BUILD.bazel
+++ b/packages/localize/tools/test/migrate/integration/BUILD.bazel
@@ -14,9 +14,9 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/logging",
"//packages/compiler-cli/src/ngtsc/logging/testing",
"//packages/compiler-cli/src/ngtsc/testing",
- "//packages/localize/src/tools",
- "//packages/localize/src/tools/test:test_lib",
- "//packages/localize/src/tools/test/helpers",
+ "//packages/localize/tools",
+ "//packages/localize/tools/test:test_lib",
+ "//packages/localize/tools/test/helpers",
],
)
diff --git a/packages/localize/tools/test/migrate/integration/main_spec.ts b/packages/localize/tools/test/migrate/integration/main_spec.ts
index 9972cd4df92..5c331a7bb92 100644
--- a/packages/localize/tools/test/migrate/integration/main_spec.ts
+++ b/packages/localize/tools/test/migrate/integration/main_spec.ts
@@ -8,7 +8,7 @@
import {absoluteFrom, AbsoluteFsPath, FileSystem, getFileSystem} from '@angular/compiler-cli/src/ngtsc/file_system';
import {MockLogger} from '@angular/compiler-cli/src/ngtsc/logging/testing';
import {loadTestDirectory} from '@angular/compiler-cli/src/ngtsc/testing';
-import {migrateFiles} from '../../../src/migrate/main';
+import {migrateFiles} from '../../../src/migrate/index';
import {runInNativeFileSystem} from '../../helpers';
runInNativeFileSystem(() => {
diff --git a/packages/localize/tools/test/translate/integration/BUILD.bazel b/packages/localize/tools/test/translate/integration/BUILD.bazel
index f2fd7a622f9..c0ac0e20e27 100644
--- a/packages/localize/tools/test/translate/integration/BUILD.bazel
+++ b/packages/localize/tools/test/translate/integration/BUILD.bazel
@@ -11,8 +11,8 @@ ts_library(
"//packages/compiler-cli/src/ngtsc/file_system",
"//packages/compiler-cli/src/ngtsc/file_system/testing",
"//packages/compiler-cli/src/ngtsc/testing",
- "//packages/localize/src/tools",
- "//packages/localize/src/tools/test/helpers",
+ "//packages/localize/tools",
+ "//packages/localize/tools/test/helpers",
],
)
@@ -20,8 +20,8 @@ jasmine_node_test(
name = "integration",
bootstrap = ["//tools/testing:node_no_angular_es5"],
data = [
- "//packages/localize/src/tools/test/translate/integration/locales",
- "//packages/localize/src/tools/test/translate/integration/test_files",
+ "//packages/localize/tools/test/translate/integration/locales",
+ "//packages/localize/tools/test/translate/integration/test_files",
],
deps = [
":test_lib",
diff --git a/packages/localize/tools/test/translate/integration/locales/BUILD.bazel b/packages/localize/tools/test/translate/integration/locales/BUILD.bazel
index 65ab28b4dea..115206c324d 100644
--- a/packages/localize/tools/test/translate/integration/locales/BUILD.bazel
+++ b/packages/localize/tools/test/translate/integration/locales/BUILD.bazel
@@ -1,6 +1,6 @@
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
-package(default_visibility = ["//packages/localize/src/tools/test/translate/integration:__pkg__"])
+package(default_visibility = ["//packages/localize/tools/test/translate/integration:__pkg__"])
# Use copy_to_bin since filegroup doesn't seem to work on Windows.
copy_to_bin(
diff --git a/packages/localize/tools/test/translate/integration/main_spec.ts b/packages/localize/tools/test/translate/integration/main_spec.ts
index d0912838202..d5a13760369 100644
--- a/packages/localize/tools/test/translate/integration/main_spec.ts
+++ b/packages/localize/tools/test/translate/integration/main_spec.ts
@@ -10,7 +10,7 @@ import {loadTestDirectory} from '@angular/compiler-cli/src/ngtsc/testing';
import {resolve as realResolve} from 'path';
import {Diagnostics} from '../../../src/diagnostics';
-import {translateFiles} from '../../../src/translate/main';
+import {translateFiles} from '../../../src/translate/index';
import {getOutputPathFn} from '../../../src/translate/output_path';
import {runInNativeFileSystem} from '../../helpers';
diff --git a/packages/localize/tools/test/translate/integration/test_files/BUILD.bazel b/packages/localize/tools/test/translate/integration/test_files/BUILD.bazel
index 16ed5b318d2..0fd58048857 100644
--- a/packages/localize/tools/test/translate/integration/test_files/BUILD.bazel
+++ b/packages/localize/tools/test/translate/integration/test_files/BUILD.bazel
@@ -1,6 +1,6 @@
load("@build_bazel_rules_nodejs//:index.bzl", "copy_to_bin")
-package(default_visibility = ["//packages/localize/src/tools/test/translate/integration:__pkg__"])
+package(default_visibility = ["//packages/localize/tools/test/translate/integration:__pkg__"])
# Use copy_to_bin since filegroup doesn't seem to work on Windows.
copy_to_bin(
diff --git a/packages/compiler-cli/extract_typings_rule.bzl b/tools/extract_typings_rule.bzl
similarity index 95%
rename from packages/compiler-cli/extract_typings_rule.bzl
rename to tools/extract_typings_rule.bzl
index 0cb80c1d509..ee07748fdb7 100644
--- a/packages/compiler-cli/extract_typings_rule.bzl
+++ b/tools/extract_typings_rule.bzl
@@ -14,6 +14,7 @@ def _extract_typings_rule_impl(ctx):
return [DefaultInfo(files = depset(transitive = transitive_depsets))]
+# TODO: Move into shared dev-infra package.
extract_typings = rule(
implementation = _extract_typings_rule_impl,
doc = """Rule that extracts all transitive typings of dependencies""",