Skip to content

Commit

Permalink
fix(localize): update ng add schematic to support Angular CLI version…
Browse files Browse the repository at this point in the history
… 15 (#47763)

Prior to this, the `@angular/localize/init` was added as a polyfill which caused the `@angular/localize` types not to be included in the TypeScript program which caused errors such as the below:

```
Error: src/app/app.component.ts:9:11 - error TS2304: Cannot find name '$localize'.
```

With the recent changes in the CLI (angular/angular-cli#24032), adding `@angular/localize/init` as polyfil or in the `main.server.ts` is no longer necessary. Instead we add this as a TypeScript type. When users are running in JIT mode, we add `@angular/localize/init` as an additional entrypoint.

This change also exposes the `$localize` method as a global when importing `@angular/localize`.

Closes #47677

PR Close #47763
  • Loading branch information
alan-agius4 authored and dylhunn committed Oct 17, 2022
1 parent 4c95484 commit b6fd814
Show file tree
Hide file tree
Showing 9 changed files with 274 additions and 334 deletions.
4 changes: 2 additions & 2 deletions goldens/public-api/localize/init/index.md
Expand Up @@ -4,11 +4,11 @@
```ts

import { ɵ$localize as $localize_2 } from '@angular/localize';
import { ɵ$localize as $localize } from '@angular/localize';
import { ɵLocalizeFn as LocalizeFn } from '@angular/localize';
import { ɵTranslateFn as TranslateFn } from '@angular/localize';

export { $localize_2 as $localize }
export { $localize }

export { LocalizeFn }

Expand Down
4 changes: 2 additions & 2 deletions integration/ng-add-localize/src/app/app.component.ts
Expand Up @@ -23,10 +23,10 @@ import { Component } from '@angular/core';
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>
`,
styles: []
})
export class AppComponent {
title = 'ng-add-localize';
title = $localize`ng-add-localize`;
}
12 changes: 9 additions & 3 deletions packages/localize/BUILD.bazel
@@ -1,4 +1,4 @@
load("//tools:defaults.bzl", "api_golden_test_npm_package", "ng_package", "ts_library")
load("//tools:defaults.bzl", "api_golden_test_npm_package", "extract_types", "ng_package", "ts_library")

package(default_visibility = ["//visibility:public"])

Expand All @@ -17,20 +17,26 @@ ts_library(
],
)

extract_types(
name = "api_type_definitions",
deps = [":localize"],
)

ng_package(
name = "npm_package",
srcs = [
"package.json",
":api_type_definitions",
],
nested_packages = [
"//packages/localize/schematics:npm_package",
"//packages/localize/tools:npm_package",
],
skip_type_bundling = [
# For the "init" entry-point we disable type bundling because API extractor
# For the primary entry-point we disable type bundling because API extractor
# does not properly handle module augumentation.
# TODO: Remove once https://github.com/microsoft/rushstack/issues/2090 is solved.
"init",
"",
],
tags = [
"release-with-framework",
Expand Down
97 changes: 0 additions & 97 deletions packages/localize/init/index.ts
Expand Up @@ -11,100 +11,3 @@ export {$localize, LocalizeFn, TranslateFn};

// Attach $localize to the global context, as a side-effect of this module.
_global.$localize = $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;
}
98 changes: 98 additions & 0 deletions packages/localize/localize.ts
Expand Up @@ -7,9 +7,107 @@
*/

// 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;
}
1 change: 1 addition & 0 deletions packages/localize/schematics/ng-add/BUILD.bazel
Expand Up @@ -37,6 +37,7 @@ ts_library(
deps = [
":ng-add",
"@npm//@angular-devkit/schematics",
"@npm//typescript",
],
)

Expand Down
6 changes: 3 additions & 3 deletions packages/localize/schematics/ng-add/README.md
Expand Up @@ -2,9 +2,9 @@

This schematic will be executed when an Angular CLI user runs `ng add @angular/localize`.

It will search their `angular.json` file, and find polyfills and main files for server builders.
Then it will add the `@angular/localize/init` polyfill that `@angular/localize` needs to work.
It will search their `angular.json` file, and add `types: ["@angular/localize"]` in the TypeScript
configuration files of the project.

If the user specifies that they want to use `$localize` at runtime then the dependency will be
added to the `depdendencies` section of `package.json` rather than in the `devDependencies` which
is the default.
is the default.

0 comments on commit b6fd814

Please sign in to comment.