Previously the metadata and placeholder blocks were serialized in
a variety of places. Moreover the code for creating the `LocalizedString`
AST node was doing serialization, which break the separation of concerns.
Now this is all done by the code that renders the AST and is refactored into
helper functions to avoid repeating the behaviour.
PR Close#32867
Now that the `$localize` translations are `MessageId` based the
compiler must render `MessageId`s in its generated `$localize` code.
This is because the `MessageId` used by the compiler is computed
from information that does not get passed through to the `$localize`
tagged string.
For example, the generated code for the following template
```html
<div id="static" i18n-title="m|d" title="introduction"></div>
```
will contain these localization statements
```ts
if (ngI18nClosureMode) {
/**
* @desc d
* @meaning m
*/
const MSG_EXTERNAL_8809028065680254561$$APP_SPEC_TS_1 = goog.getMsg("introduction");
I18N_1 = MSG_EXTERNAL_8809028065680254561$$APP_SPEC_TS_1;
}
else {
I18N_1 = $localize \`:m|d@@8809028065680254561:introduction\`;
}
```
Since `$localize` is not able to accurately regenerate the source-message
(and so the `MessageId`) from the generated code, it must rely upon the
`MessageId` being provided explicitly in the generated code.
The compiler now prepends all localized messages with a "metadata block"
containing the id (and the meaning and description if defined).
Note that this metadata block will also allow translation file extraction
from the compiled code - rather than relying on the legacy ViewEngine
extraction code. (This will be implemented post-v9).
Although these metadata blocks add to the initial code size, compile-time
inlining will completely remove these strings and so will not impact on
production bundle size.
PR Close#32594
The `goog.getMsg()` function requires placeholder names to be camelCased.
This is not the case for `$localize`. Here placeholder names need
match what is serialized to translation files.
Specifically such placeholder names keep their casing but have all characters
that are not in `a-z`, `A-Z`, `0-9` and `_` converted to `_`.
PR Close#32509
This commit changes the Angular compiler (ivy-only) to generate `$localize`
tagged strings for component templates that use `i18n` attributes.
BREAKING CHANGE
Since `$localize` is a global function, it must be included in any applications
that use i18n. This is achieved by importing the `@angular/localize` package
into an appropriate bundle, where it will be executed before the renderer
needs to call `$localize`. For CLI based projects, this is best done in
the `polyfills.ts` file.
```ts
import '@angular/localize';
```
For non-CLI applications this could be added as a script to the index.html
file or another suitable script file.
PR Close#31609
Currently, template expressions and statements have their location
recorded relative to the HTML element they are in, with no handle to
absolute location in a source file except for a line/column location.
However, the line/column location is also not entirely accurate, as it
points an entire semantic expression, and not necessarily the start of
an expression recorded by the expression parser.
To support record of the source code expressions originate from, add a
new `sourceSpan` field to `ASTWithSource` that records the absolute byte
offset of an expression within a source code.
Implement part 2 of [refactoring template parsing for
stability](https://hackmd.io/@X3ECPVy-RCuVfba-pnvIpw/BkDUxaW84/%2FMA1oxh6jRXqSmZBcLfYdyw?type=book).
PR Close#31391
Since `goog.getMsg` does not process ICUs (post-processing is required via goog.i18n.MessageFormat, https://google.github.io/closure-library/api/goog.i18n.MessageFormat.html) and placeholder format used for ICUs and regular messages inside `goog.getMsg` are different, the current implementation (that assumed the same placeholder format) needs to be updated. This commit updates placeholder format used inside ICUs from `{$placeholder}` to `{PLACEHOLDER}` to better align with Closure. ICU placeholders (that were left as is prior to this commit) are now replaced with actual values in post-processing step (inside `i18nPostprocess`).
PR Close#31459
Prior to this change i18n block bindings were converted to Expressions right away (once we first access them), when in non-i18n cases we processed them differently: the actual conversion happens at instructions generation. Because of this discrepancy, the output for bindings in i18n blocks was generated incorrectly (with invalid indicies in pipeBindN fns and invalid references to non-existent local variables). Now the bindings processing is unified and i18nExp instructions should contain right bind expressions.
PR Close#28969