fix(ivy): i18n - start generated placeholder name at PH (#32493)

Currently the expressions used in a template string are automatically named
`PH_1`, `PH_2`, etc. Whereas interpolations used in i18n templates generate
placeholders automatically named `INTERPOLATION`, `INTERPOLATION_1`, etc.

This commit aligns the behaviors by starting the generated placeholder
names for expressions at `PH`, then `PH_1`, etc.

It also documents this behavior in the documentation of `$localize` as
it was not mentioned before.

PR Close #32493
This commit is contained in:
cexbrayat
2019-09-05 15:11:31 +02:00
committed by Andrew Kushnir
parent 4c168ed9ba
commit f1b1de9a3d
6 changed files with 103 additions and 52 deletions

View File

@ -36,27 +36,65 @@ export interface TranslateFn {
* $localize `some string to localize`
* ```
*
* **Naming placeholders**
* **Providing meaning, description and id**
*
* If the template literal string contains expressions then you can optionally name the placeholder
* associated with each expression. 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 `item.length` expression placeholder `itemCount` you write:
* 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 `There are ${item.length}:itemCount: items`;
* $localize`:meaning|description@@id:source message text`;
*
* $localize`:meaning|:source message text`;
* $localize`:description:source message text`;
* $localize`:@@id:source message text`;
* ```
*
* If you need to use a `:` character directly an expression you must either provide a name or you
* can escape the `:` by preceding it with a backslash:
* This format is the same as that used for `i18n` markers in Angular templates. See the
* [Angular 18n guide](guide/i18n#template-translations).
*
* **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:: ${}`
* // or
* // anonymous substitution so colon must be escaped
* $localize `${label}\: ${}`
* ```
*
@ -64,19 +102,18 @@ export interface TranslateFn {
*
* 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.
* * **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.
* * **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.
*
* 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.

View File

@ -82,7 +82,7 @@ export function parseMessage(
const metadata = parseMetadata(messageParts[0], messageParts.raw[0]);
let messageString = metadata.text;
for (let i = 1; i < messageParts.length; i++) {
const {text: messagePart, block: placeholderName = `ph_${i}`} =
const {text: messagePart, block: placeholderName = computePlaceholderName(i)} =
splitBlock(messageParts[i], messageParts.raw[i]);
messageString += `{$${placeholderName}}${messagePart}`;
if (expressions !== undefined) {
@ -186,3 +186,7 @@ export function splitBlock(cooked: string, raw: string): {text: string, block?:
};
}
}
function computePlaceholderName(index: number) {
return index === 1 ? 'PH' : `PH_${index - 1}`;
}