fix(ivy): i18n - support colons in $localize metadata (#32867)
Metadata blocks are delimited by colons. Previously the code naively just looked for the next colon in the string as the end marker. This commit supports escaping colons within the metadata content. The Angular compiler has been updated to add escaping as required. PR Close #32867
This commit is contained in:

committed by
atscott

parent
9b15588188
commit
d24ade91b8
@ -8,7 +8,7 @@
|
||||
|
||||
import {ArrayType, AssertNotNull, BinaryOperator, BinaryOperatorExpr, BuiltinType, BuiltinTypeName, CastExpr, ClassStmt, CommaExpr, CommentStmt, ConditionalExpr, DeclareFunctionStmt, DeclareVarStmt, Expression, ExpressionStatement, ExpressionType, ExpressionVisitor, ExternalExpr, ExternalReference, FunctionExpr, IfStmt, InstantiateExpr, InvokeFunctionExpr, InvokeMethodExpr, JSDocCommentStmt, LiteralArrayExpr, LiteralExpr, LiteralMapExpr, MapType, NotExpr, ReadKeyExpr, ReadPropExpr, ReadVarExpr, ReturnStatement, Statement, StatementVisitor, StmtModifier, ThrowStmt, TryCatchStmt, Type, TypeVisitor, TypeofExpr, WrappedNodeExpr, WriteKeyExpr, WritePropExpr, WriteVarExpr} from '@angular/compiler';
|
||||
import {LocalizedString} from '@angular/compiler/src/output/output_ast';
|
||||
import {serializeI18nMetaBlock, serializeI18nPlaceholderBlock} from '@angular/compiler/src/render3/view/i18n/meta';
|
||||
import {serializeI18nHead, serializeI18nTemplatePart} from '@angular/compiler/src/render3/view/i18n/meta';
|
||||
import * as ts from 'typescript';
|
||||
|
||||
import {DefaultImportRecorder, ImportRewriter, NOOP_DEFAULT_IMPORT_RECORDER, NoopImportRewriter} from '../../imports';
|
||||
@ -529,18 +529,18 @@ export class TypeTranslatorVisitor implements ExpressionVisitor, TypeVisitor {
|
||||
*/
|
||||
function visitLocalizedString(ast: LocalizedString, context: Context, visitor: ExpressionVisitor) {
|
||||
let template: ts.TemplateLiteral;
|
||||
const headPart = `${serializeI18nMetaBlock(ast.metaBlock)}${ast.messageParts[0]}`;
|
||||
const metaBlock = serializeI18nHead(ast.metaBlock, ast.messageParts[0]);
|
||||
if (ast.messageParts.length === 1) {
|
||||
template = ts.createNoSubstitutionTemplateLiteral(headPart);
|
||||
template = ts.createNoSubstitutionTemplateLiteral(metaBlock);
|
||||
} else {
|
||||
const head = ts.createTemplateHead(headPart);
|
||||
const head = ts.createTemplateHead(metaBlock);
|
||||
const spans: ts.TemplateSpan[] = [];
|
||||
for (let i = 1; i < ast.messageParts.length; i++) {
|
||||
const resolvedExpression = ast.expressions[i - 1].visitExpression(visitor, context);
|
||||
spans.push(ts.createTemplateSpan(
|
||||
resolvedExpression,
|
||||
ts.createTemplateMiddle(
|
||||
serializeI18nPlaceholderBlock(ast.placeHolderNames[i - 1]) + ast.messageParts[i])));
|
||||
const templatePart =
|
||||
serializeI18nTemplatePart(ast.placeHolderNames[i - 1], ast.messageParts[i]);
|
||||
const templateMiddle = ts.createTemplateMiddle(templatePart);
|
||||
spans.push(ts.createTemplateSpan(resolvedExpression, templateMiddle));
|
||||
}
|
||||
if (spans.length > 0) {
|
||||
// The last span is supposed to have a tail rather than a middle
|
||||
|
@ -172,7 +172,7 @@ const verify = (input: string, output: string, extra: any = {}): void => {
|
||||
describe('i18n support in the template compiler', () => {
|
||||
|
||||
describe('element attributes', () => {
|
||||
it('should add the meaning and description as JsDoc comments', () => {
|
||||
it('should add the meaning and description as JsDoc comments and metadata blocks', () => {
|
||||
const input = `
|
||||
<div i18n="meaningA|descA@@idA">Content A</div>
|
||||
<div i18n-title="meaningB|descB@@idB" title="Title B">Content B</div>
|
||||
@ -265,7 +265,7 @@ describe('i18n support in the template compiler', () => {
|
||||
$I18N_23$ = $MSG_EXTERNAL_idG$$APP_SPEC_TS_24$;
|
||||
}
|
||||
else {
|
||||
$I18N_23$ = $localize \`:[BACKUP_MESSAGE_ID:idH]desc@@idG:Title G\`;
|
||||
$I18N_23$ = $localize \`:[BACKUP_MESSAGE_ID\\:idH]desc@@idG:Title G\`;
|
||||
}
|
||||
const $_c25$ = ["title", $I18N_23$];
|
||||
…
|
||||
@ -2361,9 +2361,9 @@ describe('i18n support in the template compiler', () => {
|
||||
<div i18n>Test</div>
|
||||
`;
|
||||
|
||||
// TODO(FW-635): currently we generate unique consts for each i18n block even though it might
|
||||
// contain the same content. This should be optimized by translation statements caching, that
|
||||
// can be implemented in the future within FW-635.
|
||||
// TODO(FW-635): currently we generate unique consts for each i18n block even though it
|
||||
// might contain the same content. This should be optimized by translation statements caching,
|
||||
// that can be implemented in the future within FW-635.
|
||||
const output = String.raw `
|
||||
var $I18N_0$;
|
||||
if (ngI18nClosureMode) {
|
||||
|
Reference in New Issue
Block a user