diff --git a/packages/localize/index.ts b/packages/localize/index.ts
index 7e531e0d29d..e58ae357021 100644
--- a/packages/localize/index.ts
+++ b/packages/localize/index.ts
@@ -11,3 +11,106 @@
// public_api_guard rules
export * from './localize';
+
+// The global declaration must be in the index.d.ts as otherwise it will not be picked up when used
+// with
+// ///
+
+import {LocalizeFn} from './src/localize';
+
+// `declare global` allows us to escape the current module and place types on the global namespace
+declare global {
+ /**
+ * Tag a template literal string for localization.
+ *
+ * For example:
+ *
+ * ```ts
+ * $localize `some string to localize`
+ * ```
+ *
+ * **Providing meaning, description and id**
+ *
+ * You can optionally specify one or more of `meaning`, `description` and `id` for a localized
+ * string by pre-pending it with a colon delimited block of the form:
+ *
+ * ```ts
+ * $localize`:meaning|description@@id:source message text`;
+ *
+ * $localize`:meaning|:source message text`;
+ * $localize`:description:source message text`;
+ * $localize`:@@id:source message text`;
+ * ```
+ *
+ * This format is the same as that used for `i18n` markers in Angular templates. See the
+ * [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template).
+ *
+ * **Naming placeholders**
+ *
+ * If the template literal string contains expressions, then the expressions will be automatically
+ * associated with placeholder names for you.
+ *
+ * For example:
+ *
+ * ```ts
+ * $localize `Hi ${name}! There are ${items.length} items.`;
+ * ```
+ *
+ * will generate a message-source of `Hi {$PH}! There are {$PH_1} items`.
+ *
+ * The recommended practice is to name the placeholder associated with each expression though.
+ *
+ * Do this by providing the placeholder name wrapped in `:` characters directly after the
+ * expression. These placeholder names are stripped out of the rendered localized string.
+ *
+ * For example, to name the `items.length` expression placeholder `itemCount` you write:
+ *
+ * ```ts
+ * $localize `There are ${items.length}:itemCount: items`;
+ * ```
+ *
+ * **Escaping colon markers**
+ *
+ * If you need to use a `:` character directly at the start of a tagged string that has no
+ * metadata block, or directly after a substitution expression that has no name you must escape
+ * the `:` by preceding it with a backslash:
+ *
+ * For example:
+ *
+ * ```ts
+ * // message has a metadata block so no need to escape colon
+ * $localize `:some description::this message starts with a colon (:)`;
+ * // no metadata block so the colon must be escaped
+ * $localize `\:this message starts with a colon (:)`;
+ * ```
+ *
+ * ```ts
+ * // named substitution so no need to escape colon
+ * $localize `${label}:label:: ${}`
+ * // anonymous substitution so colon must be escaped
+ * $localize `${label}\: ${}`
+ * ```
+ *
+ * **Processing localized strings:**
+ *
+ * There are three scenarios:
+ *
+ * * **compile-time inlining**: the `$localize` tag is transformed at compile time by a
+ * transpiler, removing the tag and replacing the template literal string with a translated
+ * literal string from a collection of translations provided to the transpilation tool.
+ *
+ * * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and
+ * reorders the parts (static strings and expressions) of the template literal string with strings
+ * from a collection of translations loaded at run-time.
+ *
+ * * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates
+ * the original template literal string without applying any translations to the parts. This
+ * version is used during development or where there is no need to translate the localized
+ * template literals.
+ *
+ * @param messageParts a collection of the static parts of the template string.
+ * @param expressions a collection of the values of each placeholder in the template string.
+ * @returns the translated string, with the `messageParts` and `expressions` interleaved together.
+ */
+ const $localize: LocalizeFn;
+}
diff --git a/packages/localize/localize.ts b/packages/localize/localize.ts
index ad2b7b1a8b0..90ae8da520f 100644
--- a/packages/localize/localize.ts
+++ b/packages/localize/localize.ts
@@ -7,107 +7,9 @@
*/
// This file contains the public API of the `@angular/localize` entry-point
-import {LocalizeFn} from './src/localize';
export {clearTranslations, loadTranslations} from './src/translate';
export {MessageId, TargetMessage} from './src/utils';
// Exports that are not part of the public API
export * from './private';
-
-// `declare global` allows us to escape the current module and place types on the global namespace
-declare global {
- /**
- * Tag a template literal string for localization.
- *
- * For example:
- *
- * ```ts
- * $localize `some string to localize`
- * ```
- *
- * **Providing meaning, description and id**
- *
- * You can optionally specify one or more of `meaning`, `description` and `id` for a localized
- * string by pre-pending it with a colon delimited block of the form:
- *
- * ```ts
- * $localize`:meaning|description@@id:source message text`;
- *
- * $localize`:meaning|:source message text`;
- * $localize`:description:source message text`;
- * $localize`:@@id:source message text`;
- * ```
- *
- * This format is the same as that used for `i18n` markers in Angular templates. See the
- * [Angular i18n guide](guide/i18n-common-prepare#mark-text-in-component-template).
- *
- * **Naming placeholders**
- *
- * If the template literal string contains expressions, then the expressions will be automatically
- * associated with placeholder names for you.
- *
- * For example:
- *
- * ```ts
- * $localize `Hi ${name}! There are ${items.length} items.`;
- * ```
- *
- * will generate a message-source of `Hi {$PH}! There are {$PH_1} items`.
- *
- * The recommended practice is to name the placeholder associated with each expression though.
- *
- * Do this by providing the placeholder name wrapped in `:` characters directly after the
- * expression. These placeholder names are stripped out of the rendered localized string.
- *
- * For example, to name the `items.length` expression placeholder `itemCount` you write:
- *
- * ```ts
- * $localize `There are ${items.length}:itemCount: items`;
- * ```
- *
- * **Escaping colon markers**
- *
- * If you need to use a `:` character directly at the start of a tagged string that has no
- * metadata block, or directly after a substitution expression that has no name you must escape
- * the `:` by preceding it with a backslash:
- *
- * For example:
- *
- * ```ts
- * // message has a metadata block so no need to escape colon
- * $localize `:some description::this message starts with a colon (:)`;
- * // no metadata block so the colon must be escaped
- * $localize `\:this message starts with a colon (:)`;
- * ```
- *
- * ```ts
- * // named substitution so no need to escape colon
- * $localize `${label}:label:: ${}`
- * // anonymous substitution so colon must be escaped
- * $localize `${label}\: ${}`
- * ```
- *
- * **Processing localized strings:**
- *
- * There are three scenarios:
- *
- * * **compile-time inlining**: the `$localize` tag is transformed at compile time by a
- * transpiler, removing the tag and replacing the template literal string with a translated
- * literal string from a collection of translations provided to the transpilation tool.
- *
- * * **run-time evaluation**: the `$localize` tag is a run-time function that replaces and
- * reorders the parts (static strings and expressions) of the template literal string with strings
- * from a collection of translations loaded at run-time.
- *
- * * **pass-through evaluation**: the `$localize` tag is a run-time function that simply evaluates
- * the original template literal string without applying any translations to the parts. This
- * version is used during development or where there is no need to translate the localized
- * template literals.
- *
- * @param messageParts a collection of the static parts of the template string.
- * @param expressions a collection of the values of each placeholder in the template string.
- * @returns the translated string, with the `messageParts` and `expressions` interleaved together.
- */
- const $localize: LocalizeFn;
-}
diff --git a/packages/localize/schematics/ng-add/index.ts b/packages/localize/schematics/ng-add/index.ts
index 462166d57c9..829bd0428a0 100644
--- a/packages/localize/schematics/ng-add/index.ts
+++ b/packages/localize/schematics/ng-add/index.ts
@@ -18,6 +18,7 @@ import {Builders} from '@schematics/angular/utility/workspace-models';
import {Schema} from './schema';
const localizeType = `@angular/localize`;
+const localizeTripleSlashType = `/// `;
function addTypeScriptConfigTypes(projectName: string): Rule {
return async (host: Tree) => {
@@ -28,7 +29,7 @@ function addTypeScriptConfigTypes(projectName: string): Rule {
}
// We add the root workspace tsconfig for better IDE support.
- const tsConfigFiles = new Set(['tsconfig.json']);
+ const tsConfigFiles = new Set();
for (const target of project.targets.values()) {
switch (target.builder) {
case Builders.Karma:
@@ -41,6 +42,13 @@ function addTypeScriptConfigTypes(projectName: string): Rule {
break;
}
+
+ if (target.builder === Builders.Browser) {
+ const value = target.options?.['main'];
+ if (typeof value === 'string') {
+ addTripleSlashType(host, value);
+ }
+ }
}
const typesJsonPath: JSONPath = ['compilerOptions', 'types'];
@@ -68,6 +76,13 @@ function addTypeScriptConfigTypes(projectName: string): Rule {
};
}
+function addTripleSlashType(host: Tree, path: string): void {
+ const content = host.readText(path);
+ if (!content.includes(localizeTripleSlashType)) {
+ host.overwrite(path, localizeTripleSlashType + '\n\n' + content);
+ }
+}
+
function moveToDependencies(host: Tree, context: SchematicContext): void {
if (!host.exists('package.json')) {
return;
diff --git a/packages/localize/schematics/ng-add/index_spec.ts b/packages/localize/schematics/ng-add/index_spec.ts
index 1f92baaa7e1..de1567ee2c5 100644
--- a/packages/localize/schematics/ng-add/index_spec.ts
+++ b/packages/localize/schematics/ng-add/index_spec.ts
@@ -16,7 +16,8 @@ interface TsConfig {
}
describe('ng-add schematic', () => {
- const localizeType = '@angular/localize';
+ const localizeTripleSlashType = `/// `;
+
const defaultOptions = {project: 'demo'};
const schematicRunner = new SchematicTestRunner(
'@angular/localize', runfiles.resolvePackageRelative('../collection.json'));
@@ -33,6 +34,11 @@ describe('ng-add schematic', () => {
},
}));
+ host.create('main.ts', `
+ import { enableProdMode } from '@angular/core';
+ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+ `);
+
host.create('angular.json', JSON.stringify({
version: 1,
projects: {
@@ -42,6 +48,7 @@ describe('ng-add schematic', () => {
build: {
builder: '@angular-devkit/build-angular:browser',
options: {
+ main: './main.ts',
tsConfig: './tsconfig.app.json',
},
},
@@ -69,36 +76,22 @@ describe('ng-add schematic', () => {
}));
});
- it(`should add '@angular/localize' in 'types' in the root level 'tsconfig.json'`, async () => {
- host.create('tsconfig.json', JSON.stringify({
- compilerOptions: {
- types: ['node'],
- },
- }));
-
+ it(`should add '@angular/localize' type reference in 'main.ts'`, async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
- const {compilerOptions} = host.readJson('tsconfig.json') as TsConfig;
- const types = compilerOptions?.types;
- expect(types).toContain(localizeType);
- expect(types).toHaveSize(2);
+ expect(host.readText('main.ts')).toContain(localizeTripleSlashType);
});
- it(`should not add '@angular/localize' in 'types' tsconfig when '@angular/localize/init' is present`,
+ it(`should not add '@angular/localize' type reference in 'main.ts' if already present`,
async () => {
- host.create('tsconfig.json', JSON.stringify({
- compilerOptions: {
- types: ['node', '@angular/localize/init'],
- },
- }));
-
+ const mainContentInput = `
+ ${localizeTripleSlashType}
+ import { enableProdMode } from '@angular/core';
+ `;
+ host.overwrite('main.ts', mainContentInput);
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
- const {compilerOptions} = host.readJson('tsconfig.json') as TsConfig;
- const types = compilerOptions?.types;
- expect(types).not.toContain(localizeType);
- expect(types).toHaveSize(2);
+ expect(host.readText('main.ts')).toBe(mainContentInput);
});
-
it(`should not add '@angular/localize' in 'types' tsconfigs referenced in non official builders`,
async () => {
const tsConfig = JSON.stringify({