fix(ivy): i18n - support "\", "`" and "${" sequences in i18n messages (#33820)

Since i18n messages are mapped to `$localize` tagged template strings,
the "raw" version must be properly escaped. Otherwise TS will throw an
error such as:

```
Error: Debug Failure. False expression: Expected argument 'text' to be the normalized (i.e. 'cooked') version of argument 'rawText'.
```

This commit ensures that we properly escape these raw strings before creating
TS AST nodes from them.

PR Close #33820
This commit is contained in:
Pete Bacon Darwin
2019-11-15 16:25:59 +00:00
committed by Alex Rickabaugh
parent 62f7d0fe5c
commit a6247aafa1
7 changed files with 156 additions and 104 deletions

View File

@ -234,50 +234,6 @@ export function parseI18nMeta(meta?: string): I18nMeta {
return {customId, meaning, description};
}
/**
* Serialize the given `meta` and `messagePart` "cooked" and "raw" strings that can be used in a
* `$localize` tagged string. The format of the metadata is the same as that parsed by
* `parseI18nMeta()`.
*
* @param meta The metadata to serialize
* @param messagePart The first part of the tagged string
*/
export function serializeI18nHead(
meta: I18nMeta, messagePart: string): {cooked: string, raw: string} {
let metaBlock = meta.description || '';
if (meta.meaning) {
metaBlock = `${meta.meaning}|${metaBlock}`;
}
if (meta.customId || meta.legacyId) {
metaBlock = `${metaBlock}@@${meta.customId || meta.legacyId}`;
}
if (metaBlock === '') {
// There is no metaBlock, so we must ensure that any starting colon is escaped.
return {cooked: messagePart, raw: escapeStartingColon(messagePart)};
} else {
return {
cooked: `:${metaBlock}:${messagePart}`,
raw: `:${escapeColons(metaBlock)}:${messagePart}`
};
}
}
/**
* Serialize the given `placeholderName` and `messagePart` into strings that can be used in a
* `$localize` tagged string.
*
* @param placeholderName The placeholder name to serialize
* @param messagePart The following message string after this placeholder
*/
export function serializeI18nTemplatePart(placeholderName: string, messagePart: string): string {
if (placeholderName === '') {
// There is no placeholder name block, so we must ensure that any starting colon is escaped.
return escapeStartingColon(messagePart);
} else {
return `:${placeholderName}:${messagePart}`;
}
}
// Converts i18n meta information for a message (id, description, meaning)
// to a JsDoc statement formatted as expected by the Closure compiler.
export function i18nMetaToDocStmt(meta: I18nMeta): o.JSDocCommentStmt|null {
@ -290,11 +246,3 @@ export function i18nMetaToDocStmt(meta: I18nMeta): o.JSDocCommentStmt|null {
}
return tags.length == 0 ? null : new o.JSDocCommentStmt(tags);
}
export function escapeStartingColon(str: string): string {
return str.replace(/^:/, '\\:');
}
export function escapeColons(str: string): string {
return str.replace(/:/g, '\\:');
}