
Update the license headers throughout the repository to reference Google LLC rather than Google Inc, for the required license headers. PR Close #37205
108 lines
3.9 KiB
TypeScript
108 lines
3.9 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {HtmlParser} from '../ml_parser/html_parser';
|
|
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
|
import {ParseError} from '../parse_util';
|
|
|
|
import {extractMessages} from './extractor_merger';
|
|
import * as i18n from './i18n_ast';
|
|
import {PlaceholderMapper, Serializer} from './serializers/serializer';
|
|
|
|
|
|
/**
|
|
* A container for message extracted from the templates.
|
|
*/
|
|
export class MessageBundle {
|
|
private _messages: i18n.Message[] = [];
|
|
|
|
constructor(
|
|
private _htmlParser: HtmlParser, private _implicitTags: string[],
|
|
private _implicitAttrs: {[k: string]: string[]}, private _locale: string|null = null) {}
|
|
|
|
updateFromTemplate(html: string, url: string, interpolationConfig: InterpolationConfig):
|
|
ParseError[] {
|
|
const htmlParserResult =
|
|
this._htmlParser.parse(html, url, {tokenizeExpansionForms: true, interpolationConfig});
|
|
|
|
if (htmlParserResult.errors.length) {
|
|
return htmlParserResult.errors;
|
|
}
|
|
|
|
const i18nParserResult = extractMessages(
|
|
htmlParserResult.rootNodes, interpolationConfig, this._implicitTags, this._implicitAttrs);
|
|
|
|
if (i18nParserResult.errors.length) {
|
|
return i18nParserResult.errors;
|
|
}
|
|
|
|
this._messages.push(...i18nParserResult.messages);
|
|
return [];
|
|
}
|
|
|
|
// Return the message in the internal format
|
|
// The public (serialized) format might be different, see the `write` method.
|
|
getMessages(): i18n.Message[] {
|
|
return this._messages;
|
|
}
|
|
|
|
write(serializer: Serializer, filterSources?: (path: string) => string): string {
|
|
const messages: {[id: string]: i18n.Message} = {};
|
|
const mapperVisitor = new MapPlaceholderNames();
|
|
|
|
// Deduplicate messages based on their ID
|
|
this._messages.forEach(message => {
|
|
const id = serializer.digest(message);
|
|
if (!messages.hasOwnProperty(id)) {
|
|
messages[id] = message;
|
|
} else {
|
|
messages[id].sources.push(...message.sources);
|
|
}
|
|
});
|
|
|
|
// Transform placeholder names using the serializer mapping
|
|
const msgList = Object.keys(messages).map(id => {
|
|
const mapper = serializer.createNameMapper(messages[id]);
|
|
const src = messages[id];
|
|
const nodes = mapper ? mapperVisitor.convert(src.nodes, mapper) : src.nodes;
|
|
let transformedMessage = new i18n.Message(nodes, {}, {}, src.meaning, src.description, id);
|
|
transformedMessage.sources = src.sources;
|
|
if (filterSources) {
|
|
transformedMessage.sources.forEach(
|
|
(source: i18n.MessageSpan) => source.filePath = filterSources(source.filePath));
|
|
}
|
|
return transformedMessage;
|
|
});
|
|
|
|
return serializer.write(msgList, this._locale);
|
|
}
|
|
}
|
|
|
|
// Transform an i18n AST by renaming the placeholder nodes with the given mapper
|
|
class MapPlaceholderNames extends i18n.CloneVisitor {
|
|
convert(nodes: i18n.Node[], mapper: PlaceholderMapper): i18n.Node[] {
|
|
return mapper ? nodes.map(n => n.visit(this, mapper)) : nodes;
|
|
}
|
|
|
|
visitTagPlaceholder(ph: i18n.TagPlaceholder, mapper: PlaceholderMapper): i18n.TagPlaceholder {
|
|
const startName = mapper.toPublicName(ph.startName)!;
|
|
const closeName = ph.closeName ? mapper.toPublicName(ph.closeName)! : ph.closeName;
|
|
const children = ph.children.map(n => n.visit(this, mapper));
|
|
return new i18n.TagPlaceholder(
|
|
ph.tag, ph.attrs, startName, closeName, children, ph.isVoid, ph.sourceSpan);
|
|
}
|
|
|
|
visitPlaceholder(ph: i18n.Placeholder, mapper: PlaceholderMapper): i18n.Placeholder {
|
|
return new i18n.Placeholder(ph.value, mapper.toPublicName(ph.name)!, ph.sourceSpan);
|
|
}
|
|
|
|
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, mapper: PlaceholderMapper): i18n.IcuPlaceholder {
|
|
return new i18n.IcuPlaceholder(ph.value, mapper.toPublicName(ph.name)!, ph.sourceSpan);
|
|
}
|
|
}
|