
This commit reformats the packages/compiler tree using the new version of clang-format. PR Close #36520
105 lines
3.4 KiB
TypeScript
105 lines
3.4 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google Inc. 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 * as i18n from '../i18n_ast';
|
|
|
|
export abstract class Serializer {
|
|
// - The `placeholders` and `placeholderToMessage` properties are irrelevant in the input messages
|
|
// - The `id` contains the message id that the serializer is expected to use
|
|
// - Placeholder names are already map to public names using the provided mapper
|
|
abstract write(messages: i18n.Message[], locale: string|null): string;
|
|
|
|
abstract load(content: string, url: string):
|
|
{locale: string|null, i18nNodesByMsgId: {[msgId: string]: i18n.Node[]}};
|
|
|
|
abstract digest(message: i18n.Message): string;
|
|
|
|
// Creates a name mapper, see `PlaceholderMapper`
|
|
// Returning `null` means that no name mapping is used.
|
|
createNameMapper(message: i18n.Message): PlaceholderMapper|null {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A `PlaceholderMapper` converts placeholder names from internal to serialized representation and
|
|
* back.
|
|
*
|
|
* It should be used for serialization format that put constraints on the placeholder names.
|
|
*/
|
|
export interface PlaceholderMapper {
|
|
toPublicName(internalName: string): string|null;
|
|
|
|
toInternalName(publicName: string): string|null;
|
|
}
|
|
|
|
/**
|
|
* A simple mapper that take a function to transform an internal name to a public name
|
|
*/
|
|
export class SimplePlaceholderMapper extends i18n.RecurseVisitor implements PlaceholderMapper {
|
|
private internalToPublic: {[k: string]: string} = {};
|
|
private publicToNextId: {[k: string]: number} = {};
|
|
private publicToInternal: {[k: string]: string} = {};
|
|
|
|
// create a mapping from the message
|
|
constructor(message: i18n.Message, private mapName: (name: string) => string) {
|
|
super();
|
|
message.nodes.forEach(node => node.visit(this));
|
|
}
|
|
|
|
toPublicName(internalName: string): string|null {
|
|
return this.internalToPublic.hasOwnProperty(internalName) ?
|
|
this.internalToPublic[internalName] :
|
|
null;
|
|
}
|
|
|
|
toInternalName(publicName: string): string|null {
|
|
return this.publicToInternal.hasOwnProperty(publicName) ? this.publicToInternal[publicName] :
|
|
null;
|
|
}
|
|
|
|
visitText(text: i18n.Text, context?: any): any {
|
|
return null;
|
|
}
|
|
|
|
visitTagPlaceholder(ph: i18n.TagPlaceholder, context?: any): any {
|
|
this.visitPlaceholderName(ph.startName);
|
|
super.visitTagPlaceholder(ph, context);
|
|
this.visitPlaceholderName(ph.closeName);
|
|
}
|
|
|
|
visitPlaceholder(ph: i18n.Placeholder, context?: any): any {
|
|
this.visitPlaceholderName(ph.name);
|
|
}
|
|
|
|
visitIcuPlaceholder(ph: i18n.IcuPlaceholder, context?: any): any {
|
|
this.visitPlaceholderName(ph.name);
|
|
}
|
|
|
|
// XMB placeholders could only contains A-Z, 0-9 and _
|
|
private visitPlaceholderName(internalName: string): void {
|
|
if (!internalName || this.internalToPublic.hasOwnProperty(internalName)) {
|
|
return;
|
|
}
|
|
|
|
let publicName = this.mapName(internalName);
|
|
|
|
if (this.publicToInternal.hasOwnProperty(publicName)) {
|
|
// Create a new XMB when it has already been used
|
|
const nextId = this.publicToNextId[publicName];
|
|
this.publicToNextId[publicName] = nextId + 1;
|
|
publicName = `${publicName}_${nextId}`;
|
|
} else {
|
|
this.publicToNextId[publicName] = 1;
|
|
}
|
|
|
|
this.internalToPublic[internalName] = publicName;
|
|
this.publicToInternal[publicName] = internalName;
|
|
}
|
|
}
|